-C Do\snot\sallow\scursor\shints\sto\suse\sexpressions\scontaining\ssubqueries.\s\sThis\nchange\sfixes\sthe\sproblem\sseen\sin\sthe\sprevious\scheck-in.
-D 2013-12-07T23:35:21.843
+C In\sthe\sexpression\spassed\sto\ssqlite3BtreeCursorHint()\sfor\sthe\sinner\sloops\sof\sjoins,\sreplace\sany\sTK_COLUMN\sreferences\sto\scolumns\sin\sthe\souter\sloops\swith\sTK_REGISTER\sexpressions\s(Expr.iTable\sindicates\sthe\sspecific\sregister\scontaining\sthe\svalue).
+D 2014-07-14T19:04:29.385
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e1a9b4258bbde53f5636f4e238c65b7e11459e2b
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
-F src/where.c 34cf76979535b933b39403f81c8c757cf3c4fe9f
+F src/where.c dcea6104452e837cc63bd1c3c5cb05868bb356ba
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 3a9bec524ef2de44028b4058e67dc962082888d3
-R e725a27255f076e1cf88ead0905058a7
-U drh
-Z 572bab5aee8e2ee9e755c685fab22b9b
+P bfefc57554853e467ee6aeaba8d08331406fa216
+R d30e9be65b11497e93ad990065d669d6
+U dan
+Z c72f8637bcd1205d8e636acedbe3ca98
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
+
+/*
+** 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.i), 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.
+*/
+static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
+ int rc = WRC_Continue;
+ if( pExpr->op==TK_COLUMN && pExpr->iTable!=pWalker->u.i ){
+ 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( 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.
*/
pLevel = &pWInfo->a[iLevel];
pWLoop = pLevel->pWLoop;
iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor;
- msk = ~getMask(&pWInfo->sMaskSet, iCur);
pWC = &pWInfo->sWC;
for(i=0; i<pWC->nTerm; i++){
pTerm = &pWC->a[i];
- if( pTerm->prereqAll & msk ) continue;
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( pTerm->prereqAll & pLevel->notReady ) continue;
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){}
if( j<pWLoop->nLTerm ) continue;
pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
- }
+ }
if( pExpr!=0 ){
- sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0,
- (const char*)pExpr, P4_EXPR);
+ const char *a = (const char*)pExpr;
+ Walker sWalker;
+ memset(&sWalker, 0, sizeof(sWalker));
+ sWalker.xExprCallback = codeCursorHintFixExpr;
+ sWalker.pParse = pParse;
+ sWalker.u.i = pLevel->iTabCur;
+ sqlite3WalkExpr(&sWalker, pExpr);
+ sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, a, P4_EXPR);
}
}
#else