From: drh Date: Wed, 13 Nov 2013 19:01:41 +0000 (+0000) Subject: Import the "PRAGMA vdbe_eqp" enhancement and the enhanced EXPLAIN formatting X-Git-Tag: version-3.8.2~94^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fskip-scan;p=thirdparty%2Fsqlite.git Import the "PRAGMA vdbe_eqp" enhancement and the enhanced EXPLAIN formatting the shell from trunk. Fix a bug in skip-scan and add a test case to prevent a regression. FossilOrigin-Name: f668616a29686f3ce532731c534b168e536adbb5 --- d24474475ed7aa862f2043359728f552236d0b3c diff --cc manifest index 390483589c,78bd21a267..414ce82414 --- a/manifest +++ b/manifest @@@ -1,5 -1,5 +1,5 @@@ - C Add\sVDBE\scomments\sto\sthe\sbeginning\sand\send\sof\sskip-scan\sloops. - D 2013-11-13T17:24:39.000 -C In\sthe\sshell\stool,\sif\san\s"EXPLAIN"\scommand\sis\sexecuted\sin\s".explain\son"\smode,\sattempt\sto\sautomatically\sindent\sthe\sbodies\sof\sloops\sin\sthe\soutput\sVDBE\sprogram. -D 2013-11-13T18:35:01.894 ++C Import\sthe\s"PRAGMA\svdbe_eqp"\senhancement\sand\sthe\senhanced\sEXPLAIN\sformatting\nthe\sshell\sfrom\strunk.\s\sFix\sa\sbug\sin\sskip-scan\sand\sadd\sa\stest\scase\sto\sprevent\na\sregression. ++D 2013-11-13T19:01:41.390 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@@ -220,7 -220,7 +220,7 @@@ F src/random.c 0b2dbc37fdfbfa6bd455b091 F src/resolve.c fc4673cc49b116e51e7f12de074c0acf8f2388f9 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 7317406831ecced390edba972818f3c5f82238c0 - F src/shell.c 03d8d9b4052430343ff30d646334621f980f1202 -F src/shell.c 3b23017da75118da0a7e3518c6ce78a7b747fb05 ++F src/shell.c 6ccc22b717afe4f6d7d3c8b6baa02e3b99a5fdf0 F src/sqlite.h.in 4dedcab5b32358bf7a596badffe7363be1f1a82d F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc @@@ -293,8 -293,8 +293,8 @@@ F src/vtab.c 5a423b042eb1402ef77697d03d F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74 - F src/where.c 1d19a1d49a608441fa697ae32627399073be8dcf -F src/where.c 537f4d7e869f41b7aef851ad0b050983b4d6508d -F src/whereInt.h 63c8345d01d12ded6250b72e7c16855f0a358041 ++F src/where.c 2eb88f96a73d77bd61d6afd50c33ec5d63c15dd5 +F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@@ -805,7 -805,6 +805,7 @@@ F test/shell5.test 46c8c18d62732415c4fe F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 - F test/skipscan1.test bc65ecb228eba396c404aa038f49798340f0677f ++F test/skipscan1.test 6bb4891c2cc5efd5690a9da9e7508e53d4a68e10 F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 @@@ -1139,7 -1138,7 +1139,7 @@@ F tool/vdbe-compress.tcl f12c884766bd14 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff - P 5e75ab93881b85801cb4ebf70f2063ff7c51ac19 - R 324d2d53e7ac48858b72f1751f7e7610 -P 8ce33f4c818e1c785a1c176f6f631b8184e1166b -R 5d7c6b4eb6f0cadad72d4cdb7ed00f79 -U dan -Z 87b1c90d92386c54cb5a5e86314bc13e ++P 0c85d93b52311dee7980d977be6ed0dc70b060c1 e7d34ec6814ed4606a6d5d7f68c218ae4d25e666 ++R 0f42dd23f60246e0b55a84d51974156a +U drh - Z 7cfb6326eedc7a21a0bd15f40c4f97e2 ++Z 2c708550c85df0e56ea327d75809b287 diff --cc manifest.uuid index ac2ea40722,e811c26432..29ff9c336f --- a/manifest.uuid +++ b/manifest.uuid @@@ -1,1 -1,1 +1,1 @@@ - 0c85d93b52311dee7980d977be6ed0dc70b060c1 -e7d34ec6814ed4606a6d5d7f68c218ae4d25e666 ++f668616a29686f3ce532731c534b168e536adbb5 diff --cc src/shell.c index c3aee04633,6761750816..61df7d6d52 --- a/src/shell.c +++ b/src/shell.c @@@ -1141,6 -1148,89 +1148,90 @@@ static int display_stats return 0; } + /* + ** Parameter azArray points to a zero-terminated array of strings. zStr + ** points to a single nul-terminated string. Return non-zero if zStr + ** is equal, according to strcmp(), to any of the strings in the array. + ** Otherwise, return zero. + */ + static int str_in_array(const char *zStr, const char **azArray){ + int i; + for(i=0; azArray[i]; i++){ + if( 0==strcmp(zStr, azArray[i]) ) return 1; + } + return 0; + } + + /* + ** If compiled statement pSql appears to be an EXPLAIN statement, allocate + ** and populate the callback_data.aiIndent[] array with the number of + ** spaces each opcode should be indented before it is output. + ** + ** The indenting rules are: + ** + ** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent + ** all opcodes that occur between the p2 jump destination and the opcode + ** itself by 2 spaces. + ** -** * For each "Goto", if the jump destination is a "Yield" instruction -** that occurs earlier in the program than the Goto itself, indent -** all opcodes between the "Yield" and "Goto" by 2 spaces. ++** * For each "Goto", if the jump destination is a "Yield", "SeekGt", ++** or "SeekLt" instruction that occurs earlier in the program than ++** the Goto itself, indent all opcodes between the earlier instruction ++** and "Goto" by 2 spaces. + */ + static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){ + const char *zSql; /* The text of the SQL statement */ + const char *z; /* Used to check if this is an EXPLAIN */ + int *abYield = 0; /* True if op is an OP_Yield */ + int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ + int iOp; + + const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", 0 }; - const char *azYield[] = { "Yield", 0 }; ++ const char *azYield[] = { "Yield", "SeekLt", "SeekGt", 0 }; + const char *azGoto[] = { "Goto", 0 }; + + /* Try to figure out if this is really an EXPLAIN statement. If this + ** cannot be verified, return early. */ + zSql = sqlite3_sql(pSql); + if( zSql==0 ) return; + for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++); + if( sqlite3_strnicmp(z, "explain", 7) ) return; + + for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){ + int i; + const char *zOp = (const char*)sqlite3_column_text(pSql, 1); + int p2 = sqlite3_column_int(pSql, 3); + + /* Grow the p->aiIndent array as required */ + if( iOp>=nAlloc ){ + nAlloc += 100; + p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int)); + abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int)); + } + abYield[iOp] = str_in_array(zOp, azYield); + p->aiIndent[iOp] = 0; + p->nIndent = iOp+1; + + if( str_in_array(zOp, azNext) ){ + for(i=p2; iaiIndent[i] += 2; + } + if( str_in_array(zOp, azGoto) && p2nIndent && abYield[p2] ){ + for(i=p2+1; iaiIndent[i] += 2; + } + } + + sqlite3_free(abYield); + sqlite3_reset(pSql); + } + + /* + ** Free the array allocated by explain_data_prepare(). + */ + static void explain_data_delete(struct callback_data *p){ + sqlite3_free(p->aiIndent); + p->aiIndent = 0; + p->nIndent = 0; + } + /* ** Execute a statement or set of statements. Print ** any result rows/columns depending on the current mode diff --cc src/where.c index 2fd7c600c8,f5030b6a68..c4f25675c2 --- a/src/where.c +++ b/src/where.c @@@ -3852,6 -3822,6 +3855,7 @@@ static void whereLoopOutputAdjust(Where if( (pTerm->prereqAll & notAllowed)!=0 ) continue; for(j=pLoop->nLTerm-1; j>=0; j--){ pX = pLoop->aLTerm[j]; ++ if( pX==0 ) continue; if( pX==pTerm ) break; if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } diff --cc test/skipscan1.test index eba7383eaa,0000000000..622e48fcfa mode 100644,000000..100644 --- a/test/skipscan1.test +++ b/test/skipscan1.test @@@ -1,175 -1,0 +1,190 @@@ +# 2013-11-13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests of the "skip-scan" query strategy. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test skipscan1-1.1 { + CREATE TABLE t1(a TEXT, b INT, c INT, d INT); + CREATE INDEX t1abc ON t1(a,b,c); + INSERT INTO t1 VALUES('abc',123,4,5); + INSERT INTO t1 VALUES('abc',234,5,6); + INSERT INTO t1 VALUES('abc',234,6,7); + INSERT INTO t1 VALUES('abc',345,7,8); + INSERT INTO t1 VALUES('def',567,8,9); + INSERT INTO t1 VALUES('def',345,9,10); + INSERT INTO t1 VALUES('bcd',100,6,11); + + /* Fake the sqlite_stat1 table so that the query planner believes + ** the table contains thousands of rows and that the first few + ** columns are not selective. */ + ANALYZE; + DELETE FROM sqlite_stat1; + INSERT INTO sqlite_stat1 VALUES('t1','t1abc','10000 5000 2000 10'); + ANALYZE sqlite_master; +} {} + +# Simple queries that leave the first one or two columns of the +# index unconstrainted. +# +do_execsql_test skipscan1-1.2 { + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {abc 345 7 8 | def 345 9 10 |} +do_execsql_test skipscan1-1.2eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {/* USING INDEX t1abc (ANY(a) AND b=?)*/} +do_execsql_test skipscan1-1.2sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.3 { + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a DESC; +} {def 345 9 10 | abc 345 7 8 |} +do_execsql_test skipscan1-1.3eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {/* USING INDEX t1abc (ANY(a) AND b=?)*/} +do_execsql_test skipscan1-1.3sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.4 { + SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; +} {abc 234 6 7 | bcd 100 6 11 |} +do_execsql_test skipscan1-1.4eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; +} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/} +do_execsql_test skipscan1-1.4sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.5 { + SELECT a,b,c,d,'|' FROM t1 WHERE c IN (6,7) ORDER BY a, b, c; +} {abc 234 6 7 | abc 345 7 8 | bcd 100 6 11 |} +do_execsql_test skipscan1-1.5eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c IN (6,7) ORDER BY a, b, c; +} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/} +do_execsql_test skipscan1-1.5sort { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c IN (6,7) ORDER BY a, b, c; +} {~/*ORDER BY*/} + +do_execsql_test skipscan1-1.6 { + SELECT a,b,c,d,'|' FROM t1 WHERE c BETWEEN 6 AND 7 ORDER BY a, b, c; +} {abc 234 6 7 | abc 345 7 8 | bcd 100 6 11 |} +do_execsql_test skipscan1-1.6eqp { + EXPLAIN QUERY PLAN + SELECT a,b,c,d,'|' FROM t1 WHERE c BETWEEN 6 AND 7 ORDER BY a, b, c; +} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c>? AND c? AND c