The IS operator can now use indexes the same as the == operator.
FossilOrigin-Name: 3428043cd00294457548bb07ada2ad526b6532d6
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C Enhancements\sto\sthe\sMSVC\smakefile.
|
||||
D 2015-05-13T04:50:30.732
|
||||
C The\sIS\soperator\scan\snow\suse\sindexes\sthe\ssame\sas\sthe\s==\soperator.
|
||||
D 2015-05-14T14:32:11.685
|
||||
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 08fadd0d211699348349be5449f3a1e391adf20e
|
||||
F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
||||
@@ -1082,7 +1082,7 @@ F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
|
||||
F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd
|
||||
F test/transitive1.test 875a9f0097a15b30a62431d183f989364d5accac
|
||||
F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03
|
||||
F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6
|
||||
F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945
|
||||
@@ -1120,12 +1120,12 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9
|
||||
F test/vtab1.test d1e5ec7a818f1d3f0402382b6a1d0c06071b770f
|
||||
F test/vtab2.test 3644649aa8d1daac57fd541f6a5f914cac59203e
|
||||
F test/vtab1.test dbe0e9e121102d0ba365f20d126a72676aa2343f
|
||||
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
|
||||
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
|
||||
F test/vtab6.test 5f5380c425e52993560ab4763db4f826d2ba7b09
|
||||
F test/vtab6.test d2986cf418dc51e7fb81d12366bea2caa8b812df
|
||||
F test/vtab7.test ae560ebea870ed04e9aa4177cc302f910faaabb5
|
||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||
@@ -1165,10 +1165,10 @@ F test/walro.test 34422d1d95aaff0388f0791ec20edb34e2a3ed57
|
||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test 28b64e93428961b07b0d486778d63fd672948f6b
|
||||
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
|
||||
@@ -1177,7 +1177,7 @@ F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
|
||||
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
|
||||
F test/whereD.test 9eba1f9b18e5b19a0b0bcaae5e8c037260195f2b
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
@@ -1258,7 +1258,8 @@ 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 f397c8622ae5a36a71f81d9f2549ca314005ece5
|
||||
R bdc88e4814b826734527d4ac723cdd70
|
||||
T +closed f397c8622ae5a36a71f81d9f2549ca314005ece5
|
||||
U drh
|
||||
Z 2145c2897b1f3b7880cf6c9a6c38a0d4
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
59e3e9e764440b7feaafadff74f422535d21bca2
|
||||
3428043cd00294457548bb07ada2ad526b6532d6
|
||||
+46
-29
@@ -363,7 +363,7 @@ static int allowedOp(int op){
|
||||
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
|
||||
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
|
||||
assert( TK_GE==TK_EQ+4 );
|
||||
return op==TK_IN || (op>=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_IS;
|
||||
}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_IS );
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -487,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;
|
||||
@@ -593,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;
|
||||
@@ -1254,6 +1260,7 @@ static void exprAnalyze(
|
||||
pTerm->u.leftColumn = pLeft->iColumn;
|
||||
pTerm->eOperator = operatorMask(op) & opMask;
|
||||
}
|
||||
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
|
||||
if( pRight && pRight->op==TK_COLUMN ){
|
||||
WhereTerm *pNew;
|
||||
Expr *pDup;
|
||||
@@ -1271,13 +1278,14 @@ static void exprAnalyze(
|
||||
markTermAsChild(pWC, idxNew, idxTerm);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
pTerm->wtFlags |= TERM_COPIED;
|
||||
if( pExpr->op==TK_EQ
|
||||
if( (op==TK_EQ || op==TK_IS)
|
||||
&& !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
&& OptimizationEnabled(db, SQLITE_Transitive)
|
||||
){
|
||||
pTerm->eOperator |= WO_EQUIV;
|
||||
eExtraOp = WO_EQUIV;
|
||||
}
|
||||
if( op==TK_IS ) pNew->wtFlags |= TERM_IS;
|
||||
}else{
|
||||
pDup = pExpr;
|
||||
pNew = pTerm;
|
||||
@@ -1468,10 +1476,7 @@ 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 TERM_VNULL.
|
||||
*/
|
||||
if( pExpr->op==TK_NOTNULL
|
||||
&& pExpr->pLeft->op==TK_COLUMN
|
||||
@@ -1675,11 +1680,12 @@ 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;
|
||||
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
|
||||
testcase( pTerm->pExpr->op==TK_IS );
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -1896,8 +1902,9 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
|
||||
testcase( pTerm->eOperator & WO_IN );
|
||||
testcase( pTerm->eOperator & WO_ISNULL );
|
||||
testcase( pTerm->eOperator & WO_IS );
|
||||
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;
|
||||
nTerm++;
|
||||
}
|
||||
@@ -1948,9 +1955,10 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
if( pTerm->leftCursor != pSrc->iCursor ) continue;
|
||||
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
|
||||
testcase( pTerm->eOperator & WO_IN );
|
||||
testcase( pTerm->eOperator & WO_IS );
|
||||
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;
|
||||
@@ -2792,7 +2800,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 +2985,7 @@ 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_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
@@ -4099,16 +4107,19 @@ 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_EQ|WO_IS))==0 ) continue;
|
||||
if( (pTerm->eOperator & WO_EQUIV)==0 ) 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 );
|
||||
testcase( pAlt->eOperator & WO_IS );
|
||||
testcase( pAlt->eOperator & WO_IN );
|
||||
VdbeModuleComment((v, "begin transitive constraint"));
|
||||
pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
|
||||
@@ -4158,9 +4169,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);
|
||||
}
|
||||
}
|
||||
@@ -4650,8 +4662,9 @@ 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 ){
|
||||
k = 10;
|
||||
}else{
|
||||
@@ -4719,10 +4732,10 @@ static int whereLoopAddBtreeIndex(
|
||||
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
|
||||
if( pNew->wsFlags & WHERE_BTM_LIMIT ){
|
||||
opMask = WO_LT|WO_LE;
|
||||
}else if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){
|
||||
}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);
|
||||
|
||||
@@ -4785,7 +4798,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 ){
|
||||
@@ -4835,7 +4848,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 ){
|
||||
@@ -4852,8 +4865,9 @@ static int whereLoopAddBtreeIndex(
|
||||
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
|
||||
){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){
|
||||
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{
|
||||
@@ -5690,9 +5704,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;
|
||||
@@ -5701,6 +5715,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
z2 = pColl->zName;
|
||||
if( sqlite3StrICmp(z1, z2)!=0 ) continue;
|
||||
testcase( pTerm->pExpr->op==TK_IS );
|
||||
}
|
||||
obSat |= MASKBIT(i);
|
||||
}
|
||||
@@ -5731,7 +5746,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
/* Skip over == and IS NULL terms */
|
||||
if( j<pLoop->u.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 );
|
||||
@@ -6304,8 +6319,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;
|
||||
@@ -6320,8 +6336,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
|
||||
) continue;
|
||||
for(j=0; j<pIdx->nKeyCol; 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;
|
||||
}
|
||||
if( j!=pIdx->nKeyCol ) continue;
|
||||
|
||||
+12
-10
@@ -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_IS 0x800 /* Term.pExpr is an IS operator */
|
||||
|
||||
/*
|
||||
** An instance of the WhereScan object is used as an iterator for locating
|
||||
@@ -428,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
|
||||
#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.
|
||||
|
||||
+17
-1
@@ -66,6 +66,12 @@ do_execsql_test transitive1-301 {
|
||||
WHERE w=y AND y IS NOT NULL
|
||||
ORDER BY w;
|
||||
} {1 2 1 3 3 4 3 6 5 6 5 7}
|
||||
do_execsql_test transitive1-302 {
|
||||
SELECT *
|
||||
FROM t301 CROSS JOIN t302
|
||||
WHERE w IS y AND y IS NOT NULL
|
||||
ORDER BY w;
|
||||
} {1 2 1 3 3 4 3 6 5 6 5 7}
|
||||
do_execsql_test transitive1-310 {
|
||||
SELECT *
|
||||
FROM t301 CROSS JOIN t302 ON w=y
|
||||
@@ -103,7 +109,7 @@ do_execsql_test transitive1-332 {
|
||||
} {3 4 3 6 1 2 1 3}
|
||||
|
||||
# Ticket [c620261b5b5dc] circa 2013-10-28.
|
||||
# Make sureconstraints are not used with LEFT JOINs.
|
||||
# Make sure constraints are not used with LEFT JOINs.
|
||||
#
|
||||
# The next case is from the ticket report. It outputs no rows in 3.8.1
|
||||
# prior to the bug-fix.
|
||||
@@ -116,6 +122,16 @@ do_execsql_test transitive1-400 {
|
||||
INSERT INTO t403 VALUES(1);
|
||||
SELECT '1-row' FROM t401 LEFT JOIN t402 ON b=a JOIN t403 ON c=a;
|
||||
} {1-row}
|
||||
do_execsql_test transitive1-401 {
|
||||
SELECT '1-row' FROM t401 LEFT JOIN t402 ON b IS a JOIN t403 ON c=a;
|
||||
} {1-row}
|
||||
do_execsql_test transitive1-402 {
|
||||
SELECT '1-row' FROM t401 LEFT JOIN t402 ON b=a JOIN t403 ON c IS a;
|
||||
} {1-row}
|
||||
do_execsql_test transitive1-403 {
|
||||
SELECT '1-row' FROM t401 LEFT JOIN t402 ON b IS a JOIN t403 ON c IS a;
|
||||
} {1-row}
|
||||
|
||||
|
||||
# The following is a script distilled from the XBMC project where the
|
||||
# bug was originally encountered. The correct answer is a single row
|
||||
|
||||
+12
-1
@@ -1085,11 +1085,22 @@ do_test vtab1.13-3 {
|
||||
SELECT * FROM echo_c WHERE b IS NULL
|
||||
}
|
||||
} {15 {} 16}
|
||||
do_test vtab1.13-3 {
|
||||
do_test vtab1.13-4 {
|
||||
unset -nocomplain null
|
||||
execsql {
|
||||
SELECT * FROM echo_c WHERE b IS $null
|
||||
}
|
||||
} {15 {} 16}
|
||||
do_test vtab1.13-5 {
|
||||
execsql {
|
||||
SELECT * FROM echo_c WHERE b IS NULL AND a = 15;
|
||||
}
|
||||
} {15 {} 16}
|
||||
do_test vtab1.13-6 {
|
||||
execsql {
|
||||
SELECT * FROM echo_c WHERE NULL IS b AND a IS 15;
|
||||
}
|
||||
} {15 {} 16}
|
||||
|
||||
|
||||
do_test vtab1-14.001 {
|
||||
|
||||
+8
-1
@@ -104,6 +104,14 @@ do_test vtab2-3.2 {
|
||||
WHERE a.rowid=1
|
||||
}
|
||||
} {main schema 0 database {} 0 {} 0 {} {} {} {} {} {} {} {} {}}
|
||||
do_test vtab2-3.3 {
|
||||
execsql {
|
||||
SELECT *, b.rowid
|
||||
FROM schema a LEFT JOIN schema b ON a.dflt_value IS b.dflt_value
|
||||
AND a.dflt_value IS NOT NULL
|
||||
WHERE a.rowid=1
|
||||
}
|
||||
} {main schema 0 database {} 0 {} 0 {} {} {} {} {} {} {} {} {}}
|
||||
|
||||
do_test vtab2-4.1 {
|
||||
execsql {
|
||||
@@ -153,4 +161,3 @@ ifcapable fts3 {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -233,6 +233,11 @@ do_test vtab6-2.4 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d
|
||||
}
|
||||
} {1 2 3 {} {} {} 2 3 4 {} {} {} 3 4 5 1 2 3}
|
||||
do_test vtab6-2.4.1 {
|
||||
execsql {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a IS t2.d
|
||||
}
|
||||
} {1 2 3 {} {} {} 2 3 4 {} {} {} 3 4 5 1 2 3}
|
||||
do_test vtab6-2.5 {
|
||||
execsql {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d WHERE t1.a>1
|
||||
|
||||
@@ -65,9 +65,15 @@ proc count sql {
|
||||
do_test where-1.1.1 {
|
||||
count {SELECT x, y, w FROM t1 WHERE w=10}
|
||||
} {3 121 10 3}
|
||||
do_test where-1.1.1b {
|
||||
count {SELECT x, y, w FROM t1 WHERE w IS 10}
|
||||
} {3 121 10 3}
|
||||
do_eqp_test where-1.1.2 {
|
||||
SELECT x, y, w FROM t1 WHERE w=10
|
||||
} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*}
|
||||
do_eqp_test where-1.1.2b {
|
||||
SELECT x, y, w FROM t1 WHERE w IS 10
|
||||
} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*}
|
||||
do_test where-1.1.3 {
|
||||
db status step
|
||||
} {0}
|
||||
@@ -101,12 +107,21 @@ do_test where-1.3.1 {
|
||||
do_test where-1.3.2 {
|
||||
count {SELECT x, y, w AS abc FROM t1 WHERE 11=abc}
|
||||
} {3 144 11 3}
|
||||
do_test where-1.3.3 {
|
||||
count {SELECT x, y, w AS abc FROM t1 WHERE 11 IS abc}
|
||||
} {3 144 11 3}
|
||||
do_test where-1.4.1 {
|
||||
count {SELECT w, x, y FROM t1 WHERE 11=w AND x>2}
|
||||
} {11 3 144 3}
|
||||
do_test where-1.4.1b {
|
||||
count {SELECT w, x, y FROM t1 WHERE 11 IS w AND x>2}
|
||||
} {11 3 144 3}
|
||||
do_eqp_test where-1.4.2 {
|
||||
SELECT w, x, y FROM t1 WHERE 11=w AND x>2
|
||||
} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*}
|
||||
do_eqp_test where-1.4.2b {
|
||||
SELECT w, x, y FROM t1 WHERE 11 IS w AND x>2
|
||||
} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*}
|
||||
do_test where-1.4.3 {
|
||||
count {SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2}
|
||||
} {11 3 144 3}
|
||||
@@ -143,6 +158,9 @@ do_test where-1.10 {
|
||||
do_test where-1.11 {
|
||||
count {SELECT x, y FROM t1 WHERE x=3 AND y=100 AND w<10}
|
||||
} {3 100 3}
|
||||
do_test where-1.11b {
|
||||
count {SELECT x, y FROM t1 WHERE x IS 3 AND y IS 100 AND w<10}
|
||||
} {3 100 3}
|
||||
|
||||
# New for SQLite version 2.1: Verify that that inequality constraints
|
||||
# are used correctly.
|
||||
@@ -150,12 +168,18 @@ do_test where-1.11 {
|
||||
do_test where-1.12 {
|
||||
count {SELECT w FROM t1 WHERE x=3 AND y<100}
|
||||
} {8 3}
|
||||
do_test where-1.12b {
|
||||
count {SELECT w FROM t1 WHERE x IS 3 AND y<100}
|
||||
} {8 3}
|
||||
do_test where-1.13 {
|
||||
count {SELECT w FROM t1 WHERE x=3 AND 100>y}
|
||||
} {8 3}
|
||||
do_test where-1.14 {
|
||||
count {SELECT w FROM t1 WHERE 3=x AND y<100}
|
||||
} {8 3}
|
||||
do_test where-1.14b {
|
||||
count {SELECT w FROM t1 WHERE 3 IS x AND y<100}
|
||||
} {8 3}
|
||||
do_test where-1.15 {
|
||||
count {SELECT w FROM t1 WHERE 3=x AND 100>y}
|
||||
} {8 3}
|
||||
@@ -168,6 +192,9 @@ do_test where-1.17 {
|
||||
do_test where-1.18 {
|
||||
count {SELECT w FROM t1 WHERE x=3 AND y>225}
|
||||
} {15 3}
|
||||
do_test where-1.18b {
|
||||
count {SELECT w FROM t1 WHERE x IS 3 AND y>225}
|
||||
} {15 3}
|
||||
do_test where-1.19 {
|
||||
count {SELECT w FROM t1 WHERE x=3 AND 225<y}
|
||||
} {15 3}
|
||||
@@ -180,6 +207,9 @@ do_test where-1.21 {
|
||||
do_test where-1.22 {
|
||||
count {SELECT w FROM t1 WHERE x=3 AND y>121 AND y<196}
|
||||
} {11 12 5}
|
||||
do_test where-1.22b {
|
||||
count {SELECT w FROM t1 WHERE x IS 3 AND y>121 AND y<196}
|
||||
} {11 12 5}
|
||||
do_test where-1.23 {
|
||||
count {SELECT w FROM t1 WHERE x=3 AND y>=121 AND y<=196}
|
||||
} {10 11 12 13 9}
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
|
||||
@@ -59,6 +59,7 @@ foreach {tn sql res} {
|
||||
12 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL" {}
|
||||
13 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL" {}
|
||||
14 "SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5" {3 4}
|
||||
15 "SELECT i FROM t1 WHERE rowid IS '12'" {12}
|
||||
} {
|
||||
do_execsql_test 1.$tn.1 $sql $res
|
||||
do_execsql_test 1.$tn.2 "$sql ORDER BY i ASC" [lsort -integer -inc $res]
|
||||
|
||||
Reference in New Issue
Block a user