]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the cursor hint mechanism so that it does the right thing for indexed
authordrh <drh@noemail.net>
Fri, 14 Aug 2015 18:50:04 +0000 (18:50 +0000)
committerdrh <drh@noemail.net>
Fri, 14 Aug 2015 18:50:04 +0000 (18:50 +0000)
lookups.

FossilOrigin-Name: 581e3d4988e98975fea5daaeb9f854c54a4976b7

manifest
manifest.uuid
src/sqliteInt.h
src/vdbeaux.c
src/where.c
src/wherecode.c

index 4a1861f11cd9f69f25d3781fd881f59fa9c50407..a0e60280dddb738f9f49ea9b086a12446ecdcd86 100644 (file)
--- 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
index d53c4b5ca81371e4a47b91f18a24fb8b1358a45e..3a1ba3442d7ce0324aeb4f08549d351009333116 100644 (file)
@@ -1 +1 @@
-fc3fb5cd0d2c123a069e5b18b62bb1f708c8698a
\ No newline at end of file
+581e3d4988e98975fea5daaeb9f854c54a4976b7
\ No newline at end of file
index f1658d12f2e4f73feff90dab7c2b9ecde72443ea..41c193114dc76621bf108be361ab7c2d9bb3cc15 100644 (file)
@@ -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;
 };
 
index bec307e1b7b276b76ab493dc34577c2d97dd58e6..df6ac61f82ebe9a94ffc16382d8e58dec03aba10 100644 (file)
@@ -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{
index 3c0f767db6c9929a27d88f9b3a55adb6b3c2f8d2..359f1506d9e4878578885ea7885fa5e227dd8727 100644 (file)
@@ -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);
index 7b9db0cb2fcde55546f3b7389965f7b54fc609dd..5052e2d378f13d10fd0a69f44daf73c25894fa64 100644 (file)
@@ -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; i<pWC->nTerm; 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);