From 7682a476f6da4808691d6387d330a3f5d7378e7b Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 29 Sep 2014 15:00:28 +0000 Subject: [PATCH 1/8] Ensure that the OP_Prev opcode verifies that content has not been deleted out from under the cursor. Fix for ticket [209d31e3161b9e9ff]. FossilOrigin-Name: 414f0d6a647a4d040b5463c73c5e15e699d85b4c --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/btree.c | 3 +-- test/eval.test | 12 ++++++++++++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 63e97cbf9f..68c67e07c1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sassert()\sto\sverify\sthe\slast-row-id\sfor\sthe\sdatabase\sjust\sprior\sto\scalling\sa\sSQL\sfunction. -D 2014-09-26T18:30:11.093 +C Ensure\sthat\sthe\sOP_Prev\sopcode\sverifies\sthat\scontent\shas\snot\sbeen\sdeleted\nout\sfrom\sunder\sthe\scursor.\s\sFix\sfor\sticket\s[209d31e3161b9e9ff]. +D 2014-09-29T15:00:28.761 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,7 +172,7 @@ F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2 F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 59f03e421dad3cb6e27cc7d2393d3a7459be4b5e +F src/btree.c ede8348a7d623257ee6c06ca4796ceaee13b8657 F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8 F src/btreeInt.h 1bd7957161a1346a914f1f09231610e777a8e58d F src/build.c bde83dd5cf812e310a7e5ad2846790a14745bef4 @@ -469,7 +469,7 @@ F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 F test/eqp.test 85873fa5816c48915c82c4e74cb5c35a5b48160f F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401 -F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 +F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75 F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 83913515830aa850f9e38406f9422d7e88dcab66 -R dc4da31df9102dea4f18af6519657b79 -U mistachkin -Z 6fd91dd1e10822b3b57f7222d98e1fa9 +P d026f0c944ce812732d3595eaa3c5d432a86c7dd +R 4bbd3babbb639de348c82ac1e98901ef +U drh +Z e609ec38acb2ceba655fca4c2f22f4af diff --git a/manifest.uuid b/manifest.uuid index 482b361956..909bc1e4db 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d026f0c944ce812732d3595eaa3c5d432a86c7dd \ No newline at end of file +414f0d6a647a4d040b5463c73c5e15e699d85b4c \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 135b40139f..503a2fb5d0 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4985,8 +4985,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ - assert( pCur->eState>=CURSOR_REQUIRESEEK ); - rc = btreeRestoreCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } diff --git a/test/eval.test b/test/eval.test index 912dc8215b..360d158f3c 100644 --- a/test/eval.test +++ b/test/eval.test @@ -58,6 +58,18 @@ do_test eval-2.2 { SELECT * FROM t2 } } {} +do_test eval-2.3 { + execsql { + INSERT INTO t2 SELECT x, x+1 FROM t1 WHERE x<5; + SELECT x, test_eval('DELETE FROM t2 WHERE x='||x), y FROM t2 + ORDER BY rowid DESC; + } +} {4 {} {} 3 {} {} 2 {} {} 1 {} {}} +do_test eval-2.4 { + execsql { + SELECT * FROM t2 + } +} {} # Modify a row while it is being read. # From 39c4b82b5a82977db329f688ebf4bf0a2d901ec1 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 29 Sep 2014 15:42:01 +0000 Subject: [PATCH 2/8] Fix the header comment in sqlite3VdbeDeletePriorOpcode(). No changes to code. FossilOrigin-Name: 7fb1626866c2f8dad84c7e6184824be3efd71ca2 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeaux.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 68c67e07c1..c39ace7ac0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sthe\sOP_Prev\sopcode\sverifies\sthat\scontent\shas\snot\sbeen\sdeleted\nout\sfrom\sunder\sthe\scursor.\s\sFix\sfor\sticket\s[209d31e3161b9e9ff]. -D 2014-09-29T15:00:28.761 +C Fix\sthe\sheader\scomment\sin\ssqlite3VdbeDeletePriorOpcode().\s\sNo\schanges\sto\ncode. +D 2014-09-29T15:42:01.115 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -293,7 +293,7 @@ F src/vdbe.c 93eeb6f9c3a3084133225a196f220454d71cca10 F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h bb7f7ecfdead1a2ae0251b59f86f5724838d975c F src/vdbeapi.c e9e33b59834e3edc8790209765e069874c269d9d -F src/vdbeaux.c a05adc3c96abdaf3db14768ddd63132fc9678060 +F src/vdbeaux.c 8e016c6051c013a394f8e8679be1ca60723707bd F src/vdbeblob.c 848238dc73e93e48432991bb5651bf87d865eca4 F src/vdbemem.c 1e105dacf5190fc85a8ec2107c0dcc1884e75099 F src/vdbesort.c 5c1bacf90578d22b630fbf6ed98ccf60d83435ef @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P d026f0c944ce812732d3595eaa3c5d432a86c7dd -R 4bbd3babbb639de348c82ac1e98901ef +P 414f0d6a647a4d040b5463c73c5e15e699d85b4c +R f6298f1a1c0cd9e9dc9c3dc07f24407e U drh -Z e609ec38acb2ceba655fca4c2f22f4af +Z 0f82639c06e932d5523a9215bf58cd9c diff --git a/manifest.uuid b/manifest.uuid index 909bc1e4db..b5ea57e647 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -414f0d6a647a4d040b5463c73c5e15e699d85b4c \ No newline at end of file +7fb1626866c2f8dad84c7e6184824be3efd71ca2 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 87b14a6d87..2562c63b62 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -752,7 +752,8 @@ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ } /* -** Remove the last opcode inserted +** If the last opcode is "op" and it is not a jump destination, +** then remove it. Return true if and only if an opcode was removed. */ int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ From 4fa4a54f7eb58c465186cac6fe9ab4f5cbddbc12 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Sep 2014 12:33:33 +0000 Subject: [PATCH 3/8] Remove the SQLITE_ENABLE_TREE_EXPLAIN compile-time option. Add alternative debugging display routines: sqlite3TreeViewExpr(), sqlite3TreeViewExprList(), and sqlite3TreeViewSelect(). FossilOrigin-Name: 4ff51325d6b41d0c59e303b573700ec80c51d216 --- manifest | 34 +++++----- manifest.uuid | 2 +- src/expr.c | 167 ++++++++++++++++++++++-------------------------- src/main.c | 16 ----- src/parse.y | 3 - src/printf.c | 64 +++++++++++++++++++ src/select.c | 124 +++++++++++++++++------------------ src/shell.c | 9 --- src/sqlite.h.in | 2 +- src/sqliteInt.h | 45 +++++++------ src/vdbeInt.h | 4 -- src/vdbeaux.c | 4 -- src/vdbetrace.c | 115 --------------------------------- src/where.c | 59 ----------------- 14 files changed, 245 insertions(+), 403 deletions(-) diff --git a/manifest b/manifest index c39ace7ac0..642f78d5ff 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sheader\scomment\sin\ssqlite3VdbeDeletePriorOpcode().\s\sNo\schanges\sto\ncode. -D 2014-09-29T15:42:01.115 +C Remove\sthe\sSQLITE_ENABLE_TREE_EXPLAIN\scompile-time\soption.\s\sAdd\salternative\ndebugging\sdisplay\sroutines:\ssqlite3TreeViewExpr(),\ssqlite3TreeViewExprList(),\nand\ssqlite3TreeViewSelect(). +D 2014-09-30T12:33:33.546 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -181,7 +181,7 @@ F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14 F src/ctime.c bb434068b5308a857b181c2d204a320ff0d6c638 F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036 F src/delete.c fae81cc2eb14b75267d4f47d3cfc9ae02aae726f -F src/expr.c f32119248996680aa73c5c37bfdd42820804dc17 +F src/expr.c 46a8ca93361d09f2ec6d9b7d524751510569d737 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c d15621461fb0c52675eba2b650492ed1beef69ab +F src/main.c 4a507a467cc20979579e4320ca6466b8ed0be268 F src/malloc.c 5bb99ee1e08ad58e457063cf79ce521db0e24195 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -217,22 +217,22 @@ F src/os_win.c 0a4042ef35f322e86fa01f6c8884c5e645b911e7 F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 F src/pager.c caab007743821d96752597c9cfd7351654697b06 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 -F src/parse.y b98772da2bb5415970085b707203f92569400aa8 +F src/parse.y ce1494308578d2f10a68cd8debc9fc156dda1094 F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c dab8ab930d4a73b99768d881185994f34b80ecaa F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196 -F src/printf.c 3a47f526b173813d9a7f4e7044007771ba68cde1 +F src/printf.c 0db94d24f97b4e562e9da9d2ce85e8a69531daf6 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c a83ed8bc2a31c131e3addb6f0488b68334085e7b -F src/shell.c dad23987c34faddb061a339da3e92e05ccc6935e -F src/sqlite.h.in 8b018219ce988913e5977d5de9ab4beb33be23b6 +F src/select.c 373da54c2bd7e38993bc926a284bc05a53b01b8b +F src/shell.c 38f627b0885191357f55902a3ac199de90d79715 +F src/sqlite.h.in 159f2cb9eef74b6c99aeeb4c071e7745835f04f6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 5e09fe04f999223680801ddf8fbae6b60751d613 +F src/sqliteInt.h 8242d04760ec2a943a152eba2a006ea121a3eafd F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb @@ -291,18 +291,18 @@ F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c 93eeb6f9c3a3084133225a196f220454d71cca10 F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 -F src/vdbeInt.h bb7f7ecfdead1a2ae0251b59f86f5724838d975c +F src/vdbeInt.h 0b97a3190f8fbf460655985a9183019f5a702754 F src/vdbeapi.c e9e33b59834e3edc8790209765e069874c269d9d -F src/vdbeaux.c 8e016c6051c013a394f8e8679be1ca60723707bd +F src/vdbeaux.c 5b687d7b5beaaa5b97189edf25cf08c311834933 F src/vdbeblob.c 848238dc73e93e48432991bb5651bf87d865eca4 F src/vdbemem.c 1e105dacf5190fc85a8ec2107c0dcc1884e75099 F src/vdbesort.c 5c1bacf90578d22b630fbf6ed98ccf60d83435ef -F src/vdbetrace.c 4f29b04edb0cec3d5fcd9b566d9f0e75c8984362 +F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c a14d3d8042adeb51f81731c1b47b3e481d1cc23a +F src/where.c 5a2c700f6f29da91ac633015d1378b91dcf237b6 F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 414f0d6a647a4d040b5463c73c5e15e699d85b4c -R f6298f1a1c0cd9e9dc9c3dc07f24407e +P 7fb1626866c2f8dad84c7e6184824be3efd71ca2 +R f57511c6ad57aee6db1d51feabde515b U drh -Z 0f82639c06e932d5523a9215bf58cd9c +Z d2ed6dec33496c4977b9e22861714f01 diff --git a/manifest.uuid b/manifest.uuid index b5ea57e647..246f7552d4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7fb1626866c2f8dad84c7e6184824be3efd71ca2 \ No newline at end of file +4ff51325d6b41d0c59e303b573700ec80c51d216 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 57e462ea6e..31ff98ea4f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3236,90 +3236,86 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ exprToRegister(pExpr, iMem); } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable explanation of an expression tree. */ -void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ - int op; /* The opcode being coded */ +void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ + pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ - op = TK_NULL; - }else{ - op = pExpr->op; + sqlite3TreeViewLine(pView, "nil"); + sqlite3TreeViewPop(pView); + return; } - switch( op ){ + switch( pExpr->op ){ case TK_AGG_COLUMN: { - sqlite3ExplainPrintf(pOut, "AGG{%d:%d}", + sqlite3TreeViewLine(pView, "AGG{%d:%d}", pExpr->iTable, pExpr->iColumn); break; } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ - sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn); + sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn); }else{ - sqlite3ExplainPrintf(pOut, "{%d:%d}", + sqlite3TreeViewLine(pView, "{%d:%d}", pExpr->iTable, pExpr->iColumn); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ - sqlite3ExplainPrintf(pOut, "%d", pExpr->u.iValue); + sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ - sqlite3ExplainPrintf(pOut, "%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); } break; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { - sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { - sqlite3ExplainPrintf(pOut,"%Q", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { - sqlite3ExplainPrintf(pOut,"NULL"); + sqlite3TreeViewLine(pView,"NULL"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { - sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken); + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { - sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)", - pExpr->u.zToken, pExpr->iColumn); + sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", + pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { - sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable); + sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } case TK_AS: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); + sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + case TK_ID: { + sqlite3TreeViewLine(pView,"ID %Q", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ - const char *zAff = "unk"; - switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){ - case SQLITE_AFF_TEXT: zAff = "TEXT"; break; - case SQLITE_AFF_NONE: zAff = "NONE"; break; - case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break; - case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break; - case SQLITE_AFF_REAL: zAff = "REAL"; break; - } - sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } #endif /* SQLITE_OMIT_CAST */ @@ -3352,8 +3348,8 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_COLLATE: { - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken); + sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } @@ -3365,41 +3361,36 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ }else{ pFarg = pExpr->x.pList; } - if( op==TK_AGG_FUNCTION ){ - sqlite3ExplainPrintf(pOut, "AGG_FUNCTION%d:%s(", + if( pExpr->op==TK_AGG_FUNCTION ){ + sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", pExpr->op2, pExpr->u.zToken); }else{ - sqlite3ExplainPrintf(pOut, "FUNCTION:%s(", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); } if( pFarg ){ - sqlite3ExplainExprList(pOut, pFarg); + sqlite3TreeViewExprList(pView, pFarg, 0, 0); } - sqlite3ExplainPrintf(pOut, ")"); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { - sqlite3ExplainPrintf(pOut, "EXISTS("); - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { - sqlite3ExplainPrintf(pOut, "("); - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3ExplainPrintf(pOut, "IN("); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ","); + sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - sqlite3ExplainSelect(pOut, pExpr->x.pSelect); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ - sqlite3ExplainExprList(pOut, pExpr->x.pList); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); } - sqlite3ExplainPrintf(pOut, ")"); break; } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -3419,13 +3410,10 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ Expr *pX = pExpr->pLeft; Expr *pY = pExpr->x.pList->a[0].pExpr; Expr *pZ = pExpr->x.pList->a[1].pExpr; - sqlite3ExplainPrintf(pOut, "BETWEEN("); - sqlite3ExplainExpr(pOut, pX); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExpr(pOut, pY); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExpr(pOut, pZ); - sqlite3ExplainPrintf(pOut, ")"); + sqlite3TreeViewLine(pView, "BETWEEN"); + sqlite3TreeViewExpr(pView, pX, 1); + sqlite3TreeViewExpr(pView, pY, 1); + sqlite3TreeViewExpr(pView, pZ, 0); break; } case TK_TRIGGER: { @@ -3436,15 +3424,14 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. */ - sqlite3ExplainPrintf(pOut, "%s(%d)", + sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { - sqlite3ExplainPrintf(pOut, "CASE("); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut, ","); - sqlite3ExplainExprList(pOut, pExpr->x.pList); + sqlite3TreeViewLine(pView, "CASE"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER @@ -3456,55 +3443,57 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } - sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken); + sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif + default: { + sqlite3TreeViewLine(pView, "op=%d", pExpr->op); + break; + } } if( zBinOp ){ - sqlite3ExplainPrintf(pOut,"%s(", zBinOp); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,","); - sqlite3ExplainExpr(pOut, pExpr->pRight); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "%s", zBinOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); }else if( zUniOp ){ - sqlite3ExplainPrintf(pOut,"%s(", zUniOp); - sqlite3ExplainExpr(pOut, pExpr->pLeft); - sqlite3ExplainPrintf(pOut,")"); + sqlite3TreeViewLine(pView, "%s", zUniOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } + sqlite3TreeViewPop(pView); } -#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ +#endif /* SQLITE_DEBUG */ -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) +#ifdef SQLITE_DEBUG /* ** Generate a human-readable explanation of an expression list. */ -void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){ +void sqlite3TreeViewExprList( + TreeView *pView, + const ExprList *pList, + u8 moreToFollow, + const char *zLabel +){ int i; - if( pList==0 || pList->nExpr==0 ){ - sqlite3ExplainPrintf(pOut, "(empty-list)"); - return; - }else if( pList->nExpr==1 ){ - sqlite3ExplainExpr(pOut, pList->a[0].pExpr); + pView = sqlite3TreeViewPush(pView, moreToFollow); + if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; + if( pList==0 ){ + sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ - sqlite3ExplainPush(pOut); + sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ - sqlite3ExplainPrintf(pOut, "item[%d] = ", i); - sqlite3ExplainPush(pOut); - sqlite3ExplainExpr(pOut, pList->a[i].pExpr); - sqlite3ExplainPop(pOut); - if( pList->a[i].zName ){ + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); +#if 0 + if( pList->a[i].zName ){ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); } if( pList->a[i].bSpanIsTab ){ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); } - if( inExpr-1 ){ - sqlite3ExplainNL(pOut); - } +#endif } - sqlite3ExplainPop(pOut); } + sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ diff --git a/src/main.c b/src/main.c index 231890de4b..dc17917796 100644 --- a/src/main.c +++ b/src/main.c @@ -3327,22 +3327,6 @@ int sqlite3_test_control(int op, ...){ break; } -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - /* sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, - ** sqlite3_stmt*,const char**); - ** - ** If compiled with SQLITE_ENABLE_TREE_EXPLAIN, each sqlite3_stmt holds - ** a string that describes the optimized parse tree. This test-control - ** returns a pointer to that string. - */ - case SQLITE_TESTCTRL_EXPLAIN_STMT: { - sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*); - const char **pzRet = va_arg(ap, const char**); - *pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt); - break; - } -#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); ** ** Set or clear a flag that indicates that the database file is always well- diff --git a/src/parse.y b/src/parse.y index 30a6dc5ff4..b47f531ee3 100644 --- a/src/parse.y +++ b/src/parse.y @@ -399,9 +399,6 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). { cmd ::= select(X). { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; sqlite3Select(pParse, X, &dest); - sqlite3ExplainBegin(pParse->pVdbe); - sqlite3ExplainSelect(pParse->pVdbe, X); - sqlite3ExplainFinish(pParse->pVdbe); sqlite3SelectDelete(pParse->db, X); } diff --git a/src/printf.c b/src/printf.c index 6d4b1b4ac7..92e8e100de 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1056,6 +1056,70 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ } #endif +#ifdef SQLITE_DEBUG +/************************************************************************* +** Routines for implementing the "TreeView" display of hierarchical +** data structures for debugging. +** +** The main entry points (coded elsewhere) are: +** sqlite3TreeViewExpr(0, pExpr, 0); +** sqlite3TreeViewExprList(0, pList, 0, 0); +** sqlite3TreeViewSelect(0, pSelect, 0); +** Insert calls to those routines while debugging in order to display +** a diagram of Expr, ExprList, and Select objects. +** +*/ +/* Add a new subitem to the tree. The moreToFollow flag indicates that this +** is not the last item in the tree. */ +TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ + if( p==0 ){ + p = sqlite3_malloc( sizeof(*p) ); + if( p==0 ) return 0; + memset(p, 0, sizeof(*p)); + }else{ + p->iLevel++; + } + assert( moreToFollow==0 || moreToFollow==1 ); + p->mLine &= ~(1<iLevel); + p->mLine |= moreToFollow << p->iLevel; + return p; +} +/* Finished with one layer of the tree */ +void sqlite3TreeViewPop(TreeView *p){ + if( p==0 ) return; + p->iLevel--; + if( p->iLevel<0 ) sqlite3_free(p); +} +/* Generate a single line of output for the tree, with a prefix that contains +** all the appropriate tree lines */ +void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ + va_list ap; + int i; + StrAccum acc; + char zBuf[500]; + sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); + acc.useMalloc = 0; + if( p ){ + for(i=0; iiLevel; i++){ + sqlite3StrAccumAppend(&acc, (p->mLine & (1<mLine & (1<selFlags & (SF_Distinct|SF_Aggregate) ){ - if( p->selFlags & SF_Distinct ){ - sqlite3ExplainPrintf(pVdbe, "DISTINCT "); - } - if( p->selFlags & SF_Aggregate ){ - sqlite3ExplainPrintf(pVdbe, "agg_flag "); - } - sqlite3ExplainNL(pVdbe); - sqlite3ExplainPrintf(pVdbe, " "); - } - sqlite3ExplainExprList(pVdbe, p->pEList); - sqlite3ExplainNL(pVdbe); +void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ + pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewLine(pView, "SELECT%s%s", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : "") + ); + sqlite3TreeViewExprList(pView, p->pEList, 1, "result-set"); if( p->pSrc && p->pSrc->nSrc ){ int i; - sqlite3ExplainPrintf(pVdbe, "FROM "); - sqlite3ExplainPush(pVdbe); + pView = sqlite3TreeViewPush(pView, 1); + sqlite3TreeViewLine(pView, "FROM"); for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; - sqlite3ExplainPrintf(pVdbe, "{%d,*} = ", pItem->iCursor); - if( pItem->pSelect ){ - sqlite3ExplainSelect(pVdbe, pItem->pSelect); - if( pItem->pTab ){ - sqlite3ExplainPrintf(pVdbe, " (tabname=%s)", pItem->pTab->zName); - } + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, zLine, sizeof(zLine), 0); + sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName); }else if( pItem->zName ){ - sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName); + sqlite3XPrintf(&x, 0, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); } if( pItem->zAlias ){ - sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias); + sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); } if( pItem->jointype & JT_LEFT ){ - sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN"); + sqlite3XPrintf(&x, 0, " LEFT-JOIN"); } - sqlite3ExplainNL(pVdbe); + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + sqlite3TreeViewPop(pView); } - sqlite3ExplainPop(pVdbe); + sqlite3TreeViewPop(pView); } if( p->pWhere ){ - sqlite3ExplainPrintf(pVdbe, "WHERE "); - sqlite3ExplainExpr(pVdbe, p->pWhere); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "WHERE", 1); + sqlite3TreeViewExpr(pView, p->pWhere, 0); + sqlite3TreeViewPop(pView); } if( p->pGroupBy ){ - sqlite3ExplainPrintf(pVdbe, "GROUPBY "); - sqlite3ExplainExprList(pVdbe, p->pGroupBy); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewExprList(pView, p->pGroupBy, 1, "GROUPBY"); } if( p->pHaving ){ - sqlite3ExplainPrintf(pVdbe, "HAVING "); - sqlite3ExplainExpr(pVdbe, p->pHaving); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "HAVING", 1); + sqlite3TreeViewExpr(pView, p->pHaving, 0); + sqlite3TreeViewPop(pView); } if( p->pOrderBy ){ - sqlite3ExplainPrintf(pVdbe, "ORDERBY "); - sqlite3ExplainExprList(pVdbe, p->pOrderBy); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewExprList(pView, p->pOrderBy, 1, "ORDERBY"); } if( p->pLimit ){ - sqlite3ExplainPrintf(pVdbe, "LIMIT "); - sqlite3ExplainExpr(pVdbe, p->pLimit); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "LIMIT", 1); + sqlite3TreeViewExpr(pView, p->pLimit, 0); + sqlite3TreeViewPop(pView); } if( p->pOffset ){ - sqlite3ExplainPrintf(pVdbe, "OFFSET "); - sqlite3ExplainExpr(pVdbe, p->pOffset); - sqlite3ExplainNL(pVdbe); + sqlite3TreeViewItem(pView, "OFFSET", 1); + sqlite3TreeViewExpr(pView, p->pOffset, 0); + sqlite3TreeViewPop(pView); } + if( p->pPrior ){ + const char *zOp = "UNION"; + switch( p->op ){ + case TK_ALL: zOp = "UNION ALL"; break; + case TK_INTERSECT: zOp = "INTERSECT"; break; + case TK_EXCEPT: zOp = "EXCEPT"; break; + } + sqlite3TreeViewItem(pView, zOp, 1); + sqlite3TreeViewSelect(pView, p->pPrior, 1); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewItem(pView, "END-SELECT", 0); + sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(pView); } -void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ - if( p==0 ){ - sqlite3ExplainPrintf(pVdbe, "(null-select)"); - return; - } - sqlite3ExplainPush(pVdbe); - while( p ){ - explainOneSelect(pVdbe, p); - p = p->pNext; - if( p==0 ) break; - sqlite3ExplainNL(pVdbe); - sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op)); - } - sqlite3ExplainPrintf(pVdbe, "END"); - sqlite3ExplainPop(pVdbe); -} - -/* End of the structure debug printing code -*****************************************************************************/ -#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ +#endif /* SQLITE_DEBUG */ diff --git a/src/shell.c b/src/shell.c index 9745e0ff25..cd4dadb08c 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1353,15 +1353,6 @@ static int shell_exec( sqlite3_free(zEQP); } - /* Output TESTCTRL_EXPLAIN text of requested */ - if( pArg && pArg->mode==MODE_Explain ){ - const char *zExplain = 0; - sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain); - if( zExplain && zExplain[0] ){ - fprintf(pArg->out, "%s", zExplain); - } - } - /* If the shell is currently in ".explain" mode, gather the extra ** data required to add indents to the output.*/ if( pArg && pArg->mode==MODE_Explain ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 8d7ac79ee7..ffb020058f 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6205,7 +6205,7 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 -#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b7e4d071ac..d637df782a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -469,6 +469,11 @@ #define MIN(A,B) ((A)<(B)?(A):(B)) #define MAX(A,B) ((A)>(B)?(A):(B)) +/* +** Swap two objects of type TYPE. +*/ +#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} + /* ** Check to see if this machine uses EBCDIC. (Yes, believe it or ** not, there are still machines out there that use EBCDIC.) @@ -855,6 +860,7 @@ typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; +typedef struct TreeView TreeView; typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; @@ -2923,6 +2929,17 @@ struct With { } a[1]; }; +#ifdef SQLITE_DEBUG +/* +** An instance of the TreeView object is used for printing the content of +** data structures on sqlite3DebugPrintf() using a tree-like view. +*/ +struct TreeView { + int iLevel; /* Which level of the tree we are on */ + u64 mLine; /* Mask of continuation lines to be drawn */ +}; +#endif /* SQLITE_DEBUG */ + /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. @@ -3087,25 +3104,14 @@ char *sqlite3MAppendf(sqlite3*,char*,const char*,...); void *sqlite3TestTextToPtr(const char*); #endif -/* Output formatting for SQLITE_TESTCTRL_EXPLAIN */ -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - void sqlite3ExplainBegin(Vdbe*); - void sqlite3ExplainPrintf(Vdbe*, const char*, ...); - void sqlite3ExplainNL(Vdbe*); - void sqlite3ExplainPush(Vdbe*); - void sqlite3ExplainPop(Vdbe*); - void sqlite3ExplainFinish(Vdbe*); - void sqlite3ExplainSelect(Vdbe*, Select*); - void sqlite3ExplainExpr(Vdbe*, Expr*); - void sqlite3ExplainExprList(Vdbe*, ExprList*); - const char *sqlite3VdbeExplanation(Vdbe*); -#else -# define sqlite3ExplainBegin(X) -# define sqlite3ExplainSelect(A,B) -# define sqlite3ExplainExpr(A,B) -# define sqlite3ExplainExprList(A,B) -# define sqlite3ExplainFinish(X) -# define sqlite3VdbeExplanation(X) 0 +#if defined(SQLITE_DEBUG) + TreeView *sqlite3TreeViewPush(TreeView*,u8); + void sqlite3TreeViewPop(TreeView*); + void sqlite3TreeViewLine(TreeView*, const char*, ...); + void sqlite3TreeViewItem(TreeView*, const char*, u8); + void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); + void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); + void sqlite3TreeViewSelect(TreeView*, const Select*, u8); #endif @@ -3128,6 +3134,7 @@ Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); void sqlite3ExprAssignVarNumber(Parse*, Expr*); void sqlite3ExprDelete(sqlite3*, Expr*); +void sqlite3ExprFactor(sqlite3*, Expr*, u8); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index f54c9c6d3b..aa1132e31c 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -360,10 +360,6 @@ struct Vdbe { i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ -#ifdef SQLITE_ENABLE_TREE_EXPLAIN - Explain *pExplain; /* The explainer */ - char *zExplain; /* Explanation of data structures */ -#endif VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 2562c63b62..33fa055369 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2678,10 +2678,6 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - sqlite3DbFree(db, p->zExplain); - sqlite3DbFree(db, p->pExplain); -#endif } /* diff --git a/src/vdbetrace.c b/src/vdbetrace.c index d27693450e..507c2f12fc 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -183,118 +183,3 @@ char *sqlite3VdbeExpandSql( } #endif /* #ifndef SQLITE_OMIT_TRACE */ - -/***************************************************************************** -** The following code implements the data-structure explaining logic -** for the Vdbe. -*/ - -#if defined(SQLITE_ENABLE_TREE_EXPLAIN) - -/* -** Allocate a new Explain object -*/ -void sqlite3ExplainBegin(Vdbe *pVdbe){ - if( pVdbe ){ - Explain *p; - sqlite3BeginBenignMalloc(); - p = (Explain *)sqlite3MallocZero( sizeof(Explain) ); - if( p ){ - p->pVdbe = pVdbe; - sqlite3_free(pVdbe->pExplain); - pVdbe->pExplain = p; - sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase), - SQLITE_MAX_LENGTH); - p->str.useMalloc = 2; - }else{ - sqlite3EndBenignMalloc(); - } - } -} - -/* -** Return true if the Explain ends with a new-line. -*/ -static int endsWithNL(Explain *p){ - return p && p->str.zText && p->str.nChar - && p->str.zText[p->str.nChar-1]=='\n'; -} - -/* -** Append text to the indentation -*/ -void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 ){ - va_list ap; - if( p->nIndent && endsWithNL(p) ){ - int n = p->nIndent; - if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent); - sqlite3AppendSpace(&p->str, p->aIndent[n-1]); - } - va_start(ap, zFormat); - sqlite3VXPrintf(&p->str, SQLITE_PRINTF_INTERNAL, zFormat, ap); - va_end(ap); - } -} - -/* -** Append a '\n' if there is not already one. -*/ -void sqlite3ExplainNL(Vdbe *pVdbe){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){ - sqlite3StrAccumAppend(&p->str, "\n", 1); - } -} - -/* -** Push a new indentation level. Subsequent lines will be indented -** so that they begin at the current cursor position. -*/ -void sqlite3ExplainPush(Vdbe *pVdbe){ - Explain *p; - if( pVdbe && (p = pVdbe->pExplain)!=0 ){ - if( p->str.zText && p->nIndentaIndent) ){ - const char *z = p->str.zText; - int i = p->str.nChar-1; - int x; - while( i>=0 && z[i]!='\n' ){ i--; } - x = (p->str.nChar - 1) - i; - if( p->nIndent && xaIndent[p->nIndent-1] ){ - x = p->aIndent[p->nIndent-1]; - } - p->aIndent[p->nIndent] = x; - } - p->nIndent++; - } -} - -/* -** Pop the indentation stack by one level. -*/ -void sqlite3ExplainPop(Vdbe *p){ - if( p && p->pExplain ) p->pExplain->nIndent--; -} - -/* -** Free the indentation structure -*/ -void sqlite3ExplainFinish(Vdbe *pVdbe){ - if( pVdbe && pVdbe->pExplain ){ - sqlite3_free(pVdbe->zExplain); - sqlite3ExplainNL(pVdbe); - pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str); - sqlite3_free(pVdbe->pExplain); - pVdbe->pExplain = 0; - sqlite3EndBenignMalloc(); - } -} - -/* -** Return the explanation of a virtual machine. -*/ -const char *sqlite3VdbeExplanation(Vdbe *pVdbe){ - return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0; -} -#endif /* defined(SQLITE_DEBUG) */ diff --git a/src/where.c b/src/where.c index 40f95acc49..9ece59f939 100644 --- a/src/where.c +++ b/src/where.c @@ -364,11 +364,6 @@ static int allowedOp(int op){ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL; } -/* -** Swap two objects of type TYPE. -*/ -#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} - /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". @@ -3761,22 +3756,6 @@ static Bitmask codeOneLoopStart( return pLevel->notReady; } -#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) -/* -** Generate "Explanation" text for a WhereTerm. -*/ -static void whereExplainTerm(Vdbe *v, WhereTerm *pTerm){ - char zType[4]; - memcpy(zType, "...", 4); - if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; - if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; - sqlite3ExplainPrintf(v, "%s ", zType); - sqlite3ExplainExpr(v, pTerm->pExpr); -} -#endif /* WHERETRACE_ENABLED && SQLITE_ENABLE_TREE_EXPLAIN */ - - #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes @@ -3819,27 +3798,6 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); -#ifdef SQLITE_ENABLE_TREE_EXPLAIN - /* If the 0x100 bit of wheretracing is set, then show all of the constraint - ** expressions in the WhereLoop.aLTerm[] array. - */ - if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ /* WHERETRACE 0x100 */ - int i; - Vdbe *v = pWInfo->pParse->pVdbe; - sqlite3ExplainBegin(v); - for(i=0; inLTerm; i++){ - WhereTerm *pTerm = p->aLTerm[i]; - if( pTerm==0 ) continue; - sqlite3ExplainPrintf(v, " (%d) #%-2d ", i+1, (int)(pTerm-pWC->a)); - sqlite3ExplainPush(v); - whereExplainTerm(v, pTerm); - sqlite3ExplainPop(v); - sqlite3ExplainNL(v); - } - sqlite3ExplainFinish(v); - sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v)); - } -#endif } #endif @@ -6172,23 +6130,6 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(0xffff,("*** Optimizer Start ***\n")); - /* Display all terms of the WHERE clause */ -#if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) - if( sqlite3WhereTrace & 0x100 ){ - int i; - Vdbe *v = pParse->pVdbe; - sqlite3ExplainBegin(v); - for(i=0; inTerm; i++){ - sqlite3ExplainPrintf(v, "#%-2d ", i); - sqlite3ExplainPush(v); - whereExplainTerm(v, &sWLB.pWC->a[i]); - sqlite3ExplainPop(v); - sqlite3ExplainNL(v); - } - sqlite3ExplainFinish(v); - sqlite3DebugPrintf("%s", sqlite3VdbeExplanation(v)); - } -#endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; From c90713d3d2feb19ca1d4f78e679a0dcc0b0e8948 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Sep 2014 13:46:49 +0000 Subject: [PATCH 4/8] Show tree diagrams of data structures in the debugging output when the 0x100 bit is set on sqlite3WhereTrace or sqlite3SelectTrace. FossilOrigin-Name: 92e0b4bd4d75e8b000586e51a07b3e181d9af20b --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 12 +++++++++++- src/where.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 642f78d5ff..4ef89a6d0a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sSQLITE_ENABLE_TREE_EXPLAIN\scompile-time\soption.\s\sAdd\salternative\ndebugging\sdisplay\sroutines:\ssqlite3TreeViewExpr(),\ssqlite3TreeViewExprList(),\nand\ssqlite3TreeViewSelect(). -D 2014-09-30T12:33:33.546 +C Show\stree\sdiagrams\sof\sdata\sstructures\sin\sthe\sdebugging\soutput\swhen\sthe\s0x100\nbit\sis\sset\son\ssqlite3WhereTrace\sor\ssqlite3SelectTrace. +D 2014-09-30T13:46:49.195 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -227,7 +227,7 @@ F src/printf.c 0db94d24f97b4e562e9da9d2ce85e8a69531daf6 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 373da54c2bd7e38993bc926a284bc05a53b01b8b +F src/select.c b5304314d9456850e755a106d64b378d60c62644 F src/shell.c 38f627b0885191357f55902a3ac199de90d79715 F src/sqlite.h.in 159f2cb9eef74b6c99aeeb4c071e7745835f04f6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad @@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 5a2c700f6f29da91ac633015d1378b91dcf237b6 +F src/where.c 5924c54986ec694e0b9e90eca506a930cfc71f6f F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7fb1626866c2f8dad84c7e6184824be3efd71ca2 -R f57511c6ad57aee6db1d51feabde515b +P 4ff51325d6b41d0c59e303b573700ec80c51d216 +R 1c3af6544b324d9bf4b577de17e6b173 U drh -Z d2ed6dec33496c4977b9e22861714f01 +Z e2f1f26ff32680c40b90d9645bff7468 diff --git a/manifest.uuid b/manifest.uuid index 246f7552d4..1357a3ed6c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4ff51325d6b41d0c59e303b573700ec80c51d216 \ No newline at end of file +92e0b4bd4d75e8b000586e51a07b3e181d9af20b \ No newline at end of file diff --git a/src/select.c b/src/select.c index 595926fa1a..4fb3860fb3 100644 --- a/src/select.c +++ b/src/select.c @@ -3642,6 +3642,13 @@ static int flattenSubquery( */ sqlite3SelectDelete(db, pSub1); +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + sqlite3DebugPrintf("After flattening:\n"); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ @@ -4649,7 +4656,10 @@ int sqlite3Select( memset(&sAggInfo, 0, sizeof(sAggInfo)); #if SELECTTRACE_ENABLED pParse->nSelectIndent++; - SELECTTRACE(1,pParse,p, ("begin processing\n")); + SELECTTRACE(1,pParse,p, ("begin processing:\n")); + if( sqlite3SelectTrace & 0x100 ){ + sqlite3TreeViewSelect(0, p, 0); + } #endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); diff --git a/src/where.c b/src/where.c index 9ece59f939..e2020ca06e 100644 --- a/src/where.c +++ b/src/where.c @@ -3756,6 +3756,23 @@ static Bitmask codeOneLoopStart( return pLevel->notReady; } +#ifdef WHERETRACE_ENABLED +/* +** Print the content of a WhereTerm object +*/ +static void whereTermPrint(WhereTerm *pTerm, int iTerm){ + char zType[4]; + memcpy(zType, "...", 4); + if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; + if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n", iTerm, + pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + pTerm->eOperator); + sqlite3TreeViewExpr(0, pTerm->pExpr, 0); +} +#endif + #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes @@ -3798,6 +3815,14 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); + if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ + int i; + for(i=0; inLTerm; i++){ + WhereTerm *pTerm = p->aLTerm[i]; + if( pTerm==0 ) continue; + whereTermPrint(pTerm, i); + } + } } #endif @@ -6130,6 +6155,16 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(0xffff,("*** Optimizer Start ***\n")); +#if defined(WHERETRACE_ENABLED) + /* Display all terms of the WHERE clause */ + if( sqlite3WhereTrace & 0x100 ){ + int i; + for(i=0; inTerm; i++){ + whereTermPrint(&sWLB.pWC->a[i], i); + } + } +#endif + if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; From 5265149c0d5eed40f7a4858aeaf73776da69f78b Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Sep 2014 14:14:19 +0000 Subject: [PATCH 5/8] Enhanced debug output for OR-logic in the query loop optimizer. FossilOrigin-Name: 2e375eae473e4a9f2e7870d59e22ba39051ecbce --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 4ef89a6d0a..1c128cf92e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Show\stree\sdiagrams\sof\sdata\sstructures\sin\sthe\sdebugging\soutput\swhen\sthe\s0x100\nbit\sis\sset\son\ssqlite3WhereTrace\sor\ssqlite3SelectTrace. -D 2014-09-30T13:46:49.195 +C Enhanced\sdebug\soutput\sfor\sOR-logic\sin\sthe\squery\sloop\soptimizer. +D 2014-09-30T14:14:19.732 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 5924c54986ec694e0b9e90eca506a930cfc71f6f +F src/where.c 1d22623f4cc01ad34f4660daae77826550033c58 F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 4ff51325d6b41d0c59e303b573700ec80c51d216 -R 1c3af6544b324d9bf4b577de17e6b173 +P 92e0b4bd4d75e8b000586e51a07b3e181d9af20b +R ad11511f8b3c0903ec6511fb5cd0e86b U drh -Z e2f1f26ff32680c40b90d9645bff7468 +Z 55bafa322513796a5af056ecffd49293 diff --git a/manifest.uuid b/manifest.uuid index 1357a3ed6c..e80a6f2549 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -92e0b4bd4d75e8b000586e51a07b3e181d9af20b \ No newline at end of file +2e375eae473e4a9f2e7870d59e22ba39051ecbce \ No newline at end of file diff --git a/src/where.c b/src/where.c index e2020ca06e..3cde23be49 100644 --- a/src/where.c +++ b/src/where.c @@ -5037,6 +5037,12 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ continue; } sCur.n = 0; +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x200 ){ + sqlite3DebugPrintf("OR-term %d:\n",(int)(pOrTerm-pOrWC->a)); + sqlite3TreeViewExpr(0, pOrTerm->pExpr, 0); + } +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mExtra); From 0a99ba3bc86ceecde75b8b3b8ed8a689183d24b8 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Sep 2014 17:03:35 +0000 Subject: [PATCH 6/8] Further enhancements to the "wheretrace" debugging output. FossilOrigin-Name: 670993eb8113f386cb2cb8b1507917f6da3b4d98 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 38 +++++++++++++++++++++++--------------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index 1c128cf92e..2a2a4b68cc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhanced\sdebug\soutput\sfor\sOR-logic\sin\sthe\squery\sloop\soptimizer. -D 2014-09-30T14:14:19.732 +C Further\senhancements\sto\sthe\s"wheretrace"\sdebugging\soutput. +D 2014-09-30T17:03:35.868 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 1d22623f4cc01ad34f4660daae77826550033c58 +F src/where.c a459332dc671138a6997904850ead36d83bfb8e0 F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 92e0b4bd4d75e8b000586e51a07b3e181d9af20b -R ad11511f8b3c0903ec6511fb5cd0e86b +P 2e375eae473e4a9f2e7870d59e22ba39051ecbce +R c96a5d9652d91d70c0e54df21653ce3e U drh -Z 55bafa322513796a5af056ecffd49293 +Z 7116ce524f0c5c15e04b43bf011b61b4 diff --git a/manifest.uuid b/manifest.uuid index e80a6f2549..42170fe6be 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2e375eae473e4a9f2e7870d59e22ba39051ecbce \ No newline at end of file +670993eb8113f386cb2cb8b1507917f6da3b4d98 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3cde23be49..bc7e58a7fe 100644 --- a/src/where.c +++ b/src/where.c @@ -3537,6 +3537,7 @@ static Bitmask codeOneLoopStart( pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ + WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); @@ -3761,15 +3762,19 @@ static Bitmask codeOneLoopStart( ** Print the content of a WhereTerm object */ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ - char zType[4]; - memcpy(zType, "...", 4); - if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; - if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; - sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n", iTerm, - pTerm, zType, pTerm->leftCursor, pTerm->truthProb, - pTerm->eOperator); - sqlite3TreeViewExpr(0, pTerm->pExpr, 0); + if( pTerm==0 ){ + sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); + }else{ + char zType[4]; + memcpy(zType, "...", 4); + if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; + if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n", + iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + pTerm->eOperator); + sqlite3TreeViewExpr(0, pTerm->pExpr, 0); + } } #endif @@ -3818,9 +3823,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ int i; for(i=0; inLTerm; i++){ - WhereTerm *pTerm = p->aLTerm[i]; - if( pTerm==0 ) continue; - whereTermPrint(pTerm, i); + whereTermPrint(p->aLTerm[i], i); } } } @@ -5023,6 +5026,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ sSubBuild.pOrderBy = 0; sSubBuild.pOrSet = &sCur; + WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); for(pOrTerm=pOrWC->a; pOrTermeOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; @@ -5038,9 +5042,12 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ } sCur.n = 0; #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace & 0x200 ){ - sqlite3DebugPrintf("OR-term %d:\n",(int)(pOrTerm-pOrWC->a)); - sqlite3TreeViewExpr(0, pOrTerm->pExpr, 0); + WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", + (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); + if( sqlite3WhereTrace & 0x400 ){ + for(i=0; inTerm; i++){ + whereTermPrint(&sSubBuild.pWC->a[i], i); + } } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -5095,6 +5102,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } + WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm)); } } return rc; From 36be4c49e42951cc38894244dd8b591803c6bd3f Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Sep 2014 17:31:23 +0000 Subject: [PATCH 7/8] Enable the query planner to deal with WHERE clauses that have OR terms nested within AND terms that are nested within OR terms. Also remove an unused function declaration. FossilOrigin-Name: b6b289182f6590288ebc7b9efbcb29b6b4480538 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 3 +-- src/where.c | 9 ++++++--- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 2a2a4b68cc..84f200ceb8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\senhancements\sto\sthe\s"wheretrace"\sdebugging\soutput. -D 2014-09-30T17:03:35.868 +C Enable\sthe\squery\splanner\sto\sdeal\swith\sWHERE\sclauses\sthat\shave\sOR\sterms\nnested\swithin\sAND\sterms\sthat\sare\snested\swithin\sOR\sterms.\s\sAlso\sremove\san\nunused\sfunction\sdeclaration. +D 2014-09-30T17:31:23.408 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -232,7 +232,7 @@ F src/shell.c 38f627b0885191357f55902a3ac199de90d79715 F src/sqlite.h.in 159f2cb9eef74b6c99aeeb4c071e7745835f04f6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 8242d04760ec2a943a152eba2a006ea121a3eafd +F src/sqliteInt.h 254797e62264c53184172d98a491aa2b8cd4ad88 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb @@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c a459332dc671138a6997904850ead36d83bfb8e0 +F src/where.c 2f42fe0d19303e0f5ce29aff3afbd3e43cbd6efb F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 2e375eae473e4a9f2e7870d59e22ba39051ecbce -R c96a5d9652d91d70c0e54df21653ce3e +P 670993eb8113f386cb2cb8b1507917f6da3b4d98 +R 1a06ccbab92129ac2bab7054741ffba8 U drh -Z 7116ce524f0c5c15e04b43bf011b61b4 +Z 36668dfa98188ac65878a88086fca9b9 diff --git a/manifest.uuid b/manifest.uuid index 42170fe6be..9e6ff3561c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -670993eb8113f386cb2cb8b1507917f6da3b4d98 \ No newline at end of file +b6b289182f6590288ebc7b9efbcb29b6b4480538 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d637df782a..35cadcdbc0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2231,7 +2231,7 @@ struct SrcList { #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ -#define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ + /* 0x0080 // not currently used */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ @@ -3134,7 +3134,6 @@ Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); void sqlite3ExprAssignVarNumber(Parse*, Expr*); void sqlite3ExprDelete(sqlite3*, Expr*); -void sqlite3ExprFactor(sqlite3*, Expr*, u8); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); diff --git a/src/where.c b/src/where.c index bc7e58a7fe..8974895c45 100644 --- a/src/where.c +++ b/src/where.c @@ -3524,8 +3524,9 @@ static Bitmask codeOneLoopStart( ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | - WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY; + wctrlFlags = WHERE_OMIT_OPEN_CLOSE + | WHERE_FORCE_TABLE + | WHERE_ONETABLE_ONLY; for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ @@ -5005,7 +5006,6 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ struct SrcList_item *pItem; pWC = pBuilder->pWC; - if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); @@ -5058,6 +5058,9 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ { rc = whereLoopAddBtree(&sSubBuild, mExtra); } + if( rc==SQLITE_OK ){ + rc = whereLoopAddOr(&sSubBuild, mExtra); + } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ sSum.n = 0; From b08cd3f34517bbb7a7cd8c745b2c51fe5bd09082 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Sep 2014 19:04:41 +0000 Subject: [PATCH 8/8] Improvements to the new syntax-tree output routines: Omit the "END SELECT" mark and instead terminate the graph at the last item. Increase the maximum tree depth to 100. FossilOrigin-Name: 5ce05757aac80b99c3b2141cd301809f8e28e661 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/printf.c | 9 ++++----- src/select.c | 31 +++++++++++++++++++------------ src/sqliteInt.h | 2 +- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 84f200ceb8..4f1b85c92d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enable\sthe\squery\splanner\sto\sdeal\swith\sWHERE\sclauses\sthat\shave\sOR\sterms\nnested\swithin\sAND\sterms\sthat\sare\snested\swithin\sOR\sterms.\s\sAlso\sremove\san\nunused\sfunction\sdeclaration. -D 2014-09-30T17:31:23.408 +C Improvements\sto\sthe\snew\ssyntax-tree\soutput\sroutines:\s\sOmit\sthe\s"END\sSELECT"\nmark\sand\sinstead\sterminate\sthe\sgraph\sat\sthe\slast\sitem.\s\sIncrease\sthe\smaximum\ntree\sdepth\sto\s100. +D 2014-09-30T19:04:41.396 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -223,16 +223,16 @@ F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c dab8ab930d4a73b99768d881185994f34b80ecaa F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196 -F src/printf.c 0db94d24f97b4e562e9da9d2ce85e8a69531daf6 +F src/printf.c 6b79bbd063dcbadca4cf617a4cde255bcc13ea64 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c b5304314d9456850e755a106d64b378d60c62644 +F src/select.c f11533162b57ed5ed37f549add34cbcdf51f6712 F src/shell.c 38f627b0885191357f55902a3ac199de90d79715 F src/sqlite.h.in 159f2cb9eef74b6c99aeeb4c071e7745835f04f6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 254797e62264c53184172d98a491aa2b8cd4ad88 +F src/sqliteInt.h 5a430c5443717d7c5e2c224f9dcc2534348dc3f6 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb @@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 670993eb8113f386cb2cb8b1507917f6da3b4d98 -R 1a06ccbab92129ac2bab7054741ffba8 +P b6b289182f6590288ebc7b9efbcb29b6b4480538 +R cfd4c6e5c7836f29218c39baf2122e42 U drh -Z 36668dfa98188ac65878a88086fca9b9 +Z 3bfcd52f8fd5ecba827fd0c1ccf2615c diff --git a/manifest.uuid b/manifest.uuid index 9e6ff3561c..f78de65f58 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b6b289182f6590288ebc7b9efbcb29b6b4480538 \ No newline at end of file +5ce05757aac80b99c3b2141cd301809f8e28e661 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 92e8e100de..c0b3c70f6b 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1080,8 +1080,7 @@ TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ p->iLevel++; } assert( moreToFollow==0 || moreToFollow==1 ); - p->mLine &= ~(1<iLevel); - p->mLine |= moreToFollow << p->iLevel; + if( p->iLevelbLine) ) p->bLine[p->iLevel] = moreToFollow; return p; } /* Finished with one layer of the tree */ @@ -1100,10 +1099,10 @@ void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); acc.useMalloc = 0; if( p ){ - for(i=0; iiLevel; i++){ - sqlite3StrAccumAppend(&acc, (p->mLine & (1<iLevel && ibLine)-1; i++){ + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); } - sqlite3StrAccumAppend(&acc, (p->mLine & (1<bLine[i] ? "|-- " : "'-- ", 4); } va_start(ap, zFormat); sqlite3VXPrintf(&acc, 0, zFormat, ap); diff --git a/src/select.c b/src/select.c index 4fb3860fb3..411bca0df4 100644 --- a/src/select.c +++ b/src/select.c @@ -5432,15 +5432,24 @@ select_end: ** Generate a human-readable description of a the Select object. */ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ + int n = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); sqlite3TreeViewLine(pView, "SELECT%s%s", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : "") ); - sqlite3TreeViewExprList(pView, p->pEList, 1, "result-set"); + if( p->pSrc && p->pSrc->nSrc ) n++; + if( p->pWhere ) n++; + if( p->pGroupBy ) n++; + if( p->pHaving ) n++; + if( p->pOrderBy ) n++; + if( p->pLimit ) n++; + if( p->pOffset ) n++; + if( p->pPrior ) n++; + sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); if( p->pSrc && p->pSrc->nSrc ){ int i; - pView = sqlite3TreeViewPush(pView, 1); + pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; @@ -5472,28 +5481,28 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ sqlite3TreeViewPop(pView); } if( p->pWhere ){ - sqlite3TreeViewItem(pView, "WHERE", 1); + sqlite3TreeViewItem(pView, "WHERE", (n--)>0); sqlite3TreeViewExpr(pView, p->pWhere, 0); sqlite3TreeViewPop(pView); } if( p->pGroupBy ){ - sqlite3TreeViewExprList(pView, p->pGroupBy, 1, "GROUPBY"); + sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); } if( p->pHaving ){ - sqlite3TreeViewItem(pView, "HAVING", 1); + sqlite3TreeViewItem(pView, "HAVING", (n--)>0); sqlite3TreeViewExpr(pView, p->pHaving, 0); sqlite3TreeViewPop(pView); } if( p->pOrderBy ){ - sqlite3TreeViewExprList(pView, p->pOrderBy, 1, "ORDERBY"); + sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ - sqlite3TreeViewItem(pView, "LIMIT", 1); + sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit, 0); sqlite3TreeViewPop(pView); } if( p->pOffset ){ - sqlite3TreeViewItem(pView, "OFFSET", 1); + sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); sqlite3TreeViewExpr(pView, p->pOffset, 0); sqlite3TreeViewPop(pView); } @@ -5504,12 +5513,10 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ case TK_INTERSECT: zOp = "INTERSECT"; break; case TK_EXCEPT: zOp = "EXCEPT"; break; } - sqlite3TreeViewItem(pView, zOp, 1); - sqlite3TreeViewSelect(pView, p->pPrior, 1); + sqlite3TreeViewItem(pView, zOp, (n--)>0); + sqlite3TreeViewSelect(pView, p->pPrior, 0); sqlite3TreeViewPop(pView); } - sqlite3TreeViewItem(pView, "END-SELECT", 0); - sqlite3TreeViewPop(pView); sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 35cadcdbc0..695b63d753 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2936,7 +2936,7 @@ struct With { */ struct TreeView { int iLevel; /* Which level of the tree we are on */ - u64 mLine; /* Mask of continuation lines to be drawn */ + u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */ }; #endif /* SQLITE_DEBUG */