From: drh Date: Wed, 13 May 2015 15:24:07 +0000 (+0000) Subject: An early attempt to get indexes to work with the IS operator. This code X-Git-Tag: version-3.8.11~262^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fcd49531c9fc2b5a75b713ac8d817f8dd722e6fa;p=thirdparty%2Fsqlite.git An early attempt to get indexes to work with the IS operator. This code passes tests, but much more testing is needed to verify that it works on all corner cases. FossilOrigin-Name: 6f7f1673d00d216a5aa456acb44793a14f3b3d91 --- diff --git a/manifest b/manifest index 0c5a5294e3..ec12a04f7c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sto\sthe\sMSVC\smakefile. -D 2015-05-13T04:50:30.732 +C An\searly\sattempt\sto\sget\sindexes\sto\swork\swith\sthe\sIS\soperator.\s\sThis\scode\npasses\stests,\sbut\smuch\smore\stesting\sis\sneeded\sto\sverify\sthat\sit\sworks\son\nall\scorner\scases. +D 2015-05-13T15:24:07.257 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 85fff9c40569ccb79c3177419b339e7d7df566cb -F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c +F src/where.c 48e3c1f0a8a7ecbaeb5a57c195254243d49430ba +F src/whereInt.h 6b5a8ac7b4adc055176c3330d755735ed674335d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 @@ -1258,7 +1258,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P b33f1bacfdb34fe66b7b073e68bfac38498d6e88 -R 786cf9bafb843a30daaea508385a36b1 -U mistachkin -Z cf0d8cd171ac487c0fd87c289759c254 +P 59e3e9e764440b7feaafadff74f422535d21bca2 +R 9f6038338a4c8e424f8c4ba92f9afc16 +T *branch * index-is-operator +T *sym-index-is-operator * +T -sym-trunk * +U drh +Z a0eadd388567e992c46f2fabbded464e diff --git a/manifest.uuid b/manifest.uuid index af09740391..877d59c28e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -59e3e9e764440b7feaafadff74f422535d21bca2 \ No newline at end of file +6f7f1673d00d216a5aa456acb44793a14f3b3d91 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 85eb00b46b..6bbfaca879 100644 --- a/src/where.c +++ b/src/where.c @@ -363,7 +363,7 @@ static int allowedOp(int op){ assert( TK_LT>TK_EQ && TK_LTTK_EQ && TK_LE=TK_EQ && op<=TK_GE) || op==TK_ISNULL; + return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; } /* @@ -416,6 +416,8 @@ static u16 operatorMask(int op){ c = WO_IN; }else if( op==TK_ISNULL ){ c = WO_ISNULL; + }else if( op==TK_IS ){ + c = WO_EQ; }else{ assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); c = (u16)(WO_EQ<<(op-TK_EQ)); @@ -427,6 +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 ); return c; } @@ -1254,6 +1257,7 @@ static void exprAnalyze( pTerm->u.leftColumn = pLeft->iColumn; pTerm->eOperator = operatorMask(op) & opMask; } + if( op==TK_IS ) pTerm->wtFlags |= TERM_NULLOK; if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; Expr *pDup; @@ -1278,6 +1282,7 @@ static void exprAnalyze( pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } + if( op==TK_IS ) pNew->wtFlags |= TERM_NULLOK; }else{ pDup = pExpr; pNew = pTerm; @@ -1468,10 +1473,8 @@ static void exprAnalyze( ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a ** virtual term of that form. ** - ** Note that the virtual term must be tagged with TERM_VNULL. This - ** TERM_VNULL tag will suppress the not-null check at the beginning - ** of the loop. Without the TERM_VNULL flag, the not-null check at - ** the start of the loop will prevent any results from being returned. + ** Note that the virtual term must be tagged with both TERM_VNULL + ** and TERM_NULLOK. */ if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN @@ -1488,7 +1491,7 @@ static void exprAnalyze( sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0); idxNew = whereClauseInsert(pWC, pNewExpr, - TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); + TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL|TERM_NULLOK); if( idxNew ){ pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = 0; @@ -2792,7 +2795,7 @@ static int codeEqualityTerm( int iReg; /* Register holding results */ assert( iTarget>0 ); - if( pX->op==TK_EQ ){ + if( pX->op==TK_EQ || pX->op==TK_IS ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; @@ -2977,7 +2980,9 @@ static int codeAllEqualityTerms( testcase( pTerm->eOperator & WO_IN ); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ Expr *pRight = pTerm->pExpr->pRight; - if( sqlite3ExprCanBeNull(pRight) ){ + if( (pTerm->wtFlags & TERM_NULLOK)==0 + && sqlite3ExprCanBeNull(pRight) + ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } @@ -3626,7 +3631,7 @@ static Bitmask codeOneLoopStart( Expr *pRight = pRangeStart->pExpr->pRight; sqlite3ExprCode(pParse, pRight, regBase+nEq); whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); - if( (pRangeStart->wtFlags & TERM_VNULL)==0 + if( (pRangeStart->wtFlags & TERM_NULLOK)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); @@ -3672,7 +3677,7 @@ static Bitmask codeOneLoopStart( sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); sqlite3ExprCode(pParse, pRight, regBase+nEq); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); - if( (pRangeEnd->wtFlags & TERM_VNULL)==0 + if( (pRangeEnd->wtFlags & TERM_NULLOK)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); @@ -4158,9 +4163,10 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; - sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n", - iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, - pTerm->eOperator); + sqlite3DebugPrintf( + "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n", + iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + pTerm->eOperator, pTerm->wtFlags); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } diff --git a/src/whereInt.h b/src/whereInt.h index 04cc2029d8..915d7b8d68 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -280,6 +280,7 @@ struct WhereTerm { #define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ #define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ #define TERM_LIKE 0x400 /* The original LIKE operator */ +#define TERM_NULLOK 0x800 /* Comparison operators against NULL work */ /* ** An instance of the WhereScan object is used as an iterator for locating