1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Fix the cursor hint mechanism so that it does the right thing for indexed

lookups.

FossilOrigin-Name: 581e3d4988e98975fea5daaeb9f854c54a4976b7
This commit is contained in:
drh
2015-08-14 18:50:04 +00:00
parent 0df57012da
commit 2f2b02785a
6 changed files with 91 additions and 34 deletions

View File

@@ -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

View File

@@ -1 +1 @@
fc3fb5cd0d2c123a069e5b18b62bb1f708c8698a
581e3d4988e98975fea5daaeb9f854c54a4976b7

View 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;
};

View 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{

View 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);

View File

@@ -588,21 +588,58 @@ 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 ){
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(
@@ -610,6 +647,11 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
);
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);