-C Provide\sthe\s-DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1\scompile-time\soption.\s\sFix\nthe\s".testctrl\sinternal_function"\scommand\sin\sthe\sCLI\sso\sthat\sit\sdoes\snot\nsignal\san\serror\son\sa\svalid\sinput.
-D 2020-01-01T23:02:35.846
+C The\ssqlite3WhereEnd()\scall\snow\sunwinds\sall\sExpr\smodifications\smade\sby\sthe\nsqlite3WhereBegin().
+D 2020-01-02T00:45:38.107
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
F src/dbstat.c 6c407e549406c10fde9ac3987f6d734459205239ad370369bc5fcd683084a4fa
F src/delete.c a5c59b9c0251cf7682bc52af0d64f09b1aefc6781a63592c8f1136f7b73c66e4
-F src/expr.c 7f3a19d0d400d079bd5e40389c75634a1b6feeb91eadfff5919d5b7d73f0c418
+F src/expr.c e76660a57fa2bbe4103686dc8add1a8c5ca40ae139076956dc8c670f5af34e93
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 92a248ec0fa4ed8ab60c98d9b188ce173aaf218f32e7737ba77deb2a684f9847
F src/func.c 259496e4856bd0a3215d16804992f3339f3e8db29f129a5a7285c341488bbe9c
F src/wal.c 15a2845769f51ba132f9cf0b2c7a6887a91fc8437892dbcce9fcdc68b66d60a1
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c a137468bf36c92e64d2275caa80c83902e3a0fc59273591b96c6416d3253d05d
-F src/where.c 602e5093556bbd9090c0a9bd834fec0717e3a4b0377a021d38091a6d554a1177
-F src/whereInt.h a727b32260e12707a8c1bc29d7f7e9b6dc1a44551a45093d5968fbe570ff0c56
-F src/wherecode.c a987d22b42e09b06f3a49596e0953b1cd28e568cc656681776edc0026cfac0cc
+F src/where.c 9353093c2a444580857006fc959494edc40e2393ac08a1f7e1eefe455c079cdb
+F src/whereInt.h d2b771335083070ff82991cc43603e2db27b7ba1313da72de092c50c68f2be9c
+F src/wherecode.c b8acf97f95de7398455e238036e96aeda8563d87c6b8108c967396431b6f2307
F src/whereexpr.c 4b34be1434183e7bb8a05d4bf42bd53ea53021b0b060936fbd12062b4ff6b396
F src/window.c 659d613248f8bb8630f51409dc08235e4494c3c84162a535d9f88b38515f390a
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 4edddcc0bc8d71e9b8abac67bc3766f1d9143dddd1f59264859ce65e5aa9b8c6
-R 7719ca5b06b1882198898d45d0aa33b1
+P 8ee2ce92c082771675d0e8be597043cf9f0fd4f8a73d6a1498bf8743d6b3904a
+Q -4edddcc0bc8d71e9b8abac67bc3766f1d9143dddd1f59264859ce65e5aa9b8c6
+R 78a3f85d954b3a0eb1fce93a6a40c0b8
U drh
-Z a96bfaa62b0a101e6ed6e47d09a94ada
+Z 7a9eae0197a9672b5fa1c50dd4bf6963
-8ee2ce92c082771675d0e8be597043cf9f0fd4f8a73d6a1498bf8743d6b3904a
\ No newline at end of file
+7bfd42f1dc0c94f9bb74516e62fec8e39c20f4749f4e0972f66c2886d3c64f73
\ No newline at end of file
SelectDest dest; /* How to deal with SELECT result */
int nReg; /* Registers to allocate */
Expr *pLimit; /* New limit expression */
- Select *pCopy; /* Copy of pSel */
- int rc; /* return value from subroutine call */
Vdbe *v = pParse->pVdbe;
assert( v!=0 );
pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
}
pSel->iLimit = 0;
-
- /* pSel might be reused. So generate code using a copy of pSel, so that
- ** if the code generator modifies the underlying structure of the SELECT
- ** (for example in whereIndexExprTrans()) the original in pSel will be
- ** unchanged. */
- pCopy = sqlite3SelectDup(pParse->db, pSel, 0);
- rc = sqlite3Select(pParse, pCopy, &dest);
- sqlite3SelectDelete(pParse->db, pCopy);
- if( rc ) return 0;
-
+ if( sqlite3Select(pParse, pSel, &dest) ){
+ return 0;
+ }
pExpr->iTable = rReg = dest.iSDParm;
ExprSetVVAProperty(pExpr, EP_NoReduce);
if( addrOnce ){
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
+ assert( pWInfo->pExprMods==0 );
sqlite3DbFreeNN(db, pWInfo);
}
}
}
+ /* Undo all Expr node modifications */
+ while( pWInfo->pExprMods ){
+ WhereExprMod *p = pWInfo->pExprMods;
+ pWInfo->pExprMods = p->pNext;
+ memcpy(p->pExpr, &p->orig, sizeof(p->orig));
+ sqlite3DbFree(db, p);
+ }
+
/* Final cleanup
*/
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
#endif
+/*
+** Each instance of this object records a change to a single node
+** in an expression tree to cause that node to point to a column
+** of an index rather than an expression or a virtual column. All
+** such transformations need to be undone at the end of WHERE clause
+** processing.
+*/
+typedef struct WhereExprMod WhereExprMod;
+struct WhereExprMod {
+ WhereExprMod *pNext; /* Next translation on a list of them all */
+ Expr *pExpr; /* The Expr node that was transformed */
+ Expr orig; /* Original value of the Expr node */
+};
+
/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
Expr *pWhere; /* The complete WHERE clause */
- LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
+ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
u8 nLevel; /* Number of nested loop */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
- u8 sorted; /* True if really sorted (not just grouped) */
u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
- u8 bDeferredSeek; /* Uses OP_DeferredSeek */
- u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values */
- u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */
+ u8 bDeferredSeek : 1; /* Uses OP_DeferredSeek */
+ u8 untestedTerms : 1; /* Not all WHERE terms resolved by outer loop */
+ u8 bOrderedInnerLoop : 1; /* True if only the inner-most loop is ordered */
+ u8 sorted : 1; /* True if really sorted (not just grouped) */
+ LogEst nRowOut; /* Estimated number of output rows */
int iTop; /* The very beginning of the WHERE loop */
WhereLoop *pLoops; /* List of all WhereLoop objects */
+ WhereExprMod *pExprMods; /* Expression modifications */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
- LogEst nRowOut; /* Estimated number of output rows */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
int iIdxCur; /* The cursor for the index */
int iIdxCol; /* The column for the index */
int iTabCol; /* The column for the table */
+ WhereInfo *pWInfo; /* Complete WHERE clause information */
+ sqlite3 *db; /* Database connection (for malloc()) */
} IdxExprTrans;
+/*
+** Preserve pExpr on the WhereETrans list of the WhereInfo.
+*/
+static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
+ WhereExprMod *pNew;
+ pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
+ if( pNew==0 ) return;
+ pNew->pNext = pTrans->pWInfo->pExprMods;
+ pTrans->pWInfo->pExprMods = pNew;
+ pNew->pExpr = pExpr;
+ memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
+}
+
/* The walker node callback used to transform matching expressions into
** a reference to an index column for an index on an expression.
**
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
IdxExprTrans *pX = p->u.pIdxTrans;
if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
+ preserveExpr(pX, pExpr);
pExpr->affExpr = sqlite3ExprAffinity(pExpr);
pExpr->op = TK_COLUMN;
pExpr->iTable = pX->iIdxCur;
IdxExprTrans *pX = p->u.pIdxTrans;
if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
assert( pExpr->y.pTab!=0 );
+ preserveExpr(pX, pExpr);
pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
pExpr->iTable = pX->iIdxCur;
pExpr->iColumn = pX->iIdxCol;
w.u.pIdxTrans = &x;
x.iTabCur = iTabCur;
x.iIdxCur = iIdxCur;
+ x.pWInfo = pWInfo;
+ x.db = pWInfo->pParse->db;
for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
i16 iRef = pIdx->aiColumn[iIdxCol];
if( iRef==XN_EXPR ){