-C Enable\spragma\svirtual\stables\sfor\sthe\sintegrity_check,\squick_check,\sand\nforeign_key_check\spragmas.
-D 2017-06-21T01:36:30.804
+C When\sgenerating\sindividual\sloops\sfor\seach\sORed\sterm\sof\san\sOR\sscan,\smove\sany\nconstant\sWHERE\sexpressions\soutside\sof\sthe\sloop,\sas\sis\sdone\sfor\stop-level\nloops.
+D 2017-06-22T16:51:16.239
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc
F src/delete.c 3213547e97b676c6fa79948b7a9ede4801ea04a01a2043241deafedf132ecf5d
F src/expr.c 452c6f3aa656aabf3eefe96bb5f316b2c987fbc12c647964e4ed880f193ca31f
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
-F src/fkey.c db65492ae549c3b548c9ef1f279ce1684f1c473b116e1c56a90878cd5dcf968d
+F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
F src/global.c 8a6ab6b4d91effb96ffa81b39f0d70c862abca157f8aaa194600a4a8b7923344
F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
-F src/tclsqlite.c c8cf60d0c5411d5e70e7c136470d29dbe760d250f55198b71682c67086524e4a
+F src/tclsqlite.c 1ac29f18b1b3787a30b45dbbdf6fdc4aa4f1a2f8c7c8fe586beba1b177eba97d
F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
F src/walker.c d46044e7a5842560dfe7122d93ff5145dd4a96f4d0bf5ba5910a7731b8c01e79
-F src/where.c aa213e1b1c29eb8946a9f25108a18666a745ae5bac41b58d0be98730937a7785
+F src/where.c d4f329d9055dbdb475d697f205db1104af886aad4400168fb9b957f6251ea926
F src/whereInt.h 2a4b634d63ce488b46d4b0da8f2eaa8f9aeab202bc25ef76f007de5e3fba1f20
F src/wherecode.c 339ee802d9d311acf0cba8b5a9a092e167ef71c3a777d4b3e57de25d193251c7
F src/whereexpr.c a2fe3811d45af45a5c6667caabc15e01054fe6228c64e86e1f7d2ba5ef5284f9
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
-F test/eqp.test 3fe051af50921284189d1970eb653f9fcf5117d2
+F test/eqp.test 3f9ba0b2594837c7beaa3ba824e2137cfe857308f020ec5a0c7a62b444e837b0
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
F test/exclusive.test 9a57bd66e39144b888ca75c309914fcdefb4e3f9
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
F test/whereD.test 711d4df58d6d4fb9b3f5ce040b818564198be002
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
-F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
+F test/whereF.test 97a86ecdfa4c21684fdff501dbd2cb7397689be8676d0dbad1f5a0892c6b56a3
F test/whereG.test dde4c52a97385a55be6a7cd46be8373f0cf35501
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test eab5b226bbc344ac70d7dc09b963a064860ae6d7
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 94e420ecfb4ec047eb7d1d3125ca8487c90d466760b7f7183759ff922bd868d1
-R bb441c04952674b0d2cabd8a1e6870d3
-U drh
-Z cb37bb49734166773486fcb21706d402
+P 118f7bb33a6f78951bbffa957f48015d1bce5aaf9246a99262a90bc8ad52e5a3
+R b4aae75660dcec44ff13144cfab52224
+T *branch * or-optimization
+T *sym-or-optimization *
+T -sym-trunk *
+U dan
+Z 7d390f8e00d309abb459da345f7f0ca9
-118f7bb33a6f78951bbffa957f48015d1bce5aaf9246a99262a90bc8ad52e5a3
\ No newline at end of file
+e4a022be4b069b08cfdfda5295461676b99d28e17bbbedfbcb362dec69de59bd
\ No newline at end of file
/* Create VDBE to loop through the entries in pSrc that match the WHERE
** clause. For each row found, increment either the deferred or immediate
** foreign key constraint counter. */
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
- sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
- if( pWInfo ){
- sqlite3WhereEnd(pWInfo);
+ if( pParse->nErr==0 ){
+ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
+ if( pWInfo ){
+ sqlite3WhereEnd(pWInfo);
+ }
}
/* Clean up the WHERE clause constructed above. */
int nStmt; /* Number of statements in stmtList */
IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
int nStep, nSort, nIndex; /* Statistics for most recent operation */
+ int nVMStep; /* Another statistic for most recent operation */
int nTransaction; /* Number of nested [transaction] methods */
int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */
#ifdef SQLITE_TEST
pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1);
pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1);
pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1);
+ pDb->nVMStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_VM_STEP,1);
dbReleaseColumnNames(p);
p->pPreStmt = 0;
}
/*
- ** $db status (step|sort|autoindex)
+ ** $db status (step|sort|autoindex|vmstep)
**
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
** SQLITE_STMTSTATUS_SORT for the most recent eval.
v = pDb->nSort;
}else if( strcmp(zOp, "autoindex")==0 ){
v = pDb->nIndex;
+ }else if( strcmp(zOp, "vmstep")==0 ){
+ v = pDb->nVMStep;
}else{
Tcl_AppendResult(interp,
- "bad argument: should be autoindex, step, or sort",
+ "bad argument: should be autoindex, step, sort or vmstep",
(char*)0);
return TCL_ERROR;
}
return 0;
}
+/*
+** Helper function for exprIsDeterministic().
+*/
+static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return true if the expression contains no non-deterministic SQL
+** functions. Do not consider non-deterministic SQL functions that are
+** part of sub-select statements.
+*/
+static int exprIsDeterministic(Expr *p){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.eCode = 1;
+ w.xExprCallback = exprNodeIsDeterministic;
+ sqlite3WalkExpr(&w, p);
+ return w.eCode;
+}
+
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
- /* Special case: a WHERE clause that is constant. Evaluate the
- ** expression and either jump over all of the code or fall thru.
- */
- for(ii=0; ii<sWLB.pWC->nTerm; ii++){
- if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){
- sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak,
- SQLITE_JUMPIFNULL);
- sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
- }
- }
-
/* Special case: No FROM clause
*/
if( nTabList==0 ){
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
if( db->mallocFailed ) goto whereBeginError;
+ /* Special case: WHERE terms that do not refer to any tables in the join
+ ** (constant expressions). Evaluate each such term, and jump over all the
+ ** generated code if the result is not true.
+ **
+ ** Do not do this if the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not strictly required, but
+ ** preserves SQLite's legacy behaviour in the following two cases:
+ **
+ ** FROM ... WHERE random()>0; -- eval random() once per row
+ ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ */
+ for(ii=0; ii<sWLB.pWC->nTerm; ii++){
+ WhereTerm *pT = &sWLB.pWC->a[ii];
+ if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
+ sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pT->wtFlags |= TERM_CODED;
+ }
+ }
+
if( wctrlFlags & WHERE_WANT_DISTINCT ){
if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
/* The DISTINCT marking is pointless. Ignore it. */
do_eqp_test 3.1.2 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
} {
- 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
+ 0 0 0 {SCAN TABLE t1}
}
do_eqp_test 3.1.3 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
} {
- 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
+ 0 0 0 {SCAN TABLE t1}
}
do_eqp_test 3.1.4 {
SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
} {
- 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
+ 0 0 0 {SCAN TABLE t1}
}
det 3.2.1 {
EXPLAIN QUERY PLAN SELECT rowid FROM t4 WHERE a=? AND b=?;
} {/a=. AND b=./}
+#-------------------------------------------------------------------------
+# Test the following case:
+#
+# ... FROM t1, t2 WHERE (
+# t2.rowid = +t1.rowid OR (t2.f2 = t1.f1 AND t1.f1!=-1)
+# )
+#
+# where there is an index on t2(f2). The planner should use "t1" as the
+# outer loop. The inner loop, on "t2", is an OR optimization. One pass
+# for:
+#
+# t2.rowid = $1
+#
+# and another for:
+#
+# t2.f2=$1 AND $1!=-1
+#
+# the test is to ensure that on the second pass, the ($1!=-1) condition
+# is tested before any seek operations are performed - i.e. outside of
+# the loop through the f2=$1 range of the t2(f2) index.
+#
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE t1(f1);
+ CREATE TABLE t2(f2);
+ CREATE INDEX t2f ON t2(f2);
+
+ INSERT INTO t1 VALUES(-1);
+ INSERT INTO t1 VALUES(-1);
+ INSERT INTO t1 VALUES(-1);
+ INSERT INTO t1 VALUES(-1);
+
+ WITH w(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM w WHERE i<1000
+ )
+ INSERT INTO t2 SELECT -1 FROM w;
+}
+
+do_execsql_test 5.1 {
+ SELECT count(*) FROM t1, t2 WHERE t2.rowid = +t1.rowid
+} {4}
+do_test 5.2 { expr [db status vmstep]<200 } 1
+
+do_execsql_test 5.3 {
+ SELECT count(*) FROM t1, t2 WHERE (
+ t2.rowid = +t1.rowid OR t2.f2 = t1.f1
+ )
+} {4000}
+do_test 5.4 { expr [db status vmstep]>1000 } 1
+
+do_execsql_test 5.5 {
+ SELECT count(*) FROM t1, t2 WHERE (
+ t2.rowid = +t1.rowid OR (t2.f2 = t1.f1 AND t1.f1!=-1)
+ )
+} {4}
+do_test 5.6 { expr [db status vmstep]<200 } 1
+
finish_test