aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/expert/expert1.test6
-rw-r--r--manifest50
-rw-r--r--manifest.uuid2
-rw-r--r--src/expr.c154
-rw-r--r--src/sqliteInt.h9
-rw-r--r--src/vdbe.c3
-rw-r--r--src/vdbe.h7
-rw-r--r--src/vdbeaux.c19
-rw-r--r--src/where.c3
-rw-r--r--src/whereInt.h3
-rw-r--r--src/wherecode.c29
-rw-r--r--test/autoindex1.test8
-rw-r--r--test/bestindex3.test18
-rw-r--r--test/cost.test21
-rw-r--r--test/eqp.test28
-rw-r--r--test/join5.test6
-rw-r--r--test/rowvalue4.test4
-rw-r--r--test/tkt-80ba201079.test2
-rw-r--r--test/where7.test6
-rw-r--r--test/where9.test18
-rw-r--r--test/whereI.test12
-rw-r--r--test/with3.test2
22 files changed, 268 insertions, 142 deletions
diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test
index 2b4668340..912c074c6 100644
--- a/ext/expert/expert1.test
+++ b/ext/expert/expert1.test
@@ -243,8 +243,10 @@ do_setup_rec_test $tn.12.1 {
CREATE INDEX t7_idx_00000062 ON t7(b);
CREATE INDEX t7_idx_00000061 ON t7(a);
MULTI-INDEX OR
- SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
- SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
+ INDEX 1
+ SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
+ INDEX 2
+ SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
}
# rowid terms.
diff --git a/manifest b/manifest
index c50fdb0ad..edcf41514 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Small\schanges\sto\sthe\sOP_OpenEphemeral\sopcode\sto\simprove\stestability.
-D 2018-12-31T17:58:05.349
+C Merge\senhancements\sand\sbug\sfixes\sfrom\strunk.
+D 2018-12-31T18:30:41.155
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in d8b254f8bb81bab43c340d70d17dc3babab40fcc8a348c8255881f780a45fee6
@@ -46,7 +46,7 @@ F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
-F ext/expert/expert1.test 333d037021c901322f9afc4a5687648ea23d56f1a0a079358a390664babf01be
+F ext/expert/expert1.test 358e416877a5693fb99d5514f5d88452b5239dc2196b74e0e926718502faef6d
F ext/expert/sqlite3expert.c 3da865f2286433588260f41e796422c611bceaca3a0bbf9139a619cf7d062c19
F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
@@ -462,7 +462,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
F src/dbstat.c 3c8bd4e77f0244fd2bd7cc90acf116ad2f8e82d70e536637f35ac2bc99b726f9
F src/delete.c 209cd8345b15d1843abeff2d91a6d9c765cf32ff4abcb24411c38fe08e18baab
-F src/expr.c 2c28e3bcb8de699e5e0da2efcae50aed2a64d02b50ecf9920d27393f3eef4629
+F src/expr.c 2871554cc9be8d0da0d481dbf20ee814fc6990ce01f885a1bb6af0d1f552085e
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c aaf28be73ab21e1e8bf4ac6b94269ebc8c93238d1e6997cb44b527b622e8ae6f
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
@@ -515,7 +515,7 @@ F src/shell.c.in 207da30342db0b6fac8b2487abd60b059a5ea80cc9494bd1db76a1dd4aae7cc
F src/sqlite.h.in b54cd42d2f3b739a00de540cafe2dcd0de3b8e1748a2db33a68def487e9e602f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
-F src/sqliteInt.h 802b760a21fadfe015e0c33b34882e5bb6953a70b36c33012c609a9bb5980012
+F src/sqliteInt.h 2ed8b7c854c9c1c300c3f17bbdff926c3022665146a3125e48bdf8ae2351db70
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -581,11 +581,11 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
F src/vacuum.c 3ffe64ecfc94b7528c5d7bdb1c3a19d72fec63f2aa846e3b90f8de5dbbddf5aa
-F src/vdbe.c 5c3d05e74f3fd43725e2a1a186b2c1021c5d68c6ac3364ca7e120740b1eab168
-F src/vdbe.h b61a6f4f23ca4f5e789f4fc9d55acd4570d50d3288457651e501d839f5167c1f
+F src/vdbe.c 0be19a62da20276746ef51828d581a8e7a07dc327d1b26edeffa5f7f7d9d05b0
+F src/vdbe.h d64fe28f20a67feffb820c20bb1bc6f8d365c6b410d66e7eb9a7192e839316b3
F src/vdbeInt.h a76d5eed62c76bcd8de7afd3147fac1bc40c5a870582664bcd7d071ef437c37f
F src/vdbeapi.c 57a2d794a8833f269b878dbc24e955369bdb379af6c4e93ebc5ce1a20fa3daf4
-F src/vdbeaux.c 1b47c59c0ec59ea138a8bca10e7810059ae6dfa5da3b249be7d31f08953527ab
+F src/vdbeaux.c b230f12642040c5ede19f092d9ad7510f75add84888e66a00108948dec574fd2
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 7b3305bc4a5139f4536ac9b5f61da0f915e49d2e3fdfa87dfdfa9d7aba8bc1e9
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
@@ -595,9 +595,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
-F src/where.c ebdd593773608097a2ef55c061247b4ccd00aab177d2de9693069bbf1a6e6c84
-F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
-F src/wherecode.c f9f790fc1c7775447949ca8182a9e142d9f5b3428bf0610774fab672083d7c23
+F src/where.c 981412c27abb9378d3024eae6f3040abd3c16db722f5ef8a7d613141ea2aea78
+F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
+F src/wherecode.c 89d2ec668aec884dfa7ac500c6744e42ec0590fcd72fb740a8b48326a8412811
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
F src/window.c f4a9ac8396395a9e281e182dd32fc9b3b19f6762a9eef468137369def3ad9a2c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -654,7 +654,7 @@ F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
F test/autoinc.test 381f494fefa90acd999933829e2934efb6b40906db9d6a39e822e3f7b4c8bf61
-F test/autoindex1.test a09958fa756129af10b6582bcbf3cbdf11e305e027b393f393caef801159dee0
+F test/autoindex1.test 96185415f5faacd5b8d7a7f505efddd5abb1f111d58338e9c0b1dc40b87cd3cc
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
F test/autoindex3.test 2dd997d6590438b53e4f715f9278aa91c9299cf3f81246a0915269c35beb790e
F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf
@@ -674,7 +674,7 @@ F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
F test/bestindex1.test 852170bddbb21daa121fabcc274640ff83d7d8705912e8b5fe7ed2c5a9a9224a
F test/bestindex2.test 9a0ccd320b6525eec3a706aae6cdab7e1b7b5abca75027e39f39f755e76e5928
-F test/bestindex3.test 001788a114ad96d81d5154fe77c7f1e26e84b3a2b5635ca29e4f96f6decc534e
+F test/bestindex3.test 7622e792ff2da16d262d3cea6ad914591ac4806d57ed128e6c940b7920b47b84
F test/bestindex4.test 038e3d0789332f3f1d61474f9bbc9c6d08c6bd1783a978f31f38ad82688de601
F test/bestindex5.test 67c1166131bb59f9e47c00118f7d432ca5491e6cae6ca3f87ca9db20103a78f9
F test/bestindex6.test d856a9bb63d927493575823eed44053bc36251e241aa364e54d0f2a2d302e1d4
@@ -752,7 +752,7 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
F test/corruptK.test 5ef338c560ca4dfb7360828da16f1829be4deba3b378cafdc7a1cdaf027eb5c4
-F test/cost.test b37db8a10d467a69e71a9f3d40bbb266c2f587742b37c6912f6e3f7185a0e216
+F test/cost.test 51f4fcaae6e78ad5a57096831259ed6c760e2ac6876836e91c00030fad385b34
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
F test/countofview.test e3d4cd6900e4e4f074968ab24b8b87d3671cd624961bef40fd3a6b8f574343cf
F test/coveridxscan.test 5ec98719a2e2914e8908dc75f7247d9b54a26df04625f846ac7900d5483f7296
@@ -825,7 +825,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
-F test/eqp.test fc00ad1a7f5b90bf1bbccbf877ae9abef8bf5c7896174830d438c8f91a6ead88
+F test/eqp.test 84879b63e3110552bf8ce648a3507dc3ceb72109ecec83c2aef0db37a27f6382
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
F test/exclusive.test 1206b87e192497d78c7f35552e86a9d05421498da300fb1cce5ca5351ccde3c3
@@ -1053,7 +1053,7 @@ F test/join.test 2ad9d7fe10e0cc06bc7803c22e5533be11cdadbc592f5f95d789a873b57a5a6
F test/join2.test 10f7047e723ebd68b2f47189be8eed20451a6f665d8bf46f1774c640d1062417
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
-F test/join5.test 5a2da0c3ea852a7063d3e72fc7d5a04a6de5ef6e6d85092582f69033f7459adc
+F test/join5.test 1df0a9b94f34a6c40c7f708f550dcb1cb80109f0ed774dba5a95915fbfbb6bc9
F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
@@ -1225,7 +1225,7 @@ F test/rowid.test 5b7509f384f4f6fae1af3c8c104c8ca299fea18d
F test/rowvalue.test b8680f07d19c8c5223b808bba998faffcec6d505f5689ff6070280119173bb51
F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b
F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256
-F test/rowvalue4.test 2b20468da3775aba971caf3158e9696a4d99c69a7623fb495f332a596daebbee
+F test/rowvalue4.test 02e35f7762371c2f57ebd856aa056eac56cb27ef7715a0bb31eac1895a745356
F test/rowvalue5.test c81c7d8cf36711ab37675ad7376084ae2a359cb6
F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087
F test/rowvalue7.test 5d06ff19d9e6969e574a2e662a531dd0c67801a8
@@ -1403,7 +1403,7 @@ F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
F test/tkt-78e04e52ea.test 1b5be1bac961833a9fd70fe50738cb4064822c61f82c54f7d488435ec806ea62
F test/tkt-7a31705a7e6.test 9e9c057b6a9497c8f7ba7b16871029414ccf6550e7345d9085d6d71c9a56bb6f
F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18
-F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
+F test/tkt-80ba201079.test 75d22bbfd118025c9504b025679a6840f7518b2947268ecdce14b7af1b7dd7f3
F test/tkt-80e031a00f.test 9ee36348b761bf7c14261e002b75a4c0d5a04d4c
F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
@@ -1642,9 +1642,9 @@ F test/where3.test 2341a294e17193a6b1699ea7f192124a5286ca6acfcc3f4b06d16c931fbcd
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
-F test/where7.test e579da972eb3372edc9de850efc221848c763f9e4feafc8426d84a4453b92b23
+F test/where7.test 75722434c486ac9e74718caa6cce234f45ba34c0b6c0f9555b29eb8bb5f6ade1
F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f
-F test/where9.test ad2ddb339d10d324763c3da60502b8631f15a2397b869192fbd4e82f40e167d3
+F test/where9.test 4fb43ad451758d9535693e110d4398fb6a6e3e153dc57bba5e61f884566c725f
F test/whereA.test 6c6a420ca7d313242f9b1bd471dc80e4d0f8323700ba9c78df0bb843d4daa3b4
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
@@ -1653,7 +1653,7 @@ F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 3d9412b1199d3e2bed34fcb76b4c48d0bf4df95d27e3f8dd27b6f8b4716d0d89
F test/whereG.test 0158783235a6dd82fc0e37652b8522b186b9510594ac0a4bff0c4101b4396a52
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
-F test/whereI.test b7769ee8dbefd987fb266715fee887f05f9ff180016b06fca7fa402df739193b
+F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
F test/whereL.test 0a19fc44cd1122040f56c934f1b14d0ca85bde28f270268a428dd9796ea0634c
@@ -1678,7 +1678,7 @@ F test/window6.test 5eae4ae7a590ccf1e605880969ca0bad3955616ac91cad3031baea38748b
F test/windowfault.test 12ceb6bbb355d13e8fcd88c5731a57256dfdf77b9a7ae20842a76fcd4623df5b
F test/with1.test 64fcb1a81685b8a67da61af260a2d8f2afbf3530d39fa451831faf5a9ba6ea45
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
-F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
+F test/with3.test 8d26920c88283e0a473ceebd3451554922108ce7b2a6a1157c47eb0a7011212c
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test 533add9100255e4cc430d371b3ecfb79f11f956b86c3a1b9d34413bf8e482d8f
@@ -1795,7 +1795,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 4678cb1044f0b4dc813e48f3bd0f85240a66e2ecf8763280d66726cc031c93a7
-R 19d15b45d6c2a613a85a1505b62bf5ca
+P 0f1b9ff9e1e6f13e03045fcb7d0907227085054f9eb0b0b8471fb26b0094b13a f856676c8438dbf52d299e78f6dd6148d929755dc05cdcabafd17d9a86439435
+R 3d5a1ea78142c180da83ac42547c771a
U drh
-Z fe2d10d5f399fae02e225088d4349735
+Z 030784c6ac18d793a85199580bd539ae
diff --git a/manifest.uuid b/manifest.uuid
index 2ecc2fe11..6c1dca9c2 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-f856676c8438dbf52d299e78f6dd6148d929755dc05cdcabafd17d9a86439435 \ No newline at end of file
+9fb646f29c05bca5f677a2c7c4f45c36bfe0a0c6a88cb7968b4a0459bdd63bb2 \ No newline at end of file
diff --git a/src/expr.c b/src/expr.c
index 1313b348e..a1f6c216d 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2350,7 +2350,8 @@ int sqlite3FindInIndex(
Expr *pX, /* The right-hand side (RHS) of the IN operator */
u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
int *prRhsHasNull, /* Register holding NULL status. See notes */
- int *aiMap /* Mapping from Index fields to RHS fields */
+ int *aiMap, /* Mapping from Index fields to RHS fields */
+ int *piTab /* OUT: index to use */
){
Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */
@@ -2543,13 +2544,11 @@ int sqlite3FindInIndex(
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
}
assert( pX->op==TK_IN );
- sqlite3CodeRhsOfIN(pParse, pX, eType==IN_INDEX_ROWID);
+ sqlite3CodeRhsOfIN(pParse, pX, iTab, eType==IN_INDEX_ROWID);
if( rMayHaveNull ){
- sqlite3SetHasNullFlag(v, pX->iTable, rMayHaveNull);
+ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull);
}
pParse->nQueryLoop = savedNQueryLoop;
- }else{
- pX->iTable = iTab;
}
if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
@@ -2557,6 +2556,7 @@ int sqlite3FindInIndex(
n = sqlite3ExprVectorSize(pX->pLeft);
for(i=0; i<n; i++) aiMap[i] = i;
}
+ *piTab = iTab;
return eType;
}
#endif
@@ -2639,7 +2639,11 @@ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
** x IN (4,5,11) -- IN operator with list on right-hand side
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
**
-** The pExpr parameter is the IN operator.
+** The pExpr parameter is the IN operator. The cursor number for the
+** constructed ephermeral table is returned. The first time the ephemeral
+** table is computed, the cursor number is also stored in pExpr->iTable,
+** however the cursor number returned might not be the same, as it might
+** have been duplicated using OP_OpenDup.
**
** If parameter isRowid is non-zero, then LHS of the IN operator is guaranteed
** to be a non-null integer. In this case, the ephemeral table can be an
@@ -2658,30 +2662,55 @@ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
void sqlite3CodeRhsOfIN(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The IN operator */
+ int iTab, /* Use this cursor number */
int isRowid /* If true, LHS is a rowid */
){
- int jmpIfDynamic = -1; /* One-time test address */
+ int addrOnce = 0; /* Address of the OP_Once instruction at top */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */
int nVal; /* Size of vector pLeft */
Vdbe *v; /* The prepared statement under construction */
- v = sqlite3GetVdbe(pParse);
+ v = pParse->pVdbe;
assert( v!=0 );
- /* The evaluation of the RHS of IN operator must be repeated every time it
+ /* The evaluation of the IN must be repeated every time it
** is encountered if any of the following is true:
**
** * The right-hand side is a correlated subquery
** * The right-hand side is an expression list containing variables
** * We are inside a trigger
**
- ** If all of the above are false, then we can run this code just once
- ** save the results, and reuse the same result on subsequent invocations.
+ ** If all of the above are false, then we can compute the RHS just once
+ ** and reuse it many names.
*/
- if( !ExprHasProperty(pExpr, EP_VarSelect) ){
- jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){
+ /* Reuse of the RHS is allowed */
+ /* If this routine has already been coded, but the previous code
+ ** might not have been invoked yet, so invoke it now as a subroutine.
+ */
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ int addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
+ pExpr->x.pSelect->selId));
+ }
+ sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
+ pExpr->y.sub.iAddr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
+ sqlite3VdbeJumpHere(v, addr);
+ return;
+ }
+
+ /* Begin coding the subroutine */
+ ExprSetProperty(pExpr, EP_Subrtn);
+ pExpr->y.sub.regReturn = ++pParse->nMem;
+ pExpr->y.sub.iAddr =
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
+ VdbeComment((v, "return address"));
+
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
/* Check to see if this is a vector IN operator */
@@ -2692,9 +2721,16 @@ void sqlite3CodeRhsOfIN(
/* Construct the ephemeral table that will contain the content of
** RHS of the IN operator.
*/
- pExpr->iTable = pParse->nTab++;
+ pExpr->iTable = iTab;
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral,
pExpr->iTable, (isRowid?0:nVal));
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId));
+ }else{
+ VdbeComment((v, "RHS of IN operator"));
+ }
+#endif
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
@@ -2706,8 +2742,8 @@ void sqlite3CodeRhsOfIN(
Select *pSelect = pExpr->x.pSelect;
ExprList *pEList = pSelect->pEList;
- ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY",
- jmpIfDynamic>=0?"":"CORRELATED "
+ ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d",
+ addrOnce?"":"CORRELATED ", pSelect->selId
));
assert( !isRowid );
/* If the LHS and RHS of the IN operator do not match, that
@@ -2715,7 +2751,7 @@ void sqlite3CodeRhsOfIN(
if( ALWAYS(pEList->nExpr==nVal) ){
SelectDest dest;
int i;
- sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
+ sqlite3SelectDestInit(&dest, SRT_Set, iTab);
dest.zAffSdst = exprINAffinity(pParse, pExpr);
pSelect->iLimit = 0;
testcase( pSelect->selFlags & SF_Distinct );
@@ -2772,24 +2808,24 @@ void sqlite3CodeRhsOfIN(
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
- if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
- sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
- jmpIfDynamic = -1;
+ if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
+ sqlite3VdbeChangeToNoop(v, addrOnce);
+ addrOnce = 0;
}
/* Evaluate the expression and insert it into the temp table */
if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
- sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
+ sqlite3VdbeAddOp3(v, OP_InsertInt, iTab, r2, iValToIns);
}else{
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
if( isRowid ){
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3,
sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
+ sqlite3VdbeAddOp3(v, OP_Insert, iTab, r2, r3);
}else{
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
- sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1);
}
}
}
@@ -2799,8 +2835,11 @@ void sqlite3CodeRhsOfIN(
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
- if( jmpIfDynamic>=0 ){
- sqlite3VdbeJumpHere(v, jmpIfDynamic);
+ if( addrOnce ){
+ sqlite3VdbeJumpHere(v, addrOnce);
+ /* Subroutine return */
+ sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
+ sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
}
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -2821,14 +2860,20 @@ void sqlite3CodeRhsOfIN(
*/
#ifndef SQLITE_OMIT_SUBQUERY
int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
- int jmpIfDynamic = -1; /* One-time test address */
+ int addrOnce = 0; /* Address of OP_Once at top of subroutine */
int rReg = 0; /* Register storing resulting */
Select *pSel; /* SELECT statement to encode */
SelectDest dest; /* How to deal with SELECT result */
int nReg; /* Registers to allocate */
Expr *pLimit; /* New limit expression */
- Vdbe *v = sqlite3GetVdbe(pParse);
+
+ Vdbe *v = pParse->pVdbe;
assert( v!=0 );
+ testcase( pExpr->op==TK_EXISTS );
+ testcase( pExpr->op==TK_SELECT );
+ assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
+ assert( ExprHasProperty(pExpr, EP_xIsSelect) );
+ pSel = pExpr->x.pSelect;
/* The evaluation of the EXISTS/SELECT must be repeated every time it
** is encountered if any of the following is true:
@@ -2841,7 +2886,23 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
- jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ /* If this routine has already been coded, then invoke it as a
+ ** subroutine. */
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId));
+ sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
+ pExpr->y.sub.iAddr);
+ return pExpr->iTable;
+ }
+
+ /* Begin coding the subroutine */
+ ExprSetProperty(pExpr, EP_Subrtn);
+ pExpr->y.sub.regReturn = ++pParse->nMem;
+ pExpr->y.sub.iAddr =
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
+ VdbeComment((v, "return address"));
+
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
/* For a SELECT, generate code to put the values for all columns of
@@ -2854,14 +2915,8 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** In both cases, the query is augmented with "LIMIT 1". Any
** preexisting limit is discarded in place of the new LIMIT 1.
*/
- testcase( pExpr->op==TK_EXISTS );
- testcase( pExpr->op==TK_SELECT );
- assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
- assert( ExprHasProperty(pExpr, EP_xIsSelect) );
-
- pSel = pExpr->x.pSelect;
- ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY",
- jmpIfDynamic>=0?"":"CORRELATED "));
+ ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d",
+ addrOnce?"":"CORRELATED ", pSel->selId));
nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
pParse->nMem += nReg;
@@ -2887,11 +2942,14 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
if( sqlite3Select(pParse, pSel, &dest) ){
return 0;
}
- rReg = dest.iSDParm;
+ pExpr->iTable = rReg = dest.iSDParm;
ExprSetVVAProperty(pExpr, EP_NoReduce);
+ if( addrOnce ){
+ sqlite3VdbeJumpHere(v, addrOnce);
- if( jmpIfDynamic>=0 ){
- sqlite3VdbeJumpHere(v, jmpIfDynamic);
+ /* Subroutine return */
+ sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
+ sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
}
return rReg;
@@ -2968,6 +3026,7 @@ static void sqlite3ExprCodeIN(
int addrTruthOp; /* Address of opcode that determines the IN is true */
int destNotNull; /* Jump here if a comparison is not true in step 6 */
int addrTop; /* Top of the step-6 loop */
+ int iTab = 0; /* Index to use */
pLeft = pExpr->pLeft;
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
@@ -2979,7 +3038,7 @@ static void sqlite3ExprCodeIN(
if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
/* Attempt to compute the RHS. After this step, if anything other than
- ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable
+ ** IN_INDEX_NOOP is returned, the table opened with cursor iTab
** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
** the RHS has not yet been coded. */
v = pParse->pVdbe;
@@ -2987,7 +3046,8 @@ static void sqlite3ExprCodeIN(
VdbeNoopComment((v, "begin IN expr"));
eType = sqlite3FindInIndex(pParse, pExpr,
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
- destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
+ destIfFalse==destIfNull ? 0 : &rRhsHasNull,
+ aiMap, &iTab);
assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
|| eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
@@ -3095,19 +3155,19 @@ static void sqlite3ExprCodeIN(
/* In this case, the RHS is the ROWID of table b-tree and so we also
** know that the RHS is non-NULL. Hence, we combine steps 3 and 4
** into a single opcode. */
- sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs);
VdbeCoverage(v);
addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */
}else{
sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
if( destIfFalse==destIfNull ){
/* Combine Step 3 and Step 5 into a single opcode */
- sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse,
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse,
rLhs, nVector); VdbeCoverage(v);
goto sqlite3ExprCodeIN_finished;
}
/* Ordinary Step 3, for the case where FALSE and NULL are distinct */
- addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0,
+ addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0,
rLhs, nVector); VdbeCoverage(v);
}
@@ -3132,7 +3192,7 @@ static void sqlite3ExprCodeIN(
** of the RHS.
*/
if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
- addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse);
VdbeCoverage(v);
if( nVector>1 ){
destNotNull = sqlite3VdbeMakeLabel(pParse);
@@ -3147,7 +3207,7 @@ static void sqlite3ExprCodeIN(
int r3 = sqlite3GetTempReg(pParse);
p = sqlite3VectorFieldSubexpr(pLeft, i);
pColl = sqlite3ExprCollSeq(pParse, p);
- sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3);
+ sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3);
sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
(void*)pColl, P4_COLLSEQ);
VdbeCoverage(v);
@@ -3156,7 +3216,7 @@ static void sqlite3ExprCodeIN(
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
if( nVector>1 ){
sqlite3VdbeResolveLabel(v, destNotNull);
- sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1);
+ sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1);
VdbeCoverage(v);
/* Step 7: If we reach this point, we know that the result must
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e056088fc..24cdc27dd 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2485,6 +2485,10 @@ struct Expr {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
** for a column of an index on an expression */
Window *pWin; /* TK_FUNCTION: Window definition for the func */
+ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
+ int iAddr; /* Subroutine entry address */
+ int regReturn; /* Register used to hold return address */
+ } sub;
} y;
};
@@ -2516,6 +2520,7 @@ struct Expr {
#define EP_Alias 0x400000 /* Is an alias for a result set column */
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
+#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
/*
** The EP_Propagate mask is a set of properties that automatically propagate
@@ -4258,7 +4263,7 @@ void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
int sqlite3GetToken(const unsigned char *, int *);
void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*, int);
-void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
+void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int);
int sqlite3CodeSubselect(Parse*, Expr*);
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
@@ -4511,7 +4516,7 @@ const char *sqlite3JournalModename(int);
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
-int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
+int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*);
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
diff --git a/src/vdbe.c b/src/vdbe.c
index 88405024c..3146d05d8 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3610,7 +3610,8 @@ case OP_OpenDup: {
pCx->isEphemeral = 1;
pCx->pKeyInfo = pOrig->pKeyInfo;
pCx->isTable = pOrig->isTable;
- rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
+ pCx->pgnoRoot = pOrig->pgnoRoot;
+ rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
pCx->pKeyInfo, pCx->uc.pCursor);
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
** opened for a database. Since there is already an open cursor when this
diff --git a/src/vdbe.h b/src/vdbe.h
index 8928798f1..27fb9056d 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -207,6 +207,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
void sqlite3VdbeExplain(Parse*,u8,const char*,...);
void sqlite3VdbeExplainPop(Parse*);
int sqlite3VdbeExplainParent(Parse*);
+ void sqlite3ExplainBreakpoint(const char*,const char*);
# define ExplainQueryPlan(P) sqlite3VdbeExplain P
# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P)
# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P)
@@ -214,6 +215,12 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
# define ExplainQueryPlan(P)
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0
+# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
+#endif
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
+ void sqlite3ExplainBreakpoint(const char*,const char*);
+#else
+# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 193b24db8..bd67b8858 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -350,7 +350,18 @@ int sqlite3VdbeExplainParent(Parse *pParse){
}
/*
-** Add a new OP_Explain opcode.
+** Set a debugger breakpoint on the following routine in order to
+** monitor the EXPLAIN QUERY PLAN code generation.
+*/
+#if defined(SQLITE_DEBUG)
+void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
+ (void)z1;
+ (void)z2;
+}
+#endif
+
+/*
+** Add a new OP_ opcode.
**
** If the bPush flag is true, then make this opcode the parent for
** subsequent Explains until sqlite3VdbeExplainPop() is called.
@@ -373,7 +384,10 @@ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
iThis = v->nOp;
sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
zMsg, P4_DYNAMIC);
- if( bPush) pParse->addrExplain = iThis;
+ sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z);
+ if( bPush){
+ pParse->addrExplain = iThis;
+ }
}
}
@@ -381,6 +395,7 @@ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
** Pop the EXPLAIN QUERY PLAN stack one level.
*/
void sqlite3VdbeExplainPop(Parse *pParse){
+ sqlite3ExplainBreakpoint("POP", 0);
pParse->addrExplain = sqlite3VdbeExplainParent(pParse);
}
#endif /* SQLITE_OMIT_EXPLAIN */
diff --git a/src/where.c b/src/where.c
index 4a8bf35af..9c0192747 100644
--- a/src/where.c
+++ b/src/where.c
@@ -854,6 +854,7 @@ static void constructAutomaticIndex(
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
pTabItem->regResult, 1);
sqlite3VdbeGoto(v, addrTop);
+ pTabItem->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
}
@@ -5074,7 +5075,7 @@ WhereInfo *sqlite3WhereBegin(
pParse, pTabList, pLevel, wctrlFlags
);
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
- notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady);
+ notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady);
pWInfo->iContinue = pLevel->addrCont;
if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){
sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain);
diff --git a/src/whereInt.h b/src/whereInt.h
index 209ac42ee..07876f435 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -507,8 +507,11 @@ void sqlite3WhereAddScanStatus(
# define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d)
#endif
Bitmask sqlite3WhereCodeOneLoopStart(
+ Parse *pParse, /* Parsing context */
+ Vdbe *v, /* Prepared statement under construction */
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
+ WhereLevel *pLevel, /* The current level pointer */
Bitmask notReady /* Which tables are currently available */
);
diff --git a/src/wherecode.c b/src/wherecode.c
index 4c68fe5a9..cffa78959 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -213,6 +213,7 @@ int sqlite3WhereExplainOneScan(
}
#endif
zMsg = sqlite3StrAccumFinish(&str);
+ sqlite3ExplainBreakpoint("",zMsg);
ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
}
@@ -538,16 +539,17 @@ static int codeEqualityTerm(
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
}
+ iTab = 0;
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
}else{
sqlite3 *db = pParse->db;
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
if( !db->mallocFailed ){
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
- pTerm->pExpr->iTable = pX->iTable;
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
+ pTerm->pExpr->iTable = iTab;
}
sqlite3ExprDelete(db, pX);
pX = pTerm->pExpr;
@@ -557,7 +559,6 @@ static int codeEqualityTerm(
testcase( bRev );
bRev = !bRev;
}
- iTab = pX->iTable;
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
@@ -1164,22 +1165,21 @@ static void whereIndexExprTrans(
** implementation described by pWInfo.
*/
Bitmask sqlite3WhereCodeOneLoopStart(
+ Parse *pParse, /* Parsing context */
+ Vdbe *v, /* Prepared statement under construction */
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
+ WhereLevel *pLevel, /* The current level pointer */
Bitmask notReady /* Which tables are currently available */
){
int j, k; /* Loop counters */
int iCur; /* The VDBE cursor for the table */
int addrNxt; /* Where to jump to continue with the next IN case */
- int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
- WhereLevel *pLevel; /* The where level to be coded */
WhereLoop *pLoop; /* The WhereLoop object being coded */
WhereClause *pWC; /* Decomposition of the entire WHERE clause */
WhereTerm *pTerm; /* A WHERE clause term */
- Parse *pParse; /* Parsing context */
sqlite3 *db; /* Database connection */
- Vdbe *v; /* The prepared stmt under constructions */
struct SrcList_item *pTabItem; /* FROM clause term being coded */
int addrBrk; /* Jump here to break out of the loop */
int addrHalt; /* addrBrk for the outermost loop */
@@ -1189,18 +1189,13 @@ Bitmask sqlite3WhereCodeOneLoopStart(
Index *pIdx = 0; /* Index used by loop (if any) */
int iLoop; /* Iteration of constraint generator loop */
- pParse = pWInfo->pParse;
- v = pParse->pVdbe;
pWC = &pWInfo->sWC;
db = pParse->db;
- pLevel = &pWInfo->a[iLevel];
pLoop = pLevel->pWLoop;
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
- omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
/* Create labels for the "break" and "continue" instructions
@@ -1341,7 +1336,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
- assert( omitTable==0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
iReleaseReg = ++pParse->nMem;
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
@@ -1360,7 +1354,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
int memEndValue = 0;
WhereTerm *pStart, *pEnd;
- assert( omitTable==0 );
j = 0;
pStart = pEnd = 0;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
@@ -1524,6 +1517,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
char *zEndAff = 0; /* Affinity for end of range constraint */
u8 bSeekPastNull = 0; /* True to seek past initial nulls */
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
+ int omitTable; /* True if we use the index only */
+
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
@@ -1725,6 +1720,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
/* Seek the table cursor, if required */
+ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
@@ -1951,6 +1948,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pOrExpr = pAndExpr;
}
/* Loop through table entries that match term pOrTerm. */
+ ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
wctrlFlags, iCovCur);
@@ -2054,6 +2052,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Finish the loop through table entries that match term pOrTerm. */
sqlite3WhereEnd(pSubWInfo);
+ ExplainQueryPlanPop(pParse);
}
}
}
diff --git a/test/autoindex1.test b/test/autoindex1.test
index 1978b8df1..b08f8cfeb 100644
--- a/test/autoindex1.test
+++ b/test/autoindex1.test
@@ -184,7 +184,7 @@ do_eqp_test autoindex1-500.1 {
} {
QUERY PLAN
|--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)
- `--LIST SUBQUERY
+ `--LIST SUBQUERY xxxxxx
`--SCAN TABLE t502
}
do_eqp_test autoindex1-501 {
@@ -193,7 +193,7 @@ do_eqp_test autoindex1-501 {
} {
QUERY PLAN
|--SCAN TABLE t501
- `--CORRELATED LIST SUBQUERY
+ `--CORRELATED LIST SUBQUERY xxxxxx
`--SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?)
}
do_eqp_test autoindex1-502 {
@@ -203,7 +203,7 @@ do_eqp_test autoindex1-502 {
} {
QUERY PLAN
|--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)
- `--CORRELATED LIST SUBQUERY
+ `--CORRELATED LIST SUBQUERY xxxxxx
`--SCAN TABLE t502
}
@@ -280,7 +280,7 @@ do_eqp_test autoindex1-600a {
|--MATERIALIZE xxxxxx
| |--SCAN TABLE sheep AS s
| |--SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?)
- | `--CORRELATED SCALAR SUBQUERY
+ | `--CORRELATED SCALAR SUBQUERY xxxxxx
| `--SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)
|--SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index
`--SEARCH SUBQUERY xxxxxx AS y USING AUTOMATIC COVERING INDEX (sheep_no=?)
diff --git a/test/bestindex3.test b/test/bestindex3.test
index 4b125d4df..80038e285 100644
--- a/test/bestindex3.test
+++ b/test/bestindex3.test
@@ -90,8 +90,10 @@ do_eqp_test 1.3 {
} {
QUERY PLAN
`--MULTI-INDEX OR
- |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?
- `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
+ |--INDEX 1
+ | `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?
+ `--INDEX 2
+ `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
}
do_eqp_test 1.4 {
@@ -99,8 +101,10 @@ do_eqp_test 1.4 {
} {
QUERY PLAN
`--MULTI-INDEX OR
- |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?
- `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
+ |--INDEX 1
+ | `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?
+ `--INDEX 2
+ `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
}
do_execsql_test 1.5 {
@@ -150,8 +154,10 @@ ifcapable !icu {
} [string map {"\n " \n} {
QUERY PLAN
`--MULTI-INDEX OR
- |--SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)
- `--SEARCH TABLE t2 USING INDEX t2y (y=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)
+ `--INDEX 2
+ `--SEARCH TABLE t2 USING INDEX t2y (y=?)
}]
}
diff --git a/test/cost.test b/test/cost.test
index 5d23e0ed7..2922a0a05 100644
--- a/test/cost.test
+++ b/test/cost.test
@@ -58,9 +58,12 @@ do_eqp_test 3.2 {
} {
QUERY PLAN
|--MULTI-INDEX OR
- | |--SEARCH TABLE t5 USING INDEX t5b (b=?)
- | |--SEARCH TABLE t5 USING INDEX t5c (c=?)
- | `--SEARCH TABLE t5 USING INDEX t5d (d=?)
+ | |--INDEX 1
+ | | `--SEARCH TABLE t5 USING INDEX t5b (b=?)
+ | |--INDEX 2
+ | | `--SEARCH TABLE t5 USING INDEX t5c (c=?)
+ | `--INDEX 3
+ | `--SEARCH TABLE t5 USING INDEX t5d (d=?)
`--USE TEMP B-TREE FOR ORDER BY
}
@@ -124,8 +127,10 @@ do_eqp_test 6.2 {
} {
QUERY PLAN
|--MULTI-INDEX OR
- | |--SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)
- | `--SEARCH TABLE t3 USING INDEX t3i2 (c=?)
+ | |--INDEX 1
+ | | `--SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)
+ | `--INDEX 2
+ | `--SEARCH TABLE t3 USING INDEX t3i2 (c=?)
`--USE TEMP B-TREE FOR ORDER BY
}
@@ -149,8 +154,10 @@ do_eqp_test 7.2 {
} {
QUERY PLAN
|--MULTI-INDEX OR
- | |--SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)
- | `--SEARCH TABLE t1 USING INDEX t1b (b=?)
+ | |--INDEX 1
+ | | `--SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)
+ | `--INDEX 2
+ | `--SEARCH TABLE t1 USING INDEX t1b (b=?)
`--USE TEMP B-TREE FOR ORDER BY
}
diff --git a/test/eqp.test b/test/eqp.test
index 3de746e3a..f931f8f34 100644
--- a/test/eqp.test
+++ b/test/eqp.test
@@ -45,8 +45,10 @@ do_eqp_test 1.2 {
} {
QUERY PLAN
|--MULTI-INDEX OR
- | |--SEARCH TABLE t1 USING INDEX i1 (a=?)
- | `--SEARCH TABLE t1 USING INDEX i2 (b=?)
+ | |--INDEX 1
+ | | `--SEARCH TABLE t1 USING INDEX i1 (a=?)
+ | `--INDEX 2
+ | `--SEARCH TABLE t1 USING INDEX i2 (b=?)
`--SCAN TABLE t2
}
do_eqp_test 1.3 {
@@ -55,8 +57,10 @@ do_eqp_test 1.3 {
QUERY PLAN
|--SCAN TABLE t2
`--MULTI-INDEX OR
- |--SEARCH TABLE t1 USING INDEX i1 (a=?)
- `--SEARCH TABLE t1 USING INDEX i2 (b=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t1 USING INDEX i1 (a=?)
+ `--INDEX 2
+ `--SEARCH TABLE t1 USING INDEX i2 (b=?)
}
do_eqp_test 1.3 {
SELECT a FROM t1 ORDER BY a
@@ -225,7 +229,7 @@ do_eqp_test 3.1.1 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--SCALAR SUBQUERY
+ `--SCALAR SUBQUERY xxxxxx
`--SCAN TABLE t1 AS sub
}
do_eqp_test 3.1.2 {
@@ -233,7 +237,7 @@ do_eqp_test 3.1.2 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--SCALAR SUBQUERY
+ `--SCALAR SUBQUERY xxxxxx
`--SCAN TABLE t1 AS sub
}
do_eqp_test 3.1.3 {
@@ -241,7 +245,7 @@ do_eqp_test 3.1.3 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--SCALAR SUBQUERY
+ `--SCALAR SUBQUERY xxxxxx
|--SCAN TABLE t1 AS sub
`--USE TEMP B-TREE FOR ORDER BY
}
@@ -250,7 +254,7 @@ do_eqp_test 3.1.4 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--SCALAR SUBQUERY
+ `--SCALAR SUBQUERY xxxxxx
`--SCAN TABLE t2 USING COVERING INDEX t2i1
}
@@ -286,7 +290,7 @@ det 3.3.1 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--LIST SUBQUERY
+ `--LIST SUBQUERY xxxxxx
`--SCAN TABLE t2
}
det 3.3.2 {
@@ -294,7 +298,7 @@ det 3.3.2 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--CORRELATED LIST SUBQUERY
+ `--CORRELATED LIST SUBQUERY xxxxxx
`--SCAN TABLE t2
}
det 3.3.3 {
@@ -302,7 +306,7 @@ det 3.3.3 {
} {
QUERY PLAN
|--SCAN TABLE t1
- `--CORRELATED SCALAR SUBQUERY
+ `--CORRELATED SCALAR SUBQUERY xxxxxx
`--SCAN TABLE t2
}
@@ -813,7 +817,7 @@ do_eqp_test 9.1 {
|--MATERIALIZE xxxxxx
| |--SCAN TABLE forumpost AS x USING INDEX forumthread
| |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
- | |--CORRELATED SCALAR SUBQUERY
+ | |--CORRELATED SCALAR SUBQUERY xxxxxx
| | |--SEARCH TABLE forumpost USING COVERING INDEX forumthread (froot=?)
| | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
| `--USE TEMP B-TREE FOR ORDER BY
diff --git a/test/join5.test b/test/join5.test
index 2df66e7cf..31280c5d1 100644
--- a/test/join5.test
+++ b/test/join5.test
@@ -267,8 +267,10 @@ do_eqp_test 7.2 {
QUERY PLAN
|--SCAN TABLE t1
`--MULTI-INDEX OR
- |--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)
- `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)
+ `--INDEX 2
+ `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)
}
do_execsql_test 7.3 {
diff --git a/test/rowvalue4.test b/test/rowvalue4.test
index 5c0d170f5..2929a97d1 100644
--- a/test/rowvalue4.test
+++ b/test/rowvalue4.test
@@ -235,9 +235,9 @@ do_eqp_test 5.1 {
} {
QUERY PLAN
|--SEARCH TABLE d2 USING INDEX d2ab (a=? AND b=?)
- |--LIST SUBQUERY
+ |--LIST SUBQUERY xxxxxx
| `--SCAN TABLE d1
- `--LIST SUBQUERY
+ `--LIST SUBQUERY xxxxxx
`--SCAN TABLE d1
}
diff --git a/test/tkt-80ba201079.test b/test/tkt-80ba201079.test
index ea0799b56..b6cc85f34 100644
--- a/test/tkt-80ba201079.test
+++ b/test/tkt-80ba201079.test
@@ -110,6 +110,8 @@ do_test tkt-80ba2-200 {
} {300 object_change 2048}
do_test tkt-80ba2-201 {
db eval {
+PRAGMA vdbe_debug=on;
+PRAGMA vdbe_addoptrace=on;
CREATE INDEX timeline_entry_id_idx on timeline(entry_id);
SELECT entry_type,
entry_types.name,
diff --git a/test/where7.test b/test/where7.test
index 5abd0a8bc..81111a9de 100644
--- a/test/where7.test
+++ b/test/where7.test
@@ -23353,8 +23353,10 @@ do_eqp_test where7-3.2 {
} {
QUERY PLAN
|--MULTI-INDEX OR
- | |--SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)
- | `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)
+ | |--INDEX 1
+ | | `--SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)
+ | `--INDEX 2
+ | `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)
|--SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)
`--USE TEMP B-TREE FOR ORDER BY
}
diff --git a/test/where9.test b/test/where9.test
index 87f5c1561..7a019d317 100644
--- a/test/where9.test
+++ b/test/where9.test
@@ -364,8 +364,10 @@ ifcapable explain {
QUERY PLAN
|--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
`--MULTI-INDEX OR
- |--SEARCH TABLE t2 USING INDEX t2d (d=?)
- `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t2 USING INDEX t2d (d=?)
+ `--INDEX 3
+ `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)
}]
do_eqp_test where9-3.2 {
SELECT coalesce(t2.a,9999)
@@ -375,8 +377,10 @@ ifcapable explain {
QUERY PLAN
|--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
`--MULTI-INDEX OR
- |--SEARCH TABLE t2 USING INDEX t2d (d=?)
- `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t2 USING INDEX t2d (d=?)
+ `--INDEX 2
+ `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)
}]
}
@@ -456,8 +460,10 @@ do_eqp_test where9-5.1 {
} {
QUERY PLAN
`--MULTI-INDEX OR
- |--SEARCH TABLE t1 USING INDEX t1c (c=?)
- `--SEARCH TABLE t1 USING INDEX t1d (d=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t1 USING INDEX t1c (c=?)
+ `--INDEX 2
+ `--SEARCH TABLE t1 USING INDEX t1d (d=?)
}
# In contrast, b=1000 is preferred over any OR-clause.
diff --git a/test/whereI.test b/test/whereI.test
index d08e62c37..7bb4ba39d 100644
--- a/test/whereI.test
+++ b/test/whereI.test
@@ -31,8 +31,10 @@ do_eqp_test 1.1 {
} {
QUERY PLAN
`--MULTI-INDEX OR
- |--SEARCH TABLE t1 USING INDEX i1 (b=?)
- `--SEARCH TABLE t1 USING INDEX i2 (c=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t1 USING INDEX i1 (b=?)
+ `--INDEX 2
+ `--SEARCH TABLE t1 USING INDEX i2 (c=?)
}
do_execsql_test 1.2 {
@@ -61,8 +63,10 @@ do_eqp_test 2.1 {
} {
QUERY PLAN
`--MULTI-INDEX OR
- |--SEARCH TABLE t2 USING INDEX i3 (b=?)
- `--SEARCH TABLE t2 USING INDEX i4 (c=?)
+ |--INDEX 1
+ | `--SEARCH TABLE t2 USING INDEX i3 (b=?)
+ `--INDEX 2
+ `--SEARCH TABLE t2 USING INDEX i4 (c=?)
}
do_execsql_test 2.2 {
diff --git a/test/with3.test b/test/with3.test
index de150b1fc..0f49f0685 100644
--- a/test/with3.test
+++ b/test/with3.test
@@ -120,7 +120,7 @@ do_eqp_test 3.2.2 {
|--MATERIALIZE xxxxxx
| |--SETUP
| | |--SCAN CONSTANT ROW
- | | `--SCALAR SUBQUERY
+ | | `--SCALAR SUBQUERY xxxxxx
| | `--SCAN TABLE w2
| `--RECURSIVE STEP
| |--SCAN TABLE w1