From: drh Date: Fri, 14 Aug 2015 18:50:04 +0000 (+0000) Subject: Fix the cursor hint mechanism so that it does the right thing for indexed X-Git-Tag: version-3.10.0~191^2~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f2b02785ad756015d111813971e3433c5d0399f;p=thirdparty%2Fsqlite.git Fix the cursor hint mechanism so that it does the right thing for indexed lookups. FossilOrigin-Name: 581e3d4988e98975fea5daaeb9f854c54a4976b7 --- diff --git a/manifest b/manifest index 4a1861f11c..a0e60280dd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\sthe\ssqlite3BtreeCursorHint()\sinterface\sfor\simproved\smaintainability. -D 2015-08-14T15:05:55.881 +C Fix\sthe\scursor\shint\smechanism\sso\sthat\sit\sdoes\sthe\sright\sthing\sfor\sindexed\nlookups. +D 2015-08-14T18:50:04.420 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -340,7 +340,7 @@ F src/shell.c b1f91e60918df3a68efad1e3a11696b9a7e23d23 F src/sqlite.h.in 447ead0a6b3293206f04a0896553955d07cfb4b9 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h a0b948ebc89bac13941254641326a6aa248c2cc4 -F src/sqliteInt.h ea5885ac6df1de2444846d0a79c6252e2fa444ab +F src/sqliteInt.h cbd6d166c5f8aa17e4be463ccefef41cd1d40286 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -403,7 +403,7 @@ F src/vdbe.c 74561c2d15895f930f08e4216d454efaaaf530c4 F src/vdbe.h 529bb4a7bedcd28dccba5abb3927e3c5cb70a832 F src/vdbeInt.h 7258d75fc2dad0bccdef14d7d8d2fd50fd1bf2d2 F src/vdbeapi.c adabbd66eb2e3a10f3998485ee0be7e326d06ee4 -F src/vdbeaux.c 8bb1ef79af006d02d218171af15b73b9005095d4 +F src/vdbeaux.c 9f726265d3c4a64264c9aa80d35aa19c51a3c6f4 F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090 F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b @@ -413,9 +413,9 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 6fb6b68969e4692593c2552c4e7bff5882de2cb8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c c745d3aa78ad1aa8982febb99f2f17ee5cbac069 +F src/where.c ef95e56b6e7cdfa3ae0b6f72e3578391addfa965 F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047 -F src/wherecode.c 3180ac6422b82e4d71fbaae8727f9dd036efd320 +F src/wherecode.c 16045545fb44878a7ba61db645521f30f9265893 F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1375,7 +1375,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f0d428d13a787251c2ca7685fec2a91b550eefba -R 3107bb0cdaaeeac152b5b9d7e7511034 +P fc3fb5cd0d2c123a069e5b18b62bb1f708c8698a +R 020be40332ddb39fbaad6fc302316e47 U drh -Z 84636ad24c17c3565bc4b3192fff4413 +Z 56068f8a083e66d3150e6ce38cb011fe diff --git a/manifest.uuid b/manifest.uuid index d53c4b5ca8..3a1ba3442d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fc3fb5cd0d2c123a069e5b18b62bb1f708c8698a \ No newline at end of file +581e3d4988e98975fea5daaeb9f854c54a4976b7 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f1658d12f2..41c193114d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2994,6 +2994,7 @@ struct Walker { int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ + struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ } u; }; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index bec307e1b7..df6ac61f82 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1593,12 +1593,12 @@ int sqlite3VdbeList( pMem->u.i = pOp->p3; /* P3 */ pMem++; - if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */ + if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */ assert( p->db->mallocFailed ); return SQLITE_ERROR; } pMem->flags = MEM_Str|MEM_Term; - zP4 = displayP4(pOp, pMem->z, 32); + zP4 = displayP4(pOp, pMem->z, pMem->szMalloc); if( zP4!=pMem->z ){ sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); }else{ diff --git a/src/where.c b/src/where.c index 3c0f767db6..359f1506d9 100644 --- a/src/where.c +++ b/src/where.c @@ -4217,6 +4217,9 @@ WhereInfo *sqlite3WhereBegin( SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } +#ifdef SQLITE_ENABLE_CURSOR_HINTS + if( pLoop->u.btree.pIndex!=0 ) sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); +#endif #ifdef SQLITE_ENABLE_COLUMN_USED_MASK sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0, (const u8*)&pTabItem->colUsed, P4_INT64); diff --git a/src/wherecode.c b/src/wherecode.c index 7b9db0cb2f..5052e2d378 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -588,28 +588,70 @@ static void whereLikeOptimizationStringFixup( } #ifdef SQLITE_ENABLE_CURSOR_HINTS +/* +** Information is passed from codeCursorHint() down to individual nodes of +** the expression tree (by sqlite3WalkExpr()) using an instance of this +** structure. +*/ +struct CCurHint { + int iTabCur; /* Cursor for the main table */ + int iIdxCur; /* Cursor for the index, if pIdx!=0. Unused otherwise */ + Index *pIdx; /* The index used to access the table */ +}; + +/* +** This function is called for every node of an expression that is a candidate +** for a cursor hint on an index cursor. For TK_COLUMN nodes that reference +** the table CCurHint.iTabCur, verify that the same column can be +** accessed through the index. If it cannot, then set pWalker->eCode to 1. +*/ +static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ + struct CCurHint *pHint = pWalker->u.pCCurHint; + assert( pHint->pIdx!=0 ); + if( pExpr->op==TK_COLUMN + && pExpr->iTable==pHint->iTabCur + && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 + ){ + pWalker->eCode = 1; + } + return WRC_Continue; +} + /* ** This function is called on every node of an expression tree used as an ** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN -** that accesses any cursor other than (pWalker->u.n), do the following: +** that accesses any table other than the one identified by +** CCurHint.iTabCur, then do the following: ** ** 1) allocate a register and code an OP_Column instruction to read ** the specified column into the new register, and ** ** 2) transform the expression node to a TK_REGISTER node that reads ** from the newly populated register. +** +** Also, if the node is a TK_COLUMN that does access the table idenified +** by pCCurHint.iTabCur, and an index is being used (which we will +** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into +** an access of the index rather than the original table. */ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ int rc = WRC_Continue; - if( pExpr->op==TK_COLUMN && pExpr->iTable!=pWalker->u.n ){ - Vdbe *v = pWalker->pParse->pVdbe; - int reg = ++pWalker->pParse->nMem; /* Register for column value */ - sqlite3ExprCodeGetColumnOfTable( - v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg - ); - pExpr->op = TK_REGISTER; - pExpr->iTable = reg; + struct CCurHint *pHint = pWalker->u.pCCurHint; + if( pExpr->op==TK_COLUMN ){ + if( pExpr->iTable!=pHint->iTabCur ){ + Vdbe *v = pWalker->pParse->pVdbe; + int reg = ++pWalker->pParse->nMem; /* Register for column value */ + sqlite3ExprCodeGetColumnOfTable( + v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg + ); + pExpr->op = TK_REGISTER; + pExpr->iTable = reg; + }else if( pHint->pIdx!=0 ){ + pExpr->iTable = pHint->iIdxCur; + pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); + assert( pExpr->iColumn>=0 ); + } }else if( pExpr->op==TK_AGG_FUNCTION ){ /* An aggregate function in the WHERE clause of a query means this must ** be a correlated sub-query, and expression pExpr is an aggregate from @@ -628,21 +670,29 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ */ static void codeCursorHint( WhereInfo *pWInfo, - int iLevel + WhereLevel *pLevel ){ Parse *pParse = pWInfo->pParse; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; - WhereLevel *pLevel; Expr *pExpr = 0; + WhereLoop *pLoop = pLevel->pWLoop; int iCur; WhereClause *pWC; WhereTerm *pTerm; int i; + struct CCurHint sHint; + Walker sWalker; if( OptimizationDisabled(db, SQLITE_CursorHints) ) return; - pLevel = &pWInfo->a[iLevel]; - iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; + iCur = pLevel->iTabCur; + assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor ); + sHint.iTabCur = iCur; + sHint.iIdxCur = pLevel->iIdxCur; + sHint.pIdx = pLoop->u.btree.pIndex; + memset(&sWalker, 0, sizeof(sWalker)); + sWalker.pParse = pParse; + sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; for(i=0; inTerm; i++){ pTerm = &pWC->a[i]; @@ -650,17 +700,20 @@ static void codeCursorHint( if( pTerm->prereqAll & pLevel->notReady ) continue; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue; + if( sHint.pIdx!=0 ){ + sWalker.eCode = 0; + sWalker.xExprCallback = codeCursorHintCheckExpr; + sqlite3WalkExpr(&sWalker, pTerm->pExpr); + if( sWalker.eCode ) continue; + } pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ - const char *a = (const char*)pExpr; - Walker sWalker; - memset(&sWalker, 0, sizeof(sWalker)); sWalker.xExprCallback = codeCursorHintFixExpr; - sWalker.pParse = pParse; - sWalker.u.n = pLevel->iTabCur; sqlite3WalkExpr(&sWalker, pExpr); - sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, a, P4_EXPR); + sqlite3VdbeAddOp4(v, OP_CursorHint, + (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, + (const char*)pExpr, P4_EXPR); } } #else @@ -830,7 +883,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( pStart = pEnd; pEnd = pTerm; } - codeCursorHint(pWInfo, iLevel); + codeCursorHint(pWInfo, pLevel); if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ @@ -1053,7 +1106,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( start_constraints = pRangeStart || nEq>0; /* Seek the index cursor to the start of the range. */ - codeCursorHint(pWInfo, iLevel); + codeCursorHint(pWInfo, pLevel); nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; @@ -1481,7 +1534,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ - codeCursorHint(pWInfo, iLevel); + codeCursorHint(pWInfo, pLevel); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);