SQLite

Check-in [cf2abd59be]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Refactor for correct NULL handling in the IS TRUE, IS FALSE, IS NOT TRUE, and IS NOT FALSE operators.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | is-true-operator
Files: files | file ages | folders
SHA3-256: cf2abd59be9971a55bd3d6c5df374c6aaa23bf81819482b42f01ee2484dcd739
User & Date: drh 2018-02-26 18:49:05.668
Context
2018-02-26
19:03
Enhance TreeView so that it can display the new IS TRUE expression trees. (check-in: 7e38305e6f user: drh tags: is-true-operator)
18:49
Refactor for correct NULL handling in the IS TRUE, IS FALSE, IS NOT TRUE, and IS NOT FALSE operators. (check-in: cf2abd59be user: drh tags: is-true-operator)
15:31
Merge the fix for determining truth of floating point values from trunk. (check-in: 003dc14053 user: drh tags: is-true-operator)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
                               pExpr->iColumn, iTab, target,
                               pExpr->op2);
    }
    case TK_INTEGER: {
      codeInteger(pParse, pExpr, 0, target);
      return target;
    }
    case TK_TRUE: {
      sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
      return target;
    }
    case TK_FALSE: {
      sqlite3VdbeAddOp2(v, OP_Integer, 0, target);
      return target;
    }
#ifndef SQLITE_OMIT_FLOATING_POINT
    case TK_FLOAT: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      codeReal(v, pExpr->u.zToken, 0, target);
      return target;







|
|
<
<
<
<







3539
3540
3541
3542
3543
3544
3545
3546
3547




3548
3549
3550
3551
3552
3553
3554
                               pExpr->iColumn, iTab, target,
                               pExpr->op2);
    }
    case TK_INTEGER: {
      codeInteger(pParse, pExpr, 0, target);
      return target;
    }
    case TK_TRUEFALSE: {
      sqlite3VdbeAddOp2(v, OP_Integer, pExpr->iTable, target);




      return target;
    }
#ifndef SQLITE_OMIT_FLOATING_POINT
    case TK_FLOAT: {
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      codeReal(v, pExpr->u.zToken, 0, target);
      return target;
3702
3703
3704
3705
3706
3707
3708
3709



3710
3711
3712
3713

3714
3715
3716
3717
3718
3719
3720
      assert( TK_BITNOT==OP_BitNot );   testcase( op==TK_BITNOT );
      assert( TK_NOT==OP_Not );         testcase( op==TK_NOT );
      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
      testcase( regFree1==0 );
      sqlite3VdbeAddOp2(v, op, r1, inReg);
      break;
    }
    case TK_ISTRUE: {



      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
      testcase( regFree1==0 );
      sqlite3VdbeAddOp2(v, OP_Not, r1, inReg);
      sqlite3VdbeAddOp2(v, OP_Not, inReg, inReg);

      break;
    }
    case TK_ISNULL:
    case TK_NOTNULL: {
      int addr;
      assert( TK_ISNULL==OP_IsNull );   testcase( op==TK_ISNULL );
      assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );







|
>
>
>


|
<
>







3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711

3712
3713
3714
3715
3716
3717
3718
3719
      assert( TK_BITNOT==OP_BitNot );   testcase( op==TK_BITNOT );
      assert( TK_NOT==OP_Not );         testcase( op==TK_NOT );
      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
      testcase( regFree1==0 );
      sqlite3VdbeAddOp2(v, op, r1, inReg);
      break;
    }
    case TK_TRUTH: {
      assert( pExpr->pRight->op==TK_TRUEFALSE );
      assert( pExpr->pRight->iTable==0 || pExpr->pRight->iTable==1 );
      assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
      r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
      testcase( regFree1==0 );
      sqlite3VdbeAddOp4Int(v, OP_IsTrue, r1, inReg, !pExpr->pRight->iTable,

                           pExpr->pRight->iTable ^ (pExpr->op2==TK_IS));
      break;
    }
    case TK_ISNULL:
    case TK_NOTNULL: {
      int addr;
      assert( TK_ISNULL==OP_IsNull );   testcase( op==TK_ISNULL );
      assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
4484
4485
4486
4487
4488
4489
4490
4491

4492






4493





4494
4495
4496
4497
4498
4499
4500
      break;
    }
    case TK_NOT: {
      testcase( jumpIfNull==0 );
      sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
      break;
    }
    case TK_ISTRUE: {

      testcase( jumpIfNull==0 );






      sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);





      break;
    }
    case TK_IS:
    case TK_ISNOT:
      testcase( op==TK_IS );
      testcase( op==TK_ISNOT );
      op = (op==TK_IS) ? TK_EQ : TK_NE;







|
>

>
>
>
>
>
>
|
>
>
>
>
>







4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
      break;
    }
    case TK_NOT: {
      testcase( jumpIfNull==0 );
      sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
      break;
    }
    case TK_TRUTH: {
      int isNot;
      testcase( jumpIfNull==0 );
      assert( pExpr->pRight->op==TK_TRUEFALSE );
      assert( pExpr->pRight->iTable==0 || pExpr->pRight->iTable==1 );
      testcase( pExpr->pRight->iTable==0 );
      assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
      isNot = pExpr->op2==TK_ISNOT;
      if( pExpr->pRight->iTable ^ isNot ){
        sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest,
                          isNot ? SQLITE_JUMPIFNULL : 0);
      }else{
        sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest,
                           isNot ? SQLITE_JUMPIFNULL : 0);
      }
      break;
    }
    case TK_IS:
    case TK_ISNOT:
      testcase( op==TK_IS );
      testcase( op==TK_ISNOT );
      op = (op==TK_IS) ? TK_EQ : TK_NE;
4643
4644
4645
4646
4647
4648
4649
4650
4651









4652







4653
4654
4655
4656
4657
4658
4659
      break;
    }
    case TK_NOT: {
      testcase( jumpIfNull==0 );
      sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
      break;
    }
    case TK_ISTRUE: {
      testcase( jumpIfNull==0 );









      sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);







      break;
    }
    case TK_IS:
    case TK_ISNOT:
      testcase( pExpr->op==TK_IS );
      testcase( pExpr->op==TK_ISNOT );
      op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;







|

>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>







4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
      break;
    }
    case TK_NOT: {
      testcase( jumpIfNull==0 );
      sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
      break;
    }
    case TK_TRUTH: {
      testcase( jumpIfNull==0 );
      int isNot;
      testcase( jumpIfNull==0 );
      assert( pExpr->pRight->op==TK_TRUEFALSE );
      assert( pExpr->pRight->iTable==0 || pExpr->pRight->iTable==1 );
      testcase( pExpr->pRight->iTable==0 );
      assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
      isNot = pExpr->op2==TK_ISNOT;
      if( pExpr->pRight->iTable ^ isNot ){
        /* IS TRUE and IS NOT FALSE */
        sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest,
                           isNot ? 0 : SQLITE_JUMPIFNULL);

      }else{
        /* IS FALSE and IS NOT TRUE */
        sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest,
                          isNot ? 0: SQLITE_JUMPIFNULL);
      }
      break;
    }
    case TK_IS:
    case TK_ISNOT:
      testcase( pExpr->op==TK_IS );
      testcase( pExpr->op==TK_ISNOT );
      op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
Changes to src/resolve.c.
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
  */
  if( cnt==0 && zTab==0 ){
    if( ExprHasProperty(pExpr,EP_DblQuoted) ){
      pExpr->op = TK_STRING;
      pExpr->pTab = 0;
      return WRC_Prune;
    }
    if( sqlite3StrICmp(zCol, "true")==0 ){
      pExpr->op = TK_TRUE;
      pExpr->pTab = 0;
      return WRC_Prune;
    }
    if( sqlite3StrICmp(zCol, "false")==0 ){
      pExpr->op = TK_FALSE;
      pExpr->pTab = 0;
      return WRC_Prune;
    }
  }

  /*
  ** cnt==0 means there was not match.  cnt>1 means there were two or







|
|
|
<
<
<
<







433
434
435
436
437
438
439
440
441
442




443
444
445
446
447
448
449
  */
  if( cnt==0 && zTab==0 ){
    if( ExprHasProperty(pExpr,EP_DblQuoted) ){
      pExpr->op = TK_STRING;
      pExpr->pTab = 0;
      return WRC_Prune;
    }
    if( sqlite3StrICmp(zCol, "true")==0 || sqlite3StrICmp(zCol, "false")==0 ){
      pExpr->op = TK_TRUEFALSE;
      pExpr->iTable = zCol[4]==0;




      pExpr->pTab = 0;
      return WRC_Prune;
    }
  }

  /*
  ** cnt==0 means there was not match.  cnt>1 means there were two or
792
793
794
795
796
797
798



799
800
801
802
803
804

805
806
807
808
809
810
811
812

813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
      break;
    }
    case TK_VARIABLE: {
      notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
      break;
    }
    case TK_IS:



      /* Handle special cases of "x IS TRUE" and "x IS FALSE".  The first
      ** is transformed into "+x" and the second into "NOT x". */
      if( pExpr->pRight->op==TK_ID ){
        int rc = resolveExprStep(pWalker, pExpr->pRight);
        if( rc==WRC_Abort ) return WRC_Abort;
        if( pExpr->pRight->op==TK_TRUE ){

          pExpr->op = TK_ISTRUE;
          return WRC_Continue;
        }else if( pExpr->pRight->op==TK_FALSE ){
          pExpr->op = TK_NOT;
          return WRC_Continue;
        }
      }
      /* Fall thru */

    case TK_BETWEEN:
    case TK_EQ:
    case TK_NE:
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE:
    case TK_ISNOT: {
      int nLeft, nRight;
      if( pParse->db->mallocFailed ) break;
      assert( pExpr->pLeft!=0 );
      nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
      if( pExpr->op==TK_BETWEEN ){
        nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
        if( nRight==nLeft ){







>
>
>
|
|
|
|

|
>
|
<
<
|




>






|
<







788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805


806
807
808
809
810
811
812
813
814
815
816
817
818

819
820
821
822
823
824
825
      break;
    }
    case TK_VARIABLE: {
      notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
      break;
    }
    case TK_IS:
    case TK_ISNOT: {
      Expr *pRight;
      assert( !ExprHasProperty(pExpr, EP_Reduced) );
      /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
      ** and "x IS NOT FALSE". */
      if( (pRight = pExpr->pRight)->op==TK_ID ){
        int rc = resolveExprStep(pWalker, pRight);
        if( rc==WRC_Abort ) return WRC_Abort;
        if( pRight->op==TK_TRUEFALSE ){
          assert( pRight->iTable==0 || pRight->iTable==1 );
          pExpr->op2 = pExpr->op;


          pExpr->op = TK_TRUTH;
          return WRC_Continue;
        }
      }
      /* Fall thru */
    }
    case TK_BETWEEN:
    case TK_EQ:
    case TK_NE:
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE: {

      int nLeft, nRight;
      if( pParse->db->mallocFailed ) break;
      assert( pExpr->pLeft!=0 );
      nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
      if( pExpr->op==TK_BETWEEN ){
        nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
        if( nRight==nLeft ){
Changes to src/sqliteInt.h.
2383
2384
2385
2386
2387
2388
2389
2390

2391
2392
2393
2394
2395
2396
2397
#if SQLITE_MAX_EXPR_DEPTH>0
  int nHeight;           /* Height of the tree headed by this node */
#endif
  int iTable;            /* TK_COLUMN: cursor number of table holding column
                         ** TK_REGISTER: register number
                         ** TK_TRIGGER: 1 -> new, 0 -> old
                         ** EP_Unlikely:  134217728 times likelihood
                         ** TK_SELECT: 1st register of result vector */

  ynVar iColumn;         /* TK_COLUMN: column index.  -1 for rowid.
                         ** TK_VARIABLE: variable number (always >= 1).
                         ** TK_SELECT_COLUMN: column of the result vector */
  i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
  i16 iRightJoinTable;   /* If EP_FromJoin, the right table of the join */
  u8 op2;                /* TK_REGISTER: original value of Expr.op
                         ** TK_COLUMN: the value of p5 for OP_Column







|
>







2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
#if SQLITE_MAX_EXPR_DEPTH>0
  int nHeight;           /* Height of the tree headed by this node */
#endif
  int iTable;            /* TK_COLUMN: cursor number of table holding column
                         ** TK_REGISTER: register number
                         ** TK_TRIGGER: 1 -> new, 0 -> old
                         ** EP_Unlikely:  134217728 times likelihood
                         ** TK_SELECT: 1st register of result vector
                         ** TK_TRUEFALSE: 1 for true, 0 for false */
  ynVar iColumn;         /* TK_COLUMN: column index.  -1 for rowid.
                         ** TK_VARIABLE: variable number (always >= 1).
                         ** TK_SELECT_COLUMN: column of the result vector */
  i16 iAgg;              /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
  i16 iRightJoinTable;   /* If EP_FromJoin, the right table of the join */
  u8 op2;                /* TK_REGISTER: original value of Expr.op
                         ** TK_COLUMN: the value of p5 for OP_Column
Changes to src/vdbe.c.
2186
2187
2188
2189
2190
2191
2192




























2193
2194
2195
2196
2197
2198
2199
    MemSetTypeFlag(pOut, MEM_Null);
  }else{
    pOut->u.i = v1;
    MemSetTypeFlag(pOut, MEM_Int);
  }
  break;
}





























/* Opcode: Not P1 P2 * * *
** Synopsis: r[P2]= !r[P1]
**
** Interpret the value in register P1 as a boolean value.  Store the
** boolean complement in register P2.  If the value in register P1 is 
** NULL, then a NULL is stored in P2.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
    MemSetTypeFlag(pOut, MEM_Null);
  }else{
    pOut->u.i = v1;
    MemSetTypeFlag(pOut, MEM_Int);
  }
  break;
}

/* Opcode: IsTrue P1 P2 P3 P4 *
** Synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4
**
** This opcode implements the IS TRUE, IS FALSE, IS NOT TRUE, and
** IS NOT FALSE operators.
**
** Interpret the value in register P1 as a boolean value.  Store the that
** boolean (a 0 or 1) in register P2.  Or if the value in register P1 is 
** NULL, then the P3 is stored in register P2.  Invert the answer if P4
** is 1.
**
** The logic is summarized like this:
**
** <ul> 
** <li> P3==0, P4==0  &rarr;  r[P2] = r[P1] IS TRUE
** <li> P3==1, P4==1  &rarr;  r[P2] = r[P1] IS FALSE
** <li> P3==0, P4==1  &rarr;  r[P2] = r[P1] IS NOT TRUE
** <li> P3==1, P4==0  &rarr;  r[P2] = r[P1] IS NOT FALSE
** </ul>
*/
case OP_IsTrue: {               /* in1, out2 */
  assert( pOp->p4type==P4_INT32 );
  assert( pOp->p4.i==0 || pOp->p4.i==1 );
  sqlite3VdbeMemSetInt64(&aMem[pOp->p2],
      sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3) ^ pOp->p4.i);
  break;
}

/* Opcode: Not P1 P2 * * *
** Synopsis: r[P2]= !r[P1]
**
** Interpret the value in register P1 as a boolean value.  Store the
** boolean complement in register P2.  If the value in register P1 is 
** NULL, then a NULL is stored in P2.
Added test/istrue.test.


































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# 2018-02-26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing expressions of the form
#
#        x IS TRUE
#        x IS FALSE
#        x IS NOT TRUE
#        x IS NOT FALSE
#
# Tests are also included for the use of TRUE and FALSE as
# literal values.

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test istrue-100 {
  CREATE TABLE t1(x INTEGER PRIMARY KEY, y BOOLEAN);
  INSERT INTO t1 VALUES(1, true),(2, false),(3, null);
  SELECT x FROM t1 WHERE y IS TRUE;
} {1}
do_execsql_test istrue-110 {
  SELECT x FROM t1 WHERE y IS FALSE;
} {2}
do_execsql_test istrue-120 {
  SELECT x FROM t1 WHERE y IS NULL;
} {3}
do_execsql_test istrue-130 {
  SELECT x FROM t1 WHERE y IS NOT TRUE;
} {2 3}
do_execsql_test istrue-140 {
  SELECT x FROM t1 WHERE y IS NOT FALSE;
} {1 3}
do_execsql_test istrue-150 {
  SELECT x FROM t1 WHERE y IS NOT NULL;
} {1 2}
unset -nocomplain X
set X 9
do_execsql_test istrue-160 {
  SELECT x FROM t1 WHERE y IS TRUE OR (8==$X)
} {1}
do_execsql_test istrue-170 {
  SELECT x FROM t1 WHERE y IS FALSE OR (8==$X)
} {2}
do_execsql_test istrue-180 {
  SELECT x FROM t1 WHERE y IS NULL OR (8==$X);
} {3}
do_execsql_test istrue-190 {
  SELECT x FROM t1 WHERE y IS NOT TRUE OR (8==$X);
} {2 3}
do_execsql_test istrue-200 {
  SELECT x FROM t1 WHERE y IS NOT FALSE OR (8==$X);
} {1 3}
do_execsql_test istrue-210 {
  SELECT x FROM t1 WHERE y IS NOT NULL OR (8==$X);
} {1 2}

do_execsql_test istrue-300 {
  SELECT x,
         y IS TRUE, y IS FALSE, y is NULL,
         y IS NOT TRUE, y IS NOT FALSE, y IS NOT NULL, '|'
    FROM t1 ORDER BY x;
} {1 1 0 0 0 1 1 | 2 0 1 0 1 0 1 | 3 0 0 1 1 1 0 |}

do_execsql_test istrue-400 {
  SELECT x FROM t1 WHERE true;
} {1 2 3}
do_execsql_test istrue-410 {
  SELECT x FROM t1 WHERE false;
} {}


finish_test
Changes to tool/addopcodes.tcl.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
}
close $in

# The following are the extra token codes to be added.  SPACE and 
# ILLEGAL *must* be the last two token codes and they must be in that order.
#
set extras {
  TRUE
  FALSE
  ISNOT
  FUNCTION
  COLUMN
  AGG_FUNCTION
  AGG_COLUMN
  UMINUS
  UPLUS
  ISTRUE
  REGISTER
  VECTOR
  SELECT_COLUMN
  IF_NULL_ROW
  ASTERISK
  SPAN
  END_OF_FILE







<
|







|







18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
}
close $in

# The following are the extra token codes to be added.  SPACE and 
# ILLEGAL *must* be the last two token codes and they must be in that order.
#
set extras {

  TRUEFALSE
  ISNOT
  FUNCTION
  COLUMN
  AGG_FUNCTION
  AGG_COLUMN
  UMINUS
  UPLUS
  TRUTH
  REGISTER
  VECTOR
  SELECT_COLUMN
  IF_NULL_ROW
  ASTERISK
  SPAN
  END_OF_FILE