1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Enable optimization of IN operators on constraints to virtual tables.

FossilOrigin-Name: aa650746b19e4a6a373f7e47effff3ab2f48e78c
This commit is contained in:
drh
2012-10-16 23:17:14 +00:00
parent 21890127cd
commit 281bbe2a95
4 changed files with 75 additions and 19 deletions

View File

@ -1,5 +1,5 @@
C Correct\scomments\sand\senhance\sreadability\sof\sthe\smkvsix\stool. C Enable\soptimization\sof\sIN\soperators\son\sconstraints\sto\svirtual\stables.
D 2012-10-15T20:28:22.029 D 2012-10-16T23:17:14.207
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -249,7 +249,7 @@ F src/vtab.c 9c64ae18af78c740610df841c6f49fc2d240a279
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 3e6c1f9efe4c6a029b0a750e0f6a63964f43bcce F src/where.c 62f667db8cdbb81028bf1c55ba4b0e845b79622c
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00 F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
@ -916,7 +916,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b
F test/view.test b182a67ec43f490b156b5a710827a341be83dd17 F test/view.test b182a67ec43f490b156b5a710827a341be83dd17
F test/vtab1.test 10fb9e656fe4b318cd82ff1616a340acc01aac4b F test/vtab1.test 524beb672c42463fe3d37351b74253c0b835498d
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1 F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
@ -1021,7 +1021,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
P 629a42d47a0d8f73de900f469845ce800bdb8959 P 2c3af657fee6153842d660a6ce29aa7d791ebd38
R c7830c7c0cb344c8cb6a175c95e5eb7f R 5cbef12c646a3899761eba454f8c4105
U mistachkin T *branch * vtab-IN-opt
Z f2086ddd83e8b281e8d53ba90c91d2db T *sym-vtab-IN-opt *
T -sym-trunk *
U drh
Z 07568d163c180c755b6278e856d28eda

View File

@ -1 +1 @@
2c3af657fee6153842d660a6ce29aa7d791ebd38 aa650746b19e4a6a373f7e47effff3ab2f48e78c

View File

@ -253,7 +253,7 @@ struct WhereCost {
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
#define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ #define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */ #define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */ #define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */
@ -2038,7 +2038,7 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_IN );
testcase( pTerm->eOperator==WO_ISNULL ); testcase( pTerm->eOperator==WO_ISNULL );
if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->eOperator & (WO_ISNULL) ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue;
nTerm++; nTerm++;
} }
@ -2086,15 +2086,18 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
pUsage; pUsage;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
u8 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->leftCursor != pSrc->iCursor ) continue;
assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_IN );
testcase( pTerm->eOperator==WO_ISNULL ); testcase( pTerm->eOperator==WO_ISNULL );
if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->eOperator & (WO_ISNULL) ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue;
pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i; pIdxCons[j].iTermOffset = i;
pIdxCons[j].op = (u8)pTerm->eOperator; op = (u8)pTerm->eOperator;
if( op==WO_IN ) op = WO_EQ;
pIdxCons[j].op = op;
/* The direct assignment in the previous line is possible only because /* The direct assignment in the previous line is possible only because
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
** following asserts verify this fact. */ ** following asserts verify this fact. */
@ -2104,7 +2107,7 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
j++; j++;
} }
for(i=0; i<nOrderBy; i++){ for(i=0; i<nOrderBy; i++){
@ -4030,6 +4033,7 @@ static Bitmask codeOneLoopStart(
** to access the data. ** to access the data.
*/ */
int iReg; /* P3 Value for OP_VFilter */ int iReg; /* P3 Value for OP_VFilter */
int addrNotFound;
sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
int nConstraint = pVtabIdx->nConstraint; int nConstraint = pVtabIdx->nConstraint;
struct sqlite3_index_constraint_usage *aUsage = struct sqlite3_index_constraint_usage *aUsage =
@ -4039,11 +4043,18 @@ static Bitmask codeOneLoopStart(
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
iReg = sqlite3GetTempRange(pParse, nConstraint+2); iReg = sqlite3GetTempRange(pParse, nConstraint+2);
addrNotFound = pLevel->addrBrk;
for(j=1; j<=nConstraint; j++){ for(j=1; j<=nConstraint; j++){
for(k=0; k<nConstraint; k++){ for(k=0; k<nConstraint; k++){
if( aUsage[k].argvIndex==j ){ if( aUsage[k].argvIndex==j ){
int iTerm = aConstraint[k].iTermOffset; WhereTerm *pTerm = &pWC->a[aConstraint[k].iTermOffset];
sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1); int iTarget = iReg+j+1;
if( pTerm->eOperator & WO_IN ){
codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
addrNotFound = pLevel->addrNxt;
}else{
sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
}
break; break;
} }
} }
@ -4051,7 +4062,7 @@ static Bitmask codeOneLoopStart(
} }
sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr, sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr,
pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
pVtabIdx->needToFreeIdxStr = 0; pVtabIdx->needToFreeIdxStr = 0;
for(j=0; j<nConstraint; j++){ for(j=0; j<nConstraint; j++){

View File

@ -1091,12 +1091,54 @@ do_test vtab1.13-3 {
} {15 {} 16} } {15 {} 16}
do_test vtab1-14.001 {
execsql {SELECT rowid, * FROM echo_c WHERE +rowid IN (1,2,3)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.002 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid IN (1,2,3)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.003 {
execsql {SELECT rowid, * FROM echo_c WHERE +rowid IN (0,1,5,2,'a',3,NULL)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.004 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid IN (0,1,5,'a',2,3,NULL)}
} {1 3 G H 2 {} 15 16 3 15 {} 16}
do_test vtab1-14.005 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,1,5,'a',2,3)}
} {}
do_test vtab1-14.006 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,5,'a',2,3)}
} {1 3 G H}
do_test vtab1-14.007 {
execsql {SELECT rowid, * FROM echo_c WHERE +rowid NOT IN (0,5,'a',2,3,NULL)}
} {}
do_test vtab1-14.008 {
execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,5,'a',2,3,NULL)}
} {}
do_test vtab1-14.011 {
execsql {SELECT * FROM echo_c WHERE +a IN (1,3,8,'x',NULL,15,24)}
} {3 G H 15 {} 16}
do_test vtab1-14.012 {
execsql {SELECT * FROM echo_c WHERE a IN (1,3,8,'x',NULL,15,24)}
} {3 G H 15 {} 16}
do_test vtab1-14.013 {
execsql {SELECT * FROM echo_c WHERE a NOT IN (1,8,'x',15,24)}
} {3 G H}
do_test vtab1-14.014 {
execsql {SELECT * FROM echo_c WHERE a NOT IN (1,8,'x',NULL,15,24)}
} {}
do_test vtab1-14.015 {
execsql {SELECT * FROM echo_c WHERE +a NOT IN (1,8,'x',NULL,15,24)}
} {}
do_test vtab1-14.1 { do_test vtab1-14.1 {
execsql { DELETE FROM c } execsql { DELETE FROM c }
set echo_module "" set echo_module ""
execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) } execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) }
set echo_module set echo_module
} [list xBestIndex {SELECT rowid, * FROM 'c'} xFilter {SELECT rowid, * FROM 'c'}] } {/xBestIndex {SELECT rowid, . FROM 'c' WHERE rowid = .} xFilter {SELECT rowid, . FROM 'c' WHERE rowid = .} 1/}
do_test vtab1-14.2 { do_test vtab1-14.2 {
set echo_module "" set echo_module ""
@ -1114,7 +1156,7 @@ do_test vtab1-14.4 {
set echo_module "" set echo_module ""
execsql { SELECT * FROM echo_c WHERE a IN (1, 2) } execsql { SELECT * FROM echo_c WHERE a IN (1, 2) }
set echo_module set echo_module
} [list xBestIndex {SELECT rowid, * FROM 'c'} xFilter {SELECT rowid, * FROM 'c'}] } {/xBestIndex {SELECT rowid, . FROM 'c' WHERE a = .} xFilter {SELECT rowid, . FROM 'c' WHERE a = .} 1/}
do_test vtab1-15.1 { do_test vtab1-15.1 {
execsql { execsql {