From: drh Date: Sat, 25 Aug 2012 00:49:08 +0000 (+0000) Subject: Backport check-in [62678be3df35cd]: X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fbranch-3.7.2;p=thirdparty%2Fsqlite.git Backport check-in [62678be3df35cd]: When the same index is used for all OR-terms in a WHERE clause, then try to use that index as a covering index. FossilOrigin-Name: 865dfcbaa59431422b5980c66c8e29e80c4ed7c9 --- diff --git a/manifest b/manifest index 187eec8f31..545be12c58 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Cherrypick\sthe\s[3513bf6ee090d9]\sso\sthat\sthe\ssqlite_source_id()\sfunction\sworks\scorrectly\seven\swith\snewer\sversions\sof\sFossil -D 2011-10-25T21:18:17.179 +C Backport\scheck-in\s[62678be3df35cd]:\nWhen\sthe\ssame\sindex\sis\sused\sfor\sall\sOR-terms\sin\sa\sWHERE\sclause,\sthen\stry\sto\nuse\sthat\sindex\sas\sa\scovering\sindex. +D 2012-08-25T00:49:08.886 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -121,10 +121,10 @@ F src/callback.c da3c38d0ef5d7f04fae371e519bda61aa9cb1704 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 2e39d3374e785a63117e077bcba9d4a6656df363 F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20 -F src/delete.c daff6cef77fe8ed57b8acfc5ecebce28244af2fa +F src/delete.c e179bd660c559c630813b01d04db663de56a124d F src/expr.c 9c8147b9c2ffcd792191bad51028bf11719bac09 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c ca7cdb310a5095ce2b304c6524260595f73827dc +F src/fkey.c b792889ef26dd4531e77de35821547c9d2b72ca1 F src/func.c 464b0dc70618b896c402c574eb04bc5eacf35341 F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af @@ -168,11 +168,11 @@ F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 -F src/select.c a9828845d04c1f583b9fb5260c0cab33da88d16e +F src/select.c 6a7353def8f6e5d800198214bf5477e8d0524e36 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056 F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 -F src/sqliteInt.h e679eece2fb35bb324a56d614d91ccf961f70cf4 +F src/sqliteInt.h da99fe107f8f51d0b624428b773122cfccb49e2a F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -214,7 +214,7 @@ F src/test_vfs.c 367e050ebedac89f741dbfdcade3d584a8061dc9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852 -F src/update.c c6be6a5af1198aeac9b25d842d97e52695ffc9e6 +F src/update.c e85ead70c972dcb0655ee2ce91422b1d50bcb7b0 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f @@ -230,7 +230,7 @@ F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4 F src/wal.c 5ac2119e23ee4424599d4275b66dc88d612a0543 F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c db40458b67dbd77c658178ec6c53432807759c3f +F src/where.c a4b2ea85eeca3350354570c3b06eee2ce00f8075 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce @@ -424,7 +424,7 @@ F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3malloc.test 059592c4f37ccd30138bbf8e3e5b7982cb5c8f2e F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844 -F test/fts3query.test 2468caf7938dbc3be2e049524320ce4faf2227b3 +F test/fts3query.test 682cf2855eebdc295f69ae1573b46f388dfac280 F test/fts3rnd.test 707533ce943f490443ce5e696236bb1675a37635 F test/fts3snippet.test 9f9a4a7e396c5d8ce2898be65ebabc429555430f F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f @@ -818,6 +818,7 @@ F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739 F test/where9.test 24f19ad14bb1b831564ced5273e681e495662848 F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 +F test/whereD.test 6b6270480480a30038029dd6cbceef54d009dbc6 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b @@ -852,7 +853,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 14bc58ca70336aed62069f223324304835991c55 -R af5db398d4569192dd77a70de5aadb2c +P 89d63a0e1db6a86fa173fb8a4e3a3904ef9e488c +R 1c2de8c77bbe509e9e60c8893c5a6225 U drh -Z e43e421cba9e7717a13b85e140461f3f +Z d3dad17d9f134d722fd6b0b2a2f50b29 diff --git a/manifest.uuid b/manifest.uuid index 8bc4863887..e5a58c23d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -89d63a0e1db6a86fa173fb8a4e3a3904ef9e488c \ No newline at end of file +865dfcbaa59431422b5980c66c8e29e80c4ed7c9 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index ca516fbf11..13436ea181 100644 --- a/src/delete.c +++ b/src/delete.c @@ -363,7 +363,7 @@ void sqlite3DeleteFrom( */ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); pWInfo = sqlite3WhereBegin( - pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK + pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0 ); if( pWInfo==0 ) goto delete_from_cleanup; regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid); diff --git a/src/fkey.c b/src/fkey.c index 2e03545d40..37e12cf15c 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -548,7 +548,7 @@ static void fkScanChildren( ** clause. If the constraint is not deferred, throw an exception for ** each row found. Otherwise, for deferred constraints, increment the ** deferred constraint counter by nIncr for each row selected. */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3ParseToplevel(pParse)->mayAbort = 1; } diff --git a/src/select.c b/src/select.c index dd812a709c..a9fad2a5da 100644 --- a/src/select.c +++ b/src/select.c @@ -3837,7 +3837,7 @@ int sqlite3Select( ExprList *pDist = (isDistinct ? p->pEList : 0); /* Begin the database scan. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0); if( pWInfo==0 ) goto select_end; if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut; @@ -4004,7 +4004,7 @@ int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0); if( pWInfo==0 ) goto select_end; if( pGroupBy==0 ){ /* The optimizer is able to deliver rows in group by order so @@ -4263,7 +4263,7 @@ int sqlite3Select( ** of output. */ resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, 0, flag); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDel); goto select_end; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4de16fc712..2d97bfb904 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1877,6 +1877,7 @@ struct WhereLevel { int addrInTop; /* Top of the IN loop */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ + Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; /* The following field is really not part of the current level. But @@ -2678,7 +2679,8 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16); +WhereInfo *sqlite3WhereBegin( + Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); diff --git a/src/update.c b/src/update.c index a2fd7b9c0c..665f3fff56 100644 --- a/src/update.c +++ b/src/update.c @@ -313,7 +313,7 @@ void sqlite3Update( */ sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); pWInfo = sqlite3WhereBegin( - pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED + pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, 0 ); if( pWInfo==0 ) goto update_cleanup; okOnePass = pWInfo->okOnePass; diff --git a/src/where.c b/src/where.c index 00c25a5a1d..4f48605ef8 100644 --- a/src/where.c +++ b/src/where.c @@ -3568,7 +3568,7 @@ static int codeAllEqualityTerms( int r1; int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); - if( NEVER(pTerm==0) ) break; + if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); @@ -4242,6 +4242,8 @@ static Bitmask codeOneLoopStart( WhereClause *pOrWc; /* The OR-clause broken out into subterms */ WhereTerm *pFinal; /* Final subterm within the OR-clause. */ SrcList *pOrTab; /* Shortened table list or OR-clause generation */ + Index *pCov = 0; /* Potential covering index (or NULL) */ + int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ @@ -4260,7 +4262,7 @@ static Bitmask codeOneLoopStart( pLevel->op = OP_Return; pLevel->p1 = regReturn; - /* Set up a new SrcList ni pOrTab containing the table being scanned + /* Set up a new SrcList in 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(). */ @@ -4307,8 +4309,10 @@ static Bitmask codeOneLoopStart( /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, 0, WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); + WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); + assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed ); if( pSubWInfo ){ + WhereLevel *pLvl; explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); @@ -4329,11 +4333,36 @@ static Bitmask codeOneLoopStart( */ if( pSubWInfo->untestedTerms ) untestedTerms = 1; + /* If all of the OR-connected terms are optimized using the same + ** index, and the index is opened using the same cursor number + ** by each call to sqlite3WhereBegin() made by this loop, it may + ** be possible to use that index as a covering index. + ** + ** If the call to sqlite3WhereBegin() above resulted in a scan that + ** uses an index, and this is either the first OR-connected term + ** processed or the index is the same as that used by all previous + ** terms, set pCov to the candidate covering index. Otherwise, set + ** pCov to NULL to indicate that no candidate covering index will + ** be available. + */ + pLvl = &pSubWInfo->a[0]; + if( (pLvl->plan.wsFlags & WHERE_INDEXED)!=0 + && (pLvl->plan.wsFlags & WHERE_TEMP_INDEX)==0 + && (ii==0 || pLvl->plan.u.pIdx==pCov) + ){ + assert( pLvl->iIdxCur==iCovCur ); + pCov = pLvl->plan.u.pIdx; + }else{ + pCov = 0; + } + /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); } } } + pLevel->u.pCovidx = pCov; + pLevel->iIdxCur = iCovCur; sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); @@ -4549,7 +4578,8 @@ WhereInfo *sqlite3WhereBegin( Expr *pWhere, /* The WHERE clause */ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */ - u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */ + u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ + int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ ){ int i; /* Loop counter */ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ @@ -4866,7 +4896,13 @@ WhereInfo *sqlite3WhereBegin( testcase( bestPlan.plan.wsFlags & WHERE_INDEXED ); testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX ); if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){ - pLevel->iIdxCur = pParse->nTab++; + if( (wctrlFlags & WHERE_ONETABLE_ONLY) + && (bestPlan.plan.wsFlags & WHERE_TEMP_INDEX)==0 + ){ + pLevel->iIdxCur = iIdxCur; + }else{ + pLevel->iIdxCur = pParse->nTab++; + } }else{ pLevel->iIdxCur = -1; } @@ -5118,6 +5154,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ */ assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ + Index *pIdx = 0; struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); @@ -5147,12 +5184,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** that reference the table and converts them into opcodes that ** reference the index. */ - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 && !db->mallocFailed){ + if( pLevel->plan.wsFlags & WHERE_INDEXED ){ + pIdx = pLevel->plan.u.pIdx; + }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){ + pIdx = pLevel->u.pCovidx; + } + if( pIdx && !db->mallocFailed){ int k, j, last; VdbeOp *pOp; - Index *pIdx = pLevel->plan.u.pIdx; - assert( pIdx!=0 ); pOp = sqlite3VdbeGetOp(v, pWInfo->iTop); last = sqlite3VdbeCurrentAddr(v); for(k=pWInfo->iTop; k