From: drh Date: Wed, 16 Dec 2009 23:28:31 +0000 (+0000) Subject: Fix for the "(x AND y) OR z" bug backported to version 3.6.21. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fbranch-3.6.21;p=thirdparty%2Fsqlite.git Fix for the "(x AND y) OR z" bug backported to version 3.6.21. FossilOrigin-Name: 867347323b0c095159411de36cbd87b09c1b2863 --- diff --git a/VERSION b/VERSION index 1bff231925..cec9d2efc3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.6.21 +3.6.21.1 diff --git a/manifest b/manifest index d8e009b542..5746e93a8b 100644 --- a/manifest +++ b/manifest @@ -1,14 +1,14 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C Version\s3.6.21\srelease\scandidate\s3. -D 2009-12-07T16:39:13 +C Fix\sfor\sthe\s"(x\sAND\sy)\sOR\sz"\sbug\sbackported\sto\sversion\s3.6.21. +D 2009-12-16T23:28:32 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.vxworks 10010ddbf52e2503c7c49c7c0b7c7a096f8638a6 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 -F VERSION aa30c4b131a981624ab576df19eb4c5c9cd582ac +F VERSION 1e6bf6cfcc755751b88c848e449f7ff02a049511 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248 @@ -169,7 +169,7 @@ F src/select.c 2f9ed7482e7a25b0b127fc41693bbdbe1caf5647 F src/shell.c f4948cb6d30665d755a6b5e0ec313d1094aab828 F src/sqlite.h.in 2d34605565e021851255e0bbcb15f8c1930d1f6f F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 -F src/sqliteInt.h e946a6a3f2df015cdbc7668e9626987e8badbb5f +F src/sqliteInt.h 93d5d01d9ea57b95ba709733dce830ec056deb84 F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6 F src/status.c e651be6b30d397d86384c6867bc016e4913bcac7 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -222,7 +222,7 @@ F src/vdbemem.c 1e16e3a16e55f4c3452834f0e041726021aa66e0 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c 456fc226614569f0e46f216e33265bea268bd917 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 11b5b00c49d53e767a7eb855bc60790edeca6185 +F src/where.c f20ee9a15c1ccb8b94cd31e3f8c6868e1358fc07 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45 @@ -602,6 +602,7 @@ F test/thread_common.tcl b65e6b1d1d90dc885e10ad080896c6c56eef0819 F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 +F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e F test/tkt-3fe897352e.test 8084dad39807eac10b10720c84193bd1a5980973 F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9 @@ -745,7 +746,7 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf F test/where7.test fdd58ab9dec9f97679e65d4414bf5e07d725d79f -F test/where8.test 434f08974964b10378d67867773a2c3aedaf1d4b +F test/where8.test 2bb8ea44b745fcc93db150fac9ce33d12e499760 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623 F test/whereA.test 1d1674254614147c866ab9b59af6582f454a858c @@ -779,14 +780,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P cd50acf37fd1e3b388f98fb2df7ed03cff454b24 -R 5d0b6a47a50c8a9cdc60d3d4d61a8cf2 +P 1ed88e9d01e9eda5cbc622e7614277f29bcc551c +R e7d1ff5fd98ae55ae61bf91d3d4df1c9 U drh -Z 8b76b0c0726e570aef93558fa0c3fdc7 +Z 49479a3b1562abdd14a885a8865e0fa5 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFLHS+0oxKgR168RlERArAKAJ97NTyJvzQHmWC2GXt2Xt7D52m04QCeLeQt -HYPTNDWgvT/KRZ19RtHNjDQ= -=tE2+ +iD8DBQFLKW0joxKgR168RlERAlZgAJoDPgJ9k9EK/kFQwfqfQ0gY5Pb57wCePWTc +6VlIsxRe62S0m1PuLBEsM9E= +=g+YX -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index b4e4637fcf..1978f23a93 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1ed88e9d01e9eda5cbc622e7614277f29bcc551c \ No newline at end of file +867347323b0c095159411de36cbd87b09c1b2863 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1202971a84..1e15dbd167 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1894,6 +1894,7 @@ struct WhereLevel { #define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */ #define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */ #define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */ +#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */ /* ** The WHERE clause processing routine has two halves. The @@ -1906,6 +1907,7 @@ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */ + u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ SrcList *pTabList; /* List of tables in the join */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ diff --git a/src/where.c b/src/where.c index 067ec4079b..f6d9ab296e 100644 --- a/src/where.c +++ b/src/where.c @@ -3265,13 +3265,14 @@ static Bitmask codeOneLoopStart( */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */ WhereTerm *pFinal; /* Final subterm within the OR-clause. */ - SrcList oneTab; /* Shortened table list */ + SrcList *pOrTab; /* Shortened table list or OR-clause generation */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ int regRowid = 0; /* Register holding rowid */ int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ int iRetInit; /* Address of regReturn init */ + int untestedTerms = 0; /* Some terms not completely tested */ int ii; pTerm = pLevel->plan.u.pTerm; @@ -3280,11 +3281,29 @@ static Bitmask codeOneLoopStart( assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); pOrWc = &pTerm->u.pOrInfo->wc; pFinal = &pOrWc->a[pOrWc->nTerm-1]; + pLevel->op = OP_Return; + pLevel->p1 = regReturn; - /* Set up a SrcList containing just the table being scanned by this loop. */ - oneTab.nSrc = 1; - oneTab.nAlloc = 1; - oneTab.a[0] = *pTabItem; + /* Set up a new SrcList ni pOrTab containing the table being scanned + ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. + ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). + */ + if( pWInfo->nLevel>1 ){ + int nNotReady; /* The number of notReady tables */ + struct SrcList_item *origSrc; /* Original list of tables */ + nNotReady = pWInfo->nLevel - iLevel - 1; + pOrTab = sqlite3StackAllocRaw(pParse->db, + sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); + if( pOrTab==0 ) return notReady; + pOrTab->nSrc = pOrTab->nAlloc = nNotReady + 1; + memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); + origSrc = pWInfo->pTabList->a; + for(k=1; k<=nNotReady; k++){ + memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); + } + }else{ + pOrTab = pWInfo->pTabList; + } /* Initialize the rowset register to contain NULL. An SQL NULL is ** equivalent to an empty rowset. @@ -3309,8 +3328,9 @@ static Bitmask codeOneLoopStart( if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ /* Loop through table entries that match term pOrTerm. */ - pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0, - WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE); + pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, + WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | + WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); if( pSubWInfo ){ if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); @@ -3322,19 +3342,24 @@ static Bitmask codeOneLoopStart( } sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); + /* The pSubWInfo->untestedTerms flag means that this OR term + ** contained one or more AND term from a notReady table. The + ** terms from the notReady table could not be tested and will + ** need to be tested later. + */ + if( pSubWInfo->untestedTerms ) untestedTerms = 1; + /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); } } } sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); - /* sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); */ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); - pLevel->op = OP_Return; - pLevel->p1 = regReturn; - disableTerm(pLevel, pTerm); + if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab); + if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ @@ -3362,7 +3387,12 @@ static Bitmask codeOneLoopStart( testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & notReady)!=0 ) continue; + if( (pTerm->prereqAll & notReady)!=0 ){ + testcase( pWInfo->untestedTerms==0 + && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); + pWInfo->untestedTerms = 1; + continue; + } pE = pTerm->pExpr; assert( pE!=0 ); if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ @@ -3385,7 +3415,10 @@ static Bitmask codeOneLoopStart( testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & notReady)!=0 ) continue; + if( (pTerm->prereqAll & notReady)!=0 ){ + assert( pWInfo->untestedTerms ); + continue; + } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; @@ -3528,6 +3561,7 @@ WhereInfo *sqlite3WhereBegin( ){ int i; /* Loop counter */ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ + int nTabList; /* Number of elements in pTabList */ WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Bitmask notReady; /* Cursors that are not yet positioned */ @@ -3547,6 +3581,13 @@ WhereInfo *sqlite3WhereBegin( return 0; } + /* This function normally generates a nested loop for all tables in + ** pTabList. But if the WHERE_ONETABLE_ONLY flag is set, then we should + ** only generate code for the first table in pTabList and assume that + ** any cursors associated with subsequent tables are uninitialized. + */ + nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc; + /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure @@ -3555,7 +3596,7 @@ WhereInfo *sqlite3WhereBegin( ** some architectures. Hence the ROUND8() below. */ db = pParse->db; - nByteWInfo = ROUND8(sizeof(WhereInfo)+(pTabList->nSrc-1)*sizeof(WhereLevel)); + nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereClause) + @@ -3564,7 +3605,7 @@ WhereInfo *sqlite3WhereBegin( if( db->mallocFailed ){ goto whereBeginError; } - pWInfo->nLevel = pTabList->nSrc; + pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); @@ -3583,7 +3624,7 @@ WhereInfo *sqlite3WhereBegin( /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ - if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){ + if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){ sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL); pWhere = 0; } @@ -3603,6 +3644,11 @@ WhereInfo *sqlite3WhereBegin( ** to virtual table cursors are set. This is used to selectively disable ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful ** with virtual tables. + ** + ** Note that bitmasks are created for all pTabList->nSrc tables in + ** pTabList, not just the first nTabList tables. nTabList is normally + ** equal to pTabList->nSrc but might be shortened to 1 if the + ** WHERE_ONETABLE_ONLY flag is set. */ assert( pWC->vmask==0 && pMaskSet->n==0 ); for(i=0; inSrc; i++){ @@ -3654,7 +3700,7 @@ WhereInfo *sqlite3WhereBegin( pLevel = pWInfo->a; andFlags = ~0; WHERETRACE(("*** Optimizer Start ***\n")); - for(i=iFrom=0, pLevel=pWInfo->a; inSrc; i++, pLevel++){ + for(i=iFrom=0, pLevel=pWInfo->a; i=0 && bestJ<0; isOptimal--){ Bitmask mask = (isOptimal ? 0 : notReady); - assert( (pTabList->nSrc-iFrom)>1 || isOptimal ); - for(j=iFrom, pTabItem=&pTabList->a[j]; jnSrc; j++, pTabItem++){ + assert( (nTabList-iFrom)>1 || isOptimal ); + for(j=iFrom, pTabItem=&pTabList->a[j]; ja; inSrc; i++, pLevel++){ + for(i=0, pLevel=pWInfo->a; inSrc; i++){ + for(i=0; iiContinue = pWInfo->a[i].addrCont; } @@ -3888,7 +3934,7 @@ WhereInfo *sqlite3WhereBegin( ** the index is listed as "{}". If the primary key is used the ** index name is '*'. */ - for(i=0; inSrc; i++){ + for(i=0; ia[i]; @@ -3956,7 +4002,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Generate loop termination code. */ sqlite3ExprCacheClear(pParse); - for(i=pTabList->nSrc-1; i>=0; i--){ + for(i=pWInfo->nLevel-1; i>=0; i--){ pLevel = &pWInfo->a[i]; sqlite3VdbeResolveLabel(v, pLevel->addrCont); if( pLevel->op!=OP_Noop ){ @@ -4002,7 +4048,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Close all of the cursors that were opened by sqlite3WhereBegin. */ - for(i=0, pLevel=pWInfo->a; inSrc; i++, pLevel++){ + assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc ); + for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); diff --git a/test/tkt-31338dca7e.test b/test/tkt-31338dca7e.test new file mode 100644 index 0000000000..3f66816d64 --- /dev/null +++ b/test/tkt-31338dca7e.test @@ -0,0 +1,77 @@ +# 2009 December 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests to verify that ticket [31338dca7e] has been +# fixed. Ticket [31338dca7e] demonstrates problems with the OR-clause +# optimization in joins where the WHERE clause is of the form +# +# (x AND y) OR z +# +# And the x and y subterms from from different tables of the join. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_test tkt-31338-1.1 { + db eval { + CREATE TABLE t1(x); + CREATE TABLE t2(y); + INSERT INTO t1 VALUES(111); + INSERT INTO t1 VALUES(222); + INSERT INTO t2 VALUES(333); + INSERT INTO t2 VALUES(444); + SELECT * FROM t1, t2 + WHERE (x=111 AND y!=444) OR x=222 + ORDER BY x, y; + } +} {111 333 222 333 222 444} + +do_test tkt-31338-1.2 { + db eval { + CREATE INDEX t1x ON t1(x); + SELECT * FROM t1, t2 + WHERE (x=111 AND y!=444) OR x=222 + ORDER BY x, y; + } +} {111 333 222 333 222 444} + +do_test tkt-31338-2.1 { + db eval { + CREATE TABLE t3(v,w); + CREATE TABLE t4(x,y); + CREATE TABLE t5(z); + INSERT INTO t3 VALUES(111,222); + INSERT INTO t3 VALUES(333,444); + INSERT INTO t4 VALUES(222,333); + INSERT INTO t4 VALUES(444,555); + INSERT INTO t5 VALUES(888); + INSERT INTO t5 VALUES(999); + + SELECT * FROM t3, t4, t5 + WHERE (v=111 AND x=w AND z!=999) OR (v=333 AND x=444) + ORDER BY v, w, x, y, z; + } +} {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999} + +do_test tkt-31338-2.2 { + db eval { + CREATE INDEX t3v ON t3(v); + CREATE INDEX t4x ON t4(x); + SELECT * FROM t3, t4, t5 + WHERE (v=111 AND x=w AND z!=999) OR (v=333 AND x=444) + ORDER BY v, w, x, y, z; + } +} {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999} + + +finish_test diff --git a/test/where8.test b/test/where8.test index 04146fe60a..04657c0473 100644 --- a/test/where8.test +++ b/test/where8.test @@ -398,6 +398,10 @@ do_test where8-4.1 { INSERT INTO t4 VALUES('his', 'of', 378678316.5); INSERT INTO t4 VALUES(271.2019091, 'viewed', 3282306647); INSERT INTO t4 VALUES('hills', 'all', 'peak'); + CREATE TABLE t5(s); + INSERT INTO t5 VALUES('tab-t5'); + CREATE TABLE t6(t); + INSERT INTO t6 VALUES(123456); COMMIT; } } {} @@ -639,6 +643,14 @@ foreach idxsql { 197 { SELECT * FROM t3, t4 WHERE g = 2643383279 AND f = g } 198 { SELECT * FROM t3, t4 WHERE g < 8979323846 } 199 { SELECT * FROM t3, t4 WHERE 'are' <= b } +200 { SELECT * FROM t3, t4 WHERE (a=1415926535 AND f=8628034825) + OR (a=6939937510 AND f=2643383279) } +201 { SELECT * FROM t3, t4, t5, t6 + WHERE (a=1415926535 AND f=8628034825 AND s!='hello' AND t!=5) + OR (a=6939937510 AND f=2643383279 AND s='tab-t5' AND t=123456) } +202 { SELECT * FROM t3, t4, t5, t6 + WHERE (a=1415926535 AND f=8628034825 AND s!='hello' AND t==5) + OR (a=6939937510 AND f=2643383279 AND s='tab-t5' AND t!=123456) } } { do_test where8-4.$A.$B.1 {