diff --git a/manifest b/manifest index 88aafccee7..438ec23110 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplified\simplementation\sof\sindexing\swith\sthe\sIS\soperator. -D 2015-05-13T19:33:41.990 +C A\snew\simplementation\sof\sindexing\swith\sthe\sIS\soperator\sthat\sworks\scorrectly\nwhen\sthe\sIS\soperator\sis\sin\sthe\sWHERE\sclause\sand\sthe\soperands\sare\sfrom\s\nopposite\ssides\sof\sa\sLEFT\sJOIN. +D 2015-05-14T01:05:25.274 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in edfc69769e613a6359c42c06ea1d42c3bece1736 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -307,8 +307,8 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c fa61aca146422a2a056aeb0381a6bb1c37d46c07 -F src/whereInt.h 31d30e83621c21358d031510d5c6a3e474cd8bb7 +F src/where.c 64afb483fe8bede1e31e6c66bc532530a4600543 +F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 @@ -1168,7 +1168,7 @@ F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test 1ff3d9f8da0a6c0dc5ccfd38d9225b2cdb5b6afb F test/where2.test 23fdb5d8e756554aad4ca7ae03de9dd8367a2c6e F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e -F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf +F test/where4.test a4603fa0d018bd4b9430dac840c9c522af421dd5 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8 @@ -1258,7 +1258,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 24263d08b11c88416d270013bdaf5ff45125cb4d -R 16be24e7bac77474bad7ab9d3d121f18 +P 95b1f9bf14e490c6c6bba9ea78aeab712a44aab5 +R 6e0cd1da1bcd5d739d5d402ab5201f6c U drh -Z 3bc6b705447a86373e017a72613abb32 +Z 3608a708c2f560b3e002545b6da23dda diff --git a/manifest.uuid b/manifest.uuid index 660fdcd247..2dcd8f7064 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -95b1f9bf14e490c6c6bba9ea78aeab712a44aab5 \ No newline at end of file +4541688b3f56f5cd3d5b299594b58c577ad633bb \ No newline at end of file diff --git a/src/where.c b/src/where.c index aad9799211..3c96f93a7e 100644 --- a/src/where.c +++ b/src/where.c @@ -417,7 +417,7 @@ static u16 operatorMask(int op){ }else if( op==TK_ISNULL ){ c = WO_ISNULL; }else if( op==TK_IS ){ - c = WO_EQ; /* IS works like ==, just without the IsNull tests */ + c = WO_IS; }else{ assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); c = (u16)(WO_EQ<<(op-TK_EQ)); @@ -429,7 +429,7 @@ static u16 operatorMask(int op){ assert( op!=TK_LE || c==WO_LE ); assert( op!=TK_GT || c==WO_GT ); assert( op!=TK_GE || c==WO_GE ); - assert( op!=TK_IS || c==WO_EQ ); + assert( op!=TK_IS || c==WO_IS ); return c; } @@ -490,11 +490,12 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ continue; } } - if( (pTerm->eOperator & WO_EQ)!=0 + if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN && pX->iTable==pScan->aEquiv[0] && pX->iColumn==pScan->aEquiv[1] ){ + testcase( pTerm->eOperator & WO_IS ); continue; } pScan->k = k+1; @@ -596,9 +597,11 @@ static WhereTerm *findTerm( WhereScan scan; p = whereScanInit(&scan, pWC, iCur, iColumn, op, pIdx); + op &= WO_EQ|WO_IS; while( p ){ if( (p->prereqRight & notReady)==0 ){ - if( p->prereqRight==0 && (p->eOperator&WO_EQ)!=0 ){ + if( p->prereqRight==0 && (p->eOperator&op)!=0 ){ + testcase( p->eOperator & WO_IS ); return p; } if( pResult==0 ) pResult = p; @@ -1679,7 +1682,7 @@ static int termCanDriveIndex( ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; - if( (pTerm->eOperator & WO_EQ)==0 ) return 0; + if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; if( (pTerm->prereqRight & notReady)!=0 ) return 0; if( pTerm->u.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; @@ -1955,7 +1958,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV))==0 ) continue; + if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; @@ -4104,16 +4107,18 @@ static Bitmask codeOneLoopStart( Expr *pE, *pEAlt; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue; + if( (pTerm->eOperator&(WO_EQUIV|WO_EQ|WO_IS))<=WO_EQUIV ) continue; if( pTerm->leftCursor!=iCur ) continue; if( pLevel->iLeftJoin ) continue; pE = pTerm->pExpr; assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); - pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); + pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, + WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; - testcase( (pAlt->eOperator & WO_EQ)!=0 && pAlt->pExpr->op==TK_IS ); + testcase( pAlt->eOperator & WO_EQ ); + testcase( pAlt->eOperator & WO_IS ); testcase( pAlt->eOperator & WO_IN ); VdbeModuleComment((v, "begin transitive constraint")); pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt)); @@ -4656,7 +4661,7 @@ static void whereLoopOutputAdjust( /* In the absence of explicit truth probabilities, use heuristics to ** guess a reasonable truth probability. */ pLoop->nOut--; - if( pTerm->eOperator&WO_EQ ){ + if( pTerm->eOperator&(WO_EQ|WO_IS) ){ Expr *pRight = pTerm->pExpr->pRight; testcase( pTerm->pExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ @@ -4729,7 +4734,7 @@ static int whereLoopAddBtreeIndex( }else if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){ opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE; }else{ - opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE; + opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); @@ -4792,7 +4797,7 @@ static int whereLoopAddBtreeIndex( assert( nIn>0 ); /* RHS always has 2 or more terms... The parser ** changes "x IN (?)" into "x=?". */ - }else if( eOp & (WO_EQ) ){ + }else if( eOp & (WO_EQ|WO_IS) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ if( iCol>=0 && pProbe->uniqNotNull==0 ){ @@ -4842,7 +4847,7 @@ static int whereLoopAddBtreeIndex( whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); }else{ int nEq = ++pNew->u.btree.nEq; - assert( eOp & (WO_ISNULL|WO_EQ|WO_IN) ); + assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) ); assert( pNew->nOut==saved_nOut ); if( pTerm->truthProb<=0 && iCol>=0 ){ @@ -4859,8 +4864,9 @@ static int whereLoopAddBtreeIndex( && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) ){ Expr *pExpr = pTerm->pExpr; - if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){ - testcase( (eOp & WO_EQ)!=0 && pExpr->op==TK_IS ); + if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ + testcase( eOp & WO_EQ ); + testcase( eOp & WO_IS ); testcase( eOp & WO_ISNULL ); rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); }else{ @@ -5697,9 +5703,9 @@ static i8 wherePathSatisfiesOrderBy( if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, - ~ready, WO_EQ|WO_ISNULL, 0); + ~ready, WO_EQ|WO_ISNULL|WO_IS, 0); if( pTerm==0 ) continue; - if( (pTerm->eOperator&WO_EQ)!=0 && pOBExpr->iColumn>=0 ){ + if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; @@ -5739,7 +5745,7 @@ static i8 wherePathSatisfiesOrderBy( /* Skip over == and IS NULL terms */ if( ju.btree.nEq && pLoop->nSkip==0 - && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 + && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ if( i & WO_ISNULL ){ testcase( isOrderDistinct ); @@ -6312,8 +6318,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; - pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0); + pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); if( pTerm ){ + testcase( pTerm->eOperator & WO_IS ); pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; @@ -6328,10 +6335,10 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; for(j=0; jnKeyCol; j++){ - pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx); + pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ|WO_IS, pIdx); if( pTerm==0 ) break; + testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; - testcase( pTerm->pExpr->op==TK_IS ); } if( j!=pIdx->nKeyCol ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; diff --git a/src/whereInt.h b/src/whereInt.h index e7730d71ed..3a5a48e840 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -429,21 +429,22 @@ struct WhereInfo { ** OR-ed combination of these values can be used when searching for ** particular WhereTerms within a WhereClause. */ -#define WO_IN 0x001 -#define WO_EQ 0x002 /* Used for both == and IS */ +#define WO_IN 0x0001 +#define WO_EQ 0x0002 #define WO_LT (WO_EQ<<(TK_LT-TK_EQ)) #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) -#define WO_MATCH 0x040 -#define WO_ISNULL 0x080 -#define WO_OR 0x100 /* Two or more OR-connected terms */ -#define WO_AND 0x200 /* Two or more AND-connected terms */ -#define WO_EQUIV 0x400 /* Of the form A==B, both columns */ -#define WO_NOOP 0x800 /* This term does not restrict search space */ +#define WO_MATCH 0x0040 +#define WO_IS 0x0080 +#define WO_ISNULL 0x0100 +#define WO_OR 0x0200 /* Two or more OR-connected terms */ +#define WO_AND 0x0400 /* Two or more AND-connected terms */ +#define WO_EQUIV 0x0800 /* Of the form A==B, both columns */ +#define WO_NOOP 0x1000 /* This term does not restrict search space */ -#define WO_ALL 0xfff /* Mask of all possible WO_* values */ -#define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */ +#define WO_ALL 0x1fff /* Mask of all possible WO_* values */ +#define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */ /* ** These are definitions of bits in the WhereLoop.wsFlags field. diff --git a/test/where4.test b/test/where4.test index a26e9ad355..6bceb9174b 100644 --- a/test/where4.test +++ b/test/where4.test @@ -57,6 +57,10 @@ proc count sql { do_test where4-1.1 { count {SELECT rowid FROM t1 WHERE w IS NULL} } {7 2} +do_test where4-1.1b { + unset -nocomplain null + count {SELECT rowid FROM t1 WHERE w IS $null} +} {7 2} do_test where4-1.2 { count {SELECT rowid FROM t1 WHERE +w IS NULL} } {7 6} @@ -143,6 +147,17 @@ do_test where4-3.2 { SELECT * FROM t2 LEFT JOIN t3 ON a=x WHERE y IS NULL; } } {2 2 {} 3 {} {}} +do_test where4-3.3 { + execsql { + SELECT * FROM t2 LEFT JOIN t3 ON a=x WHERE NULL is y; + } +} {2 2 {} 3 {} {}} +do_test where4-3.4 { + unset -nocomplain null + execsql { + SELECT * FROM t2 LEFT JOIN t3 ON a=x WHERE y IS $null; + } +} {2 2 {} 3 {} {}} # Ticket #2189. Probably the same bug as #2177. #