From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id AD40624256 for ; Sat, 9 Jun 2018 09:09:54 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 85QpmmW10Dmo for ; Sat, 9 Jun 2018 09:09:54 -0400 (EDT) Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id CFEB7240B8 for ; Sat, 9 Jun 2018 09:09:53 -0400 (EDT) From: Kirill Shcherbatov Subject: [tarantool-patches] [PATCH v1 1/1] sql: drop useless legacy Cursor hints Date: Sat, 9 Jun 2018 16:09:49 +0300 Message-Id: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Kirill Shcherbatov Deleted BTREE_BULKLOAD and OPFLAG_BULKCSR as there become useless since btree.c was dropped as a part of #2419. Removed SQLITE_ENABLE_CURSOR_HINTS sections as this code has never been in use. Start use OPFLAG_SEEKEQ instead of equal BTREE_SEEK_EQ as this macro name has no sense since no btree present in SQL. Resolves #3121. --- src/box/sql.c | 4 +- src/box/sql/build.c | 4 +- src/box/sql/cursor.c | 2 +- src/box/sql/cursor.h | 16 ---- src/box/sql/expr.c | 18 ---- src/box/sql/insert.c | 1 - src/box/sql/sqliteInt.h | 6 -- src/box/sql/vdbe.c | 19 ++-- src/box/sql/vdbe.h | 3 - src/box/sql/vdbeaux.c | 133 --------------------------- src/box/sql/where.c | 6 -- src/box/sql/wherecode.c | 234 ------------------------------------------------ 12 files changed, 11 insertions(+), 435 deletions(-) diff --git a/src/box/sql.c b/src/box/sql.c index 7379cb4..e644056 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -292,12 +292,12 @@ int tarantoolSqlite3MovetoUnpacked(BtCursor *pCur, UnpackedRecord *pIdxKey, res_success = -1; /* itemiter_type = (pCur->hints & BTREE_SEEK_EQ) ? + pCur->iter_type = (pCur->hints & OPFLAG_SEEKEQ) ? ITER_REQ : ITER_LE; res_success = 0; /* item==key */ break; case OP_SeekGE: - pCur->iter_type = (pCur->hints & BTREE_SEEK_EQ) ? + pCur->iter_type = (pCur->hints & OPFLAG_SEEKEQ) ? ITER_EQ : ITER_GE; res_success = 0; /* item==key */ break; diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 28e4d7a..93bf0cc 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -2676,9 +2676,7 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage) sqlite3VdbeAddOp2(v, OP_Clear, SQLITE_PAGENO_TO_SPACEID(tnum), 0); emit_open_cursor(pParse, iIdx, tnum); - sqlite3VdbeChangeP5(v, - OPFLAG_BULKCSR | ((memRootPage >= 0) ? - OPFLAG_P2ISREG : 0)); + sqlite3VdbeChangeP5(v, memRootPage >= 0 ? OPFLAG_P2ISREG : 0); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); diff --git a/src/box/sql/cursor.c b/src/box/sql/cursor.c index 82ad08b..9dd2b02 100644 --- a/src/box/sql/cursor.c +++ b/src/box/sql/cursor.c @@ -53,7 +53,7 @@ sql_cursor_cleanup(struct BtCursor *cursor) void sqlite3CursorHintFlags(BtCursor * pCur, unsigned x) { - assert(x == BTREE_SEEK_EQ || x == BTREE_BULKLOAD || x == 0); + assert(x == OPFLAG_SEEKEQ || x == 0); pCur->hints = x; } diff --git a/src/box/sql/cursor.h b/src/box/sql/cursor.h index c559417..252aaac 100644 --- a/src/box/sql/cursor.h +++ b/src/box/sql/cursor.h @@ -35,22 +35,6 @@ typedef struct BtCursor BtCursor; /* - * Values that may be OR'd together to form the argument to the - * BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint(): - * - * The BTREE_BULKLOAD flag is set on index cursors when the index is going - * to be filled with content that is already in sorted order. - * - * The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or - * OP_SeekLE opcodes for a range search, but where the range of entries - * selected will all have the same key. In other words, the cursor will - * be used only for equality key searches. - * - */ -#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */ -#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */ - -/* * A cursor contains a particular entry either from Tarantrool or * Sorter. Tarantool cursor is able to point to ordinary table or * ephemeral one. To distinguish them curFlags is set to TaCursor diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 8866f6f..371d5d5 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -2000,24 +2000,6 @@ sqlite3ExprIsConstantOrFunction(Expr * p, u8 isInit) return exprIsConst(p, 4 + isInit, 0); } -#ifdef SQLITE_ENABLE_CURSOR_HINTS -/* - * Walk an expression tree. Return 1 if the expression contains a - * subquery of some kind. Return 0 if there are no subqueries. - */ -int -sqlite3ExprContainsSubquery(Expr * p) -{ - Walker w; - memset(&w, 0, sizeof(w)); - w.eCode = 1; - w.xExprCallback = sqlite3ExprWalkNoop; - w.xSelectCallback = selectNodeIsConstant; - sqlite3WalkExpr(&w, p); - return w.eCode == 0; -} -#endif - /* * If the expression p codes a constant integer that is small enough * to fit in a 32-bit integer, return 1 and put the value of the integer diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 59c61c7..a3a5b45 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -1963,7 +1963,6 @@ xferOptimization(Parse * pParse, /* Parser context */ VdbeComment((v, "%s", pSrcIdx->zName)); emit_open_cursor(pParse, iDest, pDestIdx->tnum); sql_vdbe_set_p4_key_def(pParse, pDestIdx); - sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 01351a1..c95b1f0 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -2978,8 +2978,6 @@ struct Parse { * Value constraints (enforced via assert()): * OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH * OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF - * OPFLAG_BULKCSR == BTREE_BULKLOAD - * OPFLAG_SEEKEQ == BTREE_SEEK_EQ * OPFLAG_FORDELETE == BTREE_FORDELETE * OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION * OPFLAG_AUXDELETE == BTREE_AUXDELETE @@ -2995,7 +2993,6 @@ struct Parse { #endif #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ -#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ #define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ #define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ @@ -3834,9 +3831,6 @@ int sqlite3ExprIsConstant(Expr *); int sqlite3ExprIsConstantNotJoin(Expr *); int sqlite3ExprIsConstantOrFunction(Expr *, u8); int sqlite3ExprIsTableConstant(Expr *, int); -#ifdef SQLITE_ENABLE_CURSOR_HINTS -int sqlite3ExprContainsSubquery(Expr *); -#endif int sqlite3ExprIsInteger(Expr *, int *); int sqlite3ExprCanBeNull(const Expr *); int sqlite3ExprNeedsNoAffinityChange(const Expr *, char); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 3fe5875..3139933 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -3206,14 +3206,7 @@ case OP_OpenWrite: pCur->key_def = index->def->key_def; open_cursor_set_hints: - assert(OPFLAG_BULKCSR==BTREE_BULKLOAD); - assert(OPFLAG_SEEKEQ==BTREE_SEEK_EQ); - testcase( pOp->p5 & OPFLAG_BULKCSR); -#ifdef SQLITE_ENABLE_CURSOR_HINTS - testcase( pOp->p2 & OPFLAG_SEEKEQ); -#endif - sqlite3CursorHintFlags(pCur->uc.pCursor, - (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); + sqlite3CursorHintFlags(pCur->uc.pCursor, pOp->p5 & OPFLAG_SEEKEQ); if (rc) goto abort_due_to_error; break; } @@ -3527,11 +3520,13 @@ case OP_SeekGT: { /* jump, in3 */ } } } - /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and - * OP_SeekLE opcodes are allowed, and these must be immediately followed - * by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key. + /* + * For a cursor with the OPFLAG_SEEKEQ hint, only the + * OP_SeekGE and OP_SeekLE opcodes are allowed, and these + * must be immediately followed by an OP_IdxGT or + * OP_IdxLT opcode, respectively, with the same key. */ - if (sqlite3CursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)) { + if (sqlite3CursorHasHint(pC->uc.pCursor, OPFLAG_SEEKEQ) != 0) { eqOnly = 1; assert(pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE); assert(pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT); diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h index 68d542c..4dcc457 100644 --- a/src/box/sql/vdbe.h +++ b/src/box/sql/vdbe.h @@ -80,9 +80,6 @@ struct VdbeOp { int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Index *pIndex; /* Used when p4type is P4_INDEX */ -#ifdef SQLITE_ENABLE_CURSOR_HINTS - Expr *pExpr; /* Used when p4type is P4_EXPR */ -#endif int (*xAdvance) (BtCursor *, int *); /** Used when p4type is P4_KEYDEF. */ struct key_def *key_def; diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 679bd0b..a29d0a3 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -972,12 +972,6 @@ freeP4(sqlite3 * db, int p4type, void *p4) case P4_KEYDEF: key_def_delete(p4); break; -#ifdef SQLITE_ENABLE_CURSOR_HINTS - case P4_EXPR:{ - sqlite3ExprDelete(db, (Expr *) p4); - break; - } -#endif case P4_FUNCDEF:{ freeEphemeralFunction(db, (FuncDef *) p4); break; @@ -1389,127 +1383,6 @@ displayComment(const Op * pOp, /* The opcode to be commented */ } #endif /* SQLITE_DEBUG */ -#if defined(SQLITE_ENABLE_CURSOR_HINTS) -/* - * Translate the P4.pExpr value for an OP_CursorHint opcode into text - * that can be displayed in the P4 column of EXPLAIN output. - */ -static void -displayP4Expr(StrAccum * p, Expr * pExpr) -{ - const char *zOp = 0; - switch (pExpr->op) { - case TK_STRING: - sqlite3XPrintf(p, "%Q", pExpr->u.zToken); - break; - case TK_INTEGER: - sqlite3XPrintf(p, "%d", pExpr->u.iValue); - break; - case TK_NULL: - sqlite3XPrintf(p, "NULL"); - break; - case TK_REGISTER:{ - sqlite3XPrintf(p, "r[%d]", pExpr->iTable); - break; - } - case TK_COLUMN:{ - if (pExpr->iColumn < 0) { - sqlite3XPrintf(p, "rowid"); - } else { - sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn); - } - break; - } - case TK_LT: - zOp = "LT"; - break; - case TK_LE: - zOp = "LE"; - break; - case TK_GT: - zOp = "GT"; - break; - case TK_GE: - zOp = "GE"; - break; - case TK_NE: - zOp = "NE"; - break; - case TK_EQ: - zOp = "EQ"; - break; - case TK_AND: - zOp = "AND"; - break; - case TK_OR: - zOp = "OR"; - break; - case TK_PLUS: - zOp = "ADD"; - break; - case TK_STAR: - zOp = "MUL"; - break; - case TK_MINUS: - zOp = "SUB"; - break; - case TK_REM: - zOp = "REM"; - break; - case TK_BITAND: - zOp = "BITAND"; - break; - case TK_BITOR: - zOp = "BITOR"; - break; - case TK_SLASH: - zOp = "DIV"; - break; - case TK_LSHIFT: - zOp = "LSHIFT"; - break; - case TK_RSHIFT: - zOp = "RSHIFT"; - break; - case TK_CONCAT: - zOp = "CONCAT"; - break; - case TK_UMINUS: - zOp = "MINUS"; - break; - case TK_UPLUS: - zOp = "PLUS"; - break; - case TK_BITNOT: - zOp = "BITNOT"; - break; - case TK_NOT: - zOp = "NOT"; - break; - case TK_ISNULL: - zOp = "IS NULL"; - break; - case TK_NOTNULL: - zOp = "NOT NULL"; - break; - - default: - sqlite3XPrintf(p, "%s", "expr"); - break; - } - - if (zOp) { - sqlite3XPrintf(p, "%s(", zOp); - displayP4Expr(p, pExpr->pLeft); - if (pExpr->pRight) { - sqlite3StrAccumAppend(p, ",", 1); - displayP4Expr(p, pExpr->pRight); - } - sqlite3StrAccumAppend(p, ")", 1); - } -} -#endif /* defined(SQLITE_ENABLE_CURSOR_HINTS) */ - /* * Compute a string that describes the P4 parameter for an opcode. * Use zTemp for any required temporary buffer space. @@ -1549,12 +1422,6 @@ displayP4(Op * pOp, char *zTemp, int nTemp) } break; } -#ifdef SQLITE_ENABLE_CURSOR_HINTS - case P4_EXPR:{ - displayP4Expr(&x, pOp->p4.pExpr); - break; - } -#endif case P4_COLLSEQ:{ struct coll *pColl = pOp->p4.pColl; if (pColl != NULL) diff --git a/src/box/sql/where.c b/src/box/sql/where.c index e791647..1ca366c 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -4588,12 +4588,6 @@ sqlite3WhereBegin(Parse * pParse, /* The parser context */ && pTab->nCol == BMS - 1); testcase(pWInfo->eOnePass == ONEPASS_OFF && pTab->nCol == BMS); -#ifdef SQLITE_ENABLE_CURSOR_HINTS - if (pLoop->pIndex != 0) { - sqlite3VdbeChangeP5(v, - OPFLAG_SEEKEQ | bFordelete); - } else -#endif { sqlite3VdbeChangeP5(v, bFordelete); } diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index 09b2671..26eca21 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -817,241 +817,7 @@ whereLikeOptimizationStringFixup(Vdbe * v, /* prepared statement under construc #define whereLikeOptimizationStringFixup(A,B,C) #endif -#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 - && (pExpr->iColumn < 0)) { - pWalker->eCode = 1; - } - return WRC_Continue; -} - -/* - * Test whether or not expression pExpr, which was part of a WHERE clause, - * should be included in the cursor-hint for a table that is on the rhs - * of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the - * expression is not suitable. - * - * An expression is unsuitable if it might evaluate to non NULL even if - * a TK_COLUMN node that does affect the value of the expression is set - * to NULL. For example: - * - * col IS NULL - * col IS NOT NULL - * coalesce(col, 1) - * CASE WHEN col THEN 0 ELSE 1 END - */ -static int -codeCursorHintIsOrFunction(Walker * pWalker, Expr * pExpr) -{ - if (pExpr->op == TK_ISNULL - || pExpr->op == TK_NOTNULL || pExpr->op == TK_CASE) { - pWalker->eCode = 1; - } else if (pExpr->op == TK_FUNCTION) { - int d1; - char d2[3]; - if (0 == - sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, - d2)) { - 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 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; - 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->def, - pExpr->iTable, - pExpr->iColumn, reg); - pExpr->op = TK_REGISTER; - pExpr->iTable = reg; - } else if (pHint->pIdx != 0) { - pExpr->iTable = pHint->iIdxCur; - 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 - * the parent context. Do not walk the function arguments in this case. - * - * todo: It should be possible to replace this node with a TK_REGISTER - * expression, as the result of the expression must be stored in a - * register at this point. The same holds for TK_AGG_COLUMN nodes. - */ - rc = WRC_Prune; - } - return rc; -} - -/* - * Insert an OP_CursorHint instruction if it is appropriate to do so. - */ -static void -codeCursorHint(struct SrcList_item *pTabItem, /* FROM clause item */ - WhereInfo * pWInfo, /* The where clause */ - WhereLevel * pLevel, /* Which loop to provide hints for */ - WhereTerm * pEndRange) /* Hint this end-of-scan boundary term if not NULL */ -{ - Parse *pParse = pWInfo->pParse; - sqlite3 *db = pParse->db; - Vdbe *v = pParse->pVdbe; - Expr *pExpr = 0; - WhereLoop *pLoop = pLevel->pWLoop; - int iCur; - WhereClause *pWC; - WhereTerm *pTerm; - int i, j; - struct CCurHint sHint; - Walker sWalker; - - if (OptimizationDisabled(db, SQLITE_CursorHints)) - return; - iCur = pLevel->iTabCur; - assert(iCur == pWInfo->pTabList->a[pLevel->iFrom].iCursor); - sHint.iTabCur = iCur; - sHint.iIdxCur = pLevel->iIdxCur; - sHint.pIdx = pLoop->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]; - if (pTerm->wtFlags & (TERM_VIRTUAL | TERM_CODED)) - continue; - if (pTerm->prereqAll & pLevel->notReady) - continue; - - /* Any terms specified as part of the ON(...) clause for any LEFT - * JOIN for which the current table is not the rhs are omitted - * from the cursor-hint. - * - * If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms - * that were specified as part of the WHERE clause must be excluded. - * This is to address the following: - * - * SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; - * - * Say there is a single row in t2 that matches (t1.a=t2.b), but its - * t2.c values is not NULL. If the (t2.c IS NULL) constraint is - * pushed down to the cursor, this row is filtered out, causing - * SQLite to synthesize a row of NULL values. Which does match the - * WHERE clause, and so the query returns a row. Which is incorrect. - * - * For the same reason, WHERE terms such as: - * - * WHERE 1 = (t2.c IS NULL) - * - * are also excluded. See codeCursorHintIsOrFunction() for details. - */ - if (pTabItem->fg.jointype & JT_LEFT) { - Expr *pExpr = pTerm->pExpr; - if (!ExprHasProperty(pExpr, EP_FromJoin) - || pExpr->iRightJoinTable != pTabItem->iCursor) { - sWalker.eCode = 0; - sWalker.xExprCallback = - codeCursorHintIsOrFunction; - sqlite3WalkExpr(&sWalker, pTerm->pExpr); - if (sWalker.eCode) - continue; - } - } else { - if (ExprHasProperty(pTerm->pExpr, EP_FromJoin)) - continue; - } - - /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize - * the cursor. These terms are not needed as hints for a pure range - * scan (that has no == terms) so omit them. - */ - if (pLoop->nEq == 0 && pTerm != pEndRange) { - for (j = 0; - j < pLoop->nLTerm && pLoop->aLTerm[j] != pTerm; - j++) { - } - if (j < pLoop->nLTerm) - continue; - } - - /* No subqueries or non-deterministic functions allowed */ - if (sqlite3ExprContainsSubquery(pTerm->pExpr)) - continue; - - /* For an index scan, make sure referenced columns are actually in - * the index. - */ - if (sHint.pIdx != 0) { - sWalker.eCode = 0; - sWalker.xExprCallback = codeCursorHintCheckExpr; - sqlite3WalkExpr(&sWalker, pTerm->pExpr); - if (sWalker.eCode) - continue; - } - - /* If we survive all prior tests, that means this term is worth hinting */ - pExpr = - sqlite3ExprAnd(db, pExpr, - sqlite3ExprDup(db, pTerm->pExpr, 0)); - } - if (pExpr != 0) { - sWalker.xExprCallback = codeCursorHintFixExpr; - sqlite3WalkExpr(&sWalker, pExpr); - sqlite3VdbeAddOp4(v, OP_CursorHint, - (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), - 0, 0, (const char *)pExpr, P4_EXPR); - } -} -#else #define codeCursorHint(A,B,C,D) /* No-op */ -#endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* * If the expression passed as the second argument is a vector, generate -- 2.7.4