From: drh Date: Fri, 26 Aug 2016 21:15:35 +0000 (+0000) Subject: Fix the sqlite3FindInIndex() to ensure that it always uses a prefix of X-Git-Tag: version-3.15.0~110^2~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a84a283d180a4ffa54b1fb615572709dfe0f7b25;p=thirdparty%2Fsqlite.git Fix the sqlite3FindInIndex() to ensure that it always uses a prefix of the index and uses no repeated columns. Enhanced comments. FossilOrigin-Name: b9fc89e432fbe4e5b41959a42797641907e075e3 --- diff --git a/manifest b/manifest index e112f421dc..05accaa53d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sEXPLAIN\sQUERY\sPLAN\sline\sfor\swhen\sa\sindex\sis\sused\sto\simplement\nan\sIN\soperator. -D 2016-08-26T19:54:12.433 +C Fix\sthe\ssqlite3FindInIndex()\sto\sensure\sthat\sit\salways\suses\sa\sprefix\sof\nthe\sindex\sand\suses\sno\srepeated\scolumns.\s\sEnhanced\scomments. +D 2016-08-26T21:15:35.199 F Makefile.in cfd8fb987cd7a6af046daa87daa146d5aad0e088 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 5017381e4853b1472e01d5bb926be1268eba429c @@ -338,7 +338,7 @@ F src/ctime.c e77f3dc297b4b65c96da78b4ae4272fdfae863d7 F src/date.c 95c9a8d00767e7221a8e9a31f4e913fc8029bf6b F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d F src/delete.c 76c084f0265f4a3cd1ecf17eee112a94f1ccbc05 -F src/expr.c 935366a02ad0c33e7cd19ff382ef9bcdfa1aa7a9 +F src/expr.c 4c80148f83127862f69ff509fb0aa261396df24e F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e2be0968c1adc679c87e467aa5b4f167588f38a8 F src/func.c 29cc9acb170ec1387b9f63eb52cd85f8de96c771 @@ -1521,7 +1521,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 078bb69e99891ba3b76a39ac974990714c43908f -R 155df167db2a04d38d0a374ab683c0e3 +P 171aa833a2e1650c3d9cf9bd6438ae46f6c35871 +R 94dfe8764b4b5e69457ee17a8ecdc781 U drh -Z d9ed9721b1e3c6348d8b59f53fc4268d +Z ef81f77fdd077e1b395585c253a1bf6f diff --git a/manifest.uuid b/manifest.uuid index 5d43906475..e5a0ab8485 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -171aa833a2e1650c3d9cf9bd6438ae46f6c35871 \ No newline at end of file +b9fc89e432fbe4e5b41959a42797641907e075e3 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 08b72fed80..8ede47731f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1960,7 +1960,6 @@ static Select *isCandidateForInOpt(Expr *pX){ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; assert( pEList!=0 ); - /* All SELECT results must be columns. */ for(i=0; inExpr; i++){ Expr *pRes = pEList->a[i].pExpr; @@ -2150,11 +2149,7 @@ int sqlite3FindInIndex( sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - /* This function is only called from two places. In both cases the vdbe - ** has already been allocated. So assume sqlite3GetVdbe() is always - ** successful here. - */ - assert(v); + assert(v); /* sqlite3GetVdbe() has always been previously called */ if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ /* The "x IN (SELECT rowid FROM table)" case */ int iAddr = sqlite3CodeOnce(pParse); @@ -2195,67 +2190,79 @@ int sqlite3FindInIndex( } } - /* The collation sequence used by the comparison. If an index is to - ** be used in place of a temp-table, it must be ordered according - ** to this collation sequence. */ - - for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ - if( pIdx->nColumnnKeyCol>nExpr - ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx)) - ){ - continue; + if( affinity_ok ){ + /* Search for an existing index that will work for this IN operator */ + for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){ + Bitmask colUsed; /* Columns of the index used */ + Bitmask mCol; /* Mask for the current column */ + if( pIdx->nColumnnColumn==BMS-2 ); + testcase( pIdx->nColumn==BMS-1 ); + if( pIdx->nColumn>=BMS-1 ) continue; + if( mustBeUnique ){ + if( pIdx->nKeyCol>nExpr + ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx)) + ){ + continue; /* This index is not unique over the IN RHS columns */ + } } - } - - for(i=0; ipLeft, i); - Expr *pRhs = pEList->a[i].pExpr; - CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); - int j; - - assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); - for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; - assert( pIdx->azColl[j] ); - if( pReq==0 ) continue; - if( sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ) continue; - break; + + colUsed = 0; /* Columns of index used so far */ + for(i=0; ipLeft, i); + Expr *pRhs = pEList->a[i].pExpr; + CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + int j; + + assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); + for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; + assert( pIdx->azColl[j] ); + if( pReq==0 ) continue; + if( sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ) continue; + break; + } + if( j==nExpr ) break; + mCol = MASKBIT(j); + if( mCol & colUsed ) break; /* Each column used only once */ + colUsed |= mCol; + if( aiMap ) aiMap[i] = j; } - if( j==nExpr ) break; - if( aiMap ) aiMap[i] = j; - } - - if( i==nExpr ){ - int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); -#ifndef SQLITE_OMIT_EXPLAIN - sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0, - sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR", pIdx->zName), - P4_DYNAMIC); -#endif - sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); - sqlite3VdbeSetP4KeyInfo(pParse, pIdx); - VdbeComment((v, "%s", pIdx->zName)); - assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); - eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; - - if( prRhsHasNull ){ - *prRhsHasNull = ++pParse->nMem; -#ifdef SQLITE_ENABLE_COLUMN_USED_MASK - i64 mask = (1<zName), + P4_DYNAMIC); + #endif + sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + VdbeComment((v, "%s", pIdx->zName)); + assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); + eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; + + if( prRhsHasNull ){ + *prRhsHasNull = ++pParse->nMem; + #ifdef SQLITE_ENABLE_COLUMN_USED_MASK + i64 mask = (1<