diff options
-rw-r--r-- | ext/expert/expert1.test | 6 | ||||
-rw-r--r-- | manifest | 50 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/expr.c | 154 | ||||
-rw-r--r-- | src/sqliteInt.h | 9 | ||||
-rw-r--r-- | src/vdbe.c | 3 | ||||
-rw-r--r-- | src/vdbe.h | 7 | ||||
-rw-r--r-- | src/vdbeaux.c | 19 | ||||
-rw-r--r-- | src/where.c | 3 | ||||
-rw-r--r-- | src/whereInt.h | 3 | ||||
-rw-r--r-- | src/wherecode.c | 29 | ||||
-rw-r--r-- | test/autoindex1.test | 8 | ||||
-rw-r--r-- | test/bestindex3.test | 18 | ||||
-rw-r--r-- | test/cost.test | 21 | ||||
-rw-r--r-- | test/eqp.test | 28 | ||||
-rw-r--r-- | test/join5.test | 6 | ||||
-rw-r--r-- | test/rowvalue4.test | 4 | ||||
-rw-r--r-- | test/tkt-80ba201079.test | 2 | ||||
-rw-r--r-- | test/where7.test | 6 | ||||
-rw-r--r-- | test/where9.test | 18 | ||||
-rw-r--r-- | test/whereI.test | 12 | ||||
-rw-r--r-- | test/with3.test | 2 |
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. @@ -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 |