[tarantool-patches] [PATCH v1 1/1] sql: drop useless legacy Cursor hints
Kirill Shcherbatov
kshcherbatov at tarantool.org
Sat Jun 9 16:09:49 MSK 2018
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; /* item<key */
break;
case OP_SeekLE:
- pCur->iter_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
More information about the Tarantool-patches
mailing list