1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Refactor the SrcItem object to move fields associated with subqueries out

into a separate object named Subquery.  This reduces the size of the SrcItem
object by about 1/3rd and provides improved performance.

FossilOrigin-Name: 484bcd75bc95491d8540c791c1c4d40d996cb465839564662e14f98739699bf1
This commit is contained in:
drh
2024-08-20 23:11:28 +00:00
25 changed files with 665 additions and 365 deletions

View File

@ -1,5 +1,5 @@
C When\sthe\sdatabase\sencoding\sis\sUTF-16LE\sand\sthe\sGLOB\soptimization\sis\sused,\nit\sis\sok\sto\suse\sthe\srange\ssearch\sover\san\sindex,\sbut\sit\sis\snot\sok\sto\ndisable\sthe\sactual\sGLOB\sfunction\scall. C Refactor\sthe\sSrcItem\sobject\sto\smove\sfields\sassociated\swith\ssubqueries\sout\ninto\sa\sseparate\sobject\snamed\sSubquery.\s\sThis\sreduces\sthe\ssize\sof\sthe\sSrcItem\nobject\sby\sabout\s1/3rd\sand\sprovides\simproved\sperformance.
D 2024-08-20T14:12:16.713 D 2024-08-20T23:11:28.443
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -696,34 +696,34 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2 F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
F src/alter.c bb663fddf1fe0e2e6d8758b2b7fb6374e7c057a6ca3955f37a48986806029765 F src/alter.c aa93e37e4a36a0525bbb2a2aeda20d2018f0aa995542c7dc658e031375e3f532
F src/analyze.c 30bf40ec4208ead9e977bec017bccc8a9681820936e38ca5a4a7443100a6d5c5 F src/analyze.c 30bf40ec4208ead9e977bec017bccc8a9681820936e38ca5a4a7443100a6d5c5
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39 F src/attach.c 08235ab62ed5ccc93c22bf36e640d19effcd632319615851bccf724ec9341333
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4 F src/auth.c 4c1ea890e0069ad73bead5d17a5b12c34cfa4f1a24175c8147ea439b64be271c
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523 F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645 F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522 F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
F src/btree.c 8b42fc7d9efdb2df05c30e8f91ff6cfbd979724ae24bf90269028468b7a13333 F src/btree.c 8b42fc7d9efdb2df05c30e8f91ff6cfbd979724ae24bf90269028468b7a13333
F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0 F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6 F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
F src/build.c 237ccc0290d131d646be722f418e92ee0a38043aee25e7dfdc75f8ce5b3abe4e F src/build.c c5522b5faf8128227678e194275cefaeb4d063f55dbe70bcff745f1b63a187cf
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490 F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 64e4b1227b4ed123146f0aa2989131d1fbd9b927b11e80c9d58c6a68f9cd5ce3 F src/ctime.c 64e4b1227b4ed123146f0aa2989131d1fbd9b927b11e80c9d58c6a68f9cd5ce3
F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500 F src/delete.c 444c4d1eaac40103461e3b6f0881846dd3aafc1cec1dd169d3482fa331667da7
F src/expr.c fe958028b36af640b70b2174354c044f75b8c4a4645c921592122aa2a022083a F src/expr.c 6d5f2c38fe3ec06a7eac599dac822788b36064124e20112a844e9cd5156cb239
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 852f93c0ef995e0c2b8983059a2b97151c194cc8259e21f5bc2b7ac508348c2a F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
F src/func.c 1f61e32e7a357e615b5d2e774bee563761fce4f2fd97ecb0f72c33e62a2ada5f F src/func.c 1f61e32e7a357e615b5d2e774bee563761fce4f2fd97ecb0f72c33e62a2ada5f
F src/global.c 61a419dd9e993b9be0f91de4c4ccf322b053eb829868e089f0321dd669be3b90 F src/global.c 61a419dd9e993b9be0f91de4c4ccf322b053eb829868e089f0321dd669be3b90
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220 F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 8ff11e9e54c5fc1fe89707b3d41cf44ad2822f712bd3b5da68338ea42518847e F src/insert.c f8d1a0f8ee258411009c6b7f2d93170e351bd19f5ad89d57e1180644297cbe70
F src/json.c 5b6a1d6015997b9ee848a32948720bdb26a0ef2de5a2127ebf7355ce66dbdc0d F src/json.c 5b6a1d6015997b9ee848a32948720bdb26a0ef2de5a2127ebf7355ce66dbdc0d
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
@ -753,23 +753,23 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c b08600ebf0db90b6d1e9b8b6577c6fa3877cbe1a100bd0b2899e4c6e9adad4b3 F src/pager.c b08600ebf0db90b6d1e9b8b6577c6fa3877cbe1a100bd0b2899e4c6e9adad4b3
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
F src/parse.y 318ef86fbe358b1a93262a42e152f37b97b3fddae8d319dffbd24ce2300f6c88 F src/parse.y 5972b7d00af4c8d96fdad781af1ea1d5d51fc3b907ad61bda60e49503274e5ed
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319 F src/pcache1.c 49516ad7718a3626f28f710fa7448ef1fce3c07fd169acbb4817341950264319
F src/pragma.c 52bfbf6dfd668b69b5eb9bd1186e3a67367c8453807150d6e75239229924f684 F src/pragma.c 52bfbf6dfd668b69b5eb9bd1186e3a67367c8453807150d6e75239229924f684
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c d99931f45416652895e502328ca49fe782cfc4e1ebdcda13b3736d991ebf42ce F src/prepare.c d99931f45416652895e502328ca49fe782cfc4e1ebdcda13b3736d991ebf42ce
F src/printf.c 8b250972305e14b365561be5117ed0fd364e4fd58968776df1ce64c6280b90f9 F src/printf.c 6a87534ebfb9e5346011191b1f3a7ebc457f5938c7e4feeea478ecf53f6a41b2
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 0aee8a2e5340ba95a966917305dfaff5147fcad78d0839cd364b16e4746b8bcb F src/resolve.c 9afed5fd7b9111633bdb74a73cdc47324e28e4dc6c27113e3e9aee38fb9422ab
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 7e907830b01c7fd34968514067aed1eac13e47da4bc1a936ef2020c6b866cc08 F src/select.c 44d135bbea93872a7318f048d9d6e566b1c3eaa92d6dabe06e4741aa78d1c1ec
F src/shell.c.in 94571558b0fb28c37a5cf6dbd6ea27285341023a28a8cb5795cd2768fab67704 F src/shell.c.in 94571558b0fb28c37a5cf6dbd6ea27285341023a28a8cb5795cd2768fab67704
F src/sqlite.h.in 1ad9110150773c38ebababbad11b5cb361bcd3997676dec1c91ac5e0416a7b86 F src/sqlite.h.in 1ad9110150773c38ebababbad11b5cb361bcd3997676dec1c91ac5e0416a7b86
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
F src/sqliteInt.h 128b9004698cc79993d5369d7d1763deaf8bbf26e5e8931ec540707e5a7238df F src/sqliteInt.h 28c878bdf528879afefe1994ac007d094f8061f2fdacdc55d6055d7e9341151e
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728 F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@ -828,10 +828,10 @@ F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68 F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
F src/treeview.c 774838df4e25956ca34ff79bef150266412cfc2640620d04e22d5c8a55a98992 F src/treeview.c e98dbc8068d27f3d0bd2a4cebfce6a7c21c776edc23d80e12c67a70cd2ba3fe5
F src/trigger.c 0858f75818ed1580332db274f1032bcc5effe567cb132df5c5be8b1d800ca97f F src/trigger.c 0bb986a5b96047fd597c6aac28588853df56064e576e6b81ba777ef2ccaac461
F src/update.c 732404a04d1737ef14bb6ec6b84f74edf28b3c102a92ae46b4855438a710efe7 F src/update.c 0e01aa6a3edf9ec112b33eb714b9016a81241497b1fb7c3e74332f4f71756508
F src/upsert.c 2e60567a0e9e8520c18671b30712a88dc73534474304af94f32bb5f3ef65ac65 F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
F src/util.c 5d1a0134cf4240648d1c6bb5cc8efaca0ea2b5d5c840985aec7e947271f04375 F src/util.c 5d1a0134cf4240648d1c6bb5cc8efaca0ea2b5d5c840985aec7e947271f04375
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104 F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
@ -849,12 +849,12 @@ F src/vtab.c 5fb499d20494b7eecaadb7584634af9afcb374cb0524912b475fcb1712458a1b
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
F src/where.c f5be664f3379c9f930696e339ec4ef4c1187af860cca727411156101fae6b677 F src/where.c b6f79b189fcba459bb80420d3b4102f42a399be36ff29a3deff4ae4888fee46d
F src/whereInt.h 6444b888ce395cb80511284b8a73b63472d34247fcb1b125ee06a54fa6ae878e F src/whereInt.h 6444b888ce395cb80511284b8a73b63472d34247fcb1b125ee06a54fa6ae878e
F src/wherecode.c c9cac0b0b8e809c5e7e79d7796918907fb685ad99be2aaa9737f9787aa47349c F src/wherecode.c 137797b0de9ddf1ff43e5b0edffcc76fb05184ed651fc4f5a0a01a45c0b89d04
F src/whereexpr.c 26a5a798b3f676447ae54a27584c43b32abfebb8bbcaf6faffbb7ee1da486f2d F src/whereexpr.c 44f41ae554c7572e1de1485b3169b233ee04d464b2ee5881687ede3bf07cacfa
F src/window.c 1e40ffc509bae21e466f6106382d238e91eb73edd4ba10e66ca4fd7af2b96896 F src/window.c 499d48f315a09242dc68f2fac635ed27dcf6bbb0d9ab9084857898c64489e975
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9 F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
@ -2075,7 +2075,7 @@ F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3c
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
F test/windowpushd.test c420e2265f0e09a0e798d0513a660d71b51602088d81b3dbd038918ee1339dcc F test/windowpushd.test c420e2265f0e09a0e798d0513a660d71b51602088d81b3dbd038918ee1339dcc
F test/with1.test b93833890e5d2a368e78747f124503a0159aa029b98e9ed4795ebf630b2efd3d F test/with1.test b93833890e5d2a368e78747f124503a0159aa029b98e9ed4795ebf630b2efd3d
F test/with2.test a1df41b987198383b9b70bf5e5fda390582e46398653858dbc6ceb24253b28df F test/with2.test 181674a6cc86a601ca2ac052741cdfad5b529e07e870435d2f6cdb92d589ff17
F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65 F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205 F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8 F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
@ -2210,8 +2210,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P a5797ebdea423afc3d2d3bd8adaf1575d33a01f594c0c315afcb1499f1718e9b P 3399698376761ab8c422f8ea02bfa2759afb606f08bedbd1cf7eee834229a9aa 4fa8235dd59cd683d6c6c97bfe181a9637be7c054d435323c903b9dbd74aff02
R 0a328206336eacdda27ba4526bd5a010 R 82a6023b6446e680173d0de603e0e98e
U drh U drh
Z 4c7bd06b974e78d392c3b37a21911656 Z cc2792cc7e3d54684569210f9c97c9df
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
3399698376761ab8c422f8ea02bfa2759afb606f08bedbd1cf7eee834229a9aa 484bcd75bc95491d8540c791c1c4d40d996cb465839564662e14f98739699bf1

View File

@ -1366,8 +1366,9 @@ static int renameResolveTrigger(Parse *pParse){
int i; int i;
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){ for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
SrcItem *p = &pStep->pFrom->a[i]; SrcItem *p = &pStep->pFrom->a[i];
if( p->pSelect ){ if( p->fg.isSubquery ){
sqlite3SelectPrep(pParse, p->pSelect, 0); assert( p->u4.pSubq!=0 );
sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
} }
} }
} }
@ -1435,8 +1436,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
} }
if( pStep->pFrom ){ if( pStep->pFrom ){
int i; int i;
for(i=0; i<pStep->pFrom->nSrc; i++){ SrcList *pFrom = pStep->pFrom;
sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); for(i=0; i<pFrom->nSrc; i++){
if( pFrom->a[i].fg.isSubquery ){
assert( pFrom->a[i].u4.pSubq!=0 );
sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
}
} }
} }
} }
@ -1683,7 +1688,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
} }
for(i=0; i<pSrc->nSrc; i++){ for(i=0; i<pSrc->nSrc; i++){
SrcItem *pItem = &pSrc->a[i]; SrcItem *pItem = &pSrc->a[i];
if( pItem->pTab==p->pTab ){ if( pItem->pSTab==p->pTab ){
renameTokenFind(pWalker->pParse, p, pItem->zName); renameTokenFind(pWalker->pParse, p, pItem->zName);
} }
} }

View File

@ -479,20 +479,21 @@ static int fixSelectCb(Walker *p, Select *pSelect){
if( NEVER(pList==0) ) return WRC_Continue; if( NEVER(pList==0) ) return WRC_Continue;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pFix->bTemp==0 ){ if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){
if( pItem->zDatabase ){ if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){
sqlite3ErrorMsg(pFix->pParse, sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s", "%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase); pFix->zType, pFix->pName, pItem->u4.zDatabase);
return WRC_Abort; return WRC_Abort;
} }
sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->u4.zDatabase);
pItem->zDatabase = 0;
pItem->fg.notCte = 1; pItem->fg.notCte = 1;
pItem->fg.hadSchema = 1;
} }
pItem->pSchema = pFix->pSchema; pItem->u4.pSchema = pFix->pSchema;
pItem->fg.fromDDL = 1; pItem->fg.fromDDL = 1;
pItem->fg.fixedSchema = 1;
} }
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( pList->a[i].fg.isUsing==0 if( pList->a[i].fg.isUsing==0

View File

@ -165,7 +165,7 @@ void sqlite3AuthRead(
assert( pTabList ); assert( pTabList );
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){ for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
pTab = pTabList->a[iSrc].pTab; pTab = pTabList->a[iSrc].pSTab;
break; break;
} }
} }

View File

@ -497,12 +497,12 @@ Table *sqlite3LocateTableItem(
SrcItem *p SrcItem *p
){ ){
const char *zDb; const char *zDb;
assert( p->pSchema==0 || p->zDatabase==0 ); if( p->fg.fixedSchema ){
if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema);
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
zDb = pParse->db->aDb[iDb].zDbSName; zDb = pParse->db->aDb[iDb].zDbSName;
}else{ }else{
zDb = p->zDatabase; assert( !p->fg.isSubquery );
zDb = p->u4.zDatabase;
} }
return sqlite3LocateTable(pParse, flags, p->zName, zDb); return sqlite3LocateTable(pParse, flags, p->zName, zDb);
} }
@ -3487,6 +3487,8 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
} }
assert( pParse->nErr==0 ); assert( pParse->nErr==0 );
assert( pName->nSrc==1 ); assert( pName->nSrc==1 );
assert( pName->a[0].fg.fixedSchema==0 );
assert( pName->a[0].fg.isSubquery==0 );
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++; if( noErr ) db->suppressErr++;
assert( isView==0 || isView==LOCATE_VIEW ); assert( isView==0 || isView==LOCATE_VIEW );
@ -3495,7 +3497,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
if( pTab==0 ){ if( pTab==0 ){
if( noErr ){ if( noErr ){
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
sqlite3ForceNotReadOnly(pParse); sqlite3ForceNotReadOnly(pParse);
} }
goto exit_drop_table; goto exit_drop_table;
@ -4586,15 +4588,17 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
} }
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
assert( pName->nSrc==1 ); assert( pName->nSrc==1 );
assert( pName->a[0].fg.fixedSchema==0 );
assert( pName->a[0].fg.isSubquery==0 );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto exit_drop_index; goto exit_drop_index;
} }
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase);
if( pIndex==0 ){ if( pIndex==0 ){
if( !ifExists ){ if( !ifExists ){
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
}else{ }else{
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
sqlite3ForceNotReadOnly(pParse); sqlite3ForceNotReadOnly(pParse);
} }
pParse->checkSchema = 1; pParse->checkSchema = 1;
@ -4891,12 +4895,14 @@ SrcList *sqlite3SrcListAppend(
if( pDatabase && pDatabase->z==0 ){ if( pDatabase && pDatabase->z==0 ){
pDatabase = 0; pDatabase = 0;
} }
assert( pItem->fg.fixedSchema==0 );
assert( pItem->fg.isSubquery==0 );
if( pDatabase ){ if( pDatabase ){
pItem->zName = sqlite3NameFromToken(db, pDatabase); pItem->zName = sqlite3NameFromToken(db, pDatabase);
pItem->zDatabase = sqlite3NameFromToken(db, pTable); pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable);
}else{ }else{
pItem->zName = sqlite3NameFromToken(db, pTable); pItem->zName = sqlite3NameFromToken(db, pTable);
pItem->zDatabase = 0; pItem->u4.zDatabase = 0;
} }
return pList; return pList;
} }
@ -4912,13 +4918,40 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->iCursor>=0 ) continue; if( pItem->iCursor>=0 ) continue;
pItem->iCursor = pParse->nTab++; pItem->iCursor = pParse->nTab++;
if( pItem->pSelect ){ if( pItem->fg.isSubquery ){
sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); assert( pItem->u4.pSubq!=0 );
assert( pItem->u4.pSubq->pSelect!=0 );
assert( pItem->u4.pSubq->pSelect->pSrc!=0 );
sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc);
} }
} }
} }
} }
/*
** Delete a Subquery object and its substructure.
*/
void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){
assert( pSubq!=0 && pSubq->pSelect!=0 );
sqlite3SelectDelete(db, pSubq->pSelect);
sqlite3DbFree(db, pSubq);
}
/*
** Remove a Subquery from a SrcItem. Return the associated Select object.
** The returned Select becomes the responsibility of the caller.
*/
Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){
Select *pSel;
assert( pItem!=0 );
assert( pItem->fg.isSubquery );
pSel = pItem->u4.pSubq->pSelect;
sqlite3DbFree(db, pItem->u4.pSubq);
pItem->u4.pSubq = 0;
pItem->fg.isSubquery = 0;
return pSel;
}
/* /*
** Delete an entire SrcList including all its substructure. ** Delete an entire SrcList including all its substructure.
*/ */
@ -4928,13 +4961,26 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
assert( db!=0 ); assert( db!=0 );
if( pList==0 ) return; if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
/* Check invariants on SrcItem */
assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc );
assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy );
assert( !pItem->fg.hadSchema || !pItem->fg.isSubquery );
assert( !pItem->fg.hadSchema || pItem->fg.fixedSchema );
assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery );
assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 &&
pItem->u4.pSubq->pSelect!=0) );
if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName); if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias); if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
if( pItem->fg.isSubquery ){
sqlite3SubqueryDelete(db, pItem->u4.pSubq);
}else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
sqlite3DbNNFreeNN(db, pItem->u4.zDatabase);
}
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab); sqlite3DeleteTable(db, pItem->pSTab);
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
if( pItem->fg.isUsing ){ if( pItem->fg.isUsing ){
sqlite3IdListDelete(db, pItem->u3.pUsing); sqlite3IdListDelete(db, pItem->u3.pUsing);
}else if( pItem->u3.pOn ){ }else if( pItem->u3.pOn ){
@ -4944,6 +4990,54 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
sqlite3DbNNFreeNN(db, pList); sqlite3DbNNFreeNN(db, pList);
} }
/*
** Attach a Subquery object to pItem->uv.pSubq. Set the
** pSelect value but leave all the other values initialized
** to zero.
**
** A copy of the Select object is made if dupSelect is true, and the
** SrcItem takes responsibility for deleting the copy. If dupSelect is
** false, ownership of the Select passes to the SrcItem. Either way,
** the SrcItem will take responsibility for deleting the Select.
**
** When dupSelect is zero, that means the Select might get deleted right
** away if there is an OOM error. Beware.
**
** Return non-zero on success. Return zero on an OOM error.
*/
int sqlite3SrcItemAttachSubquery(
Parse *pParse, /* Parsing context */
SrcItem *pItem, /* Item to which the subquery is to be attached */
Select *pSelect, /* The subquery SELECT. Must be non-NULL */
int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/
){
Subquery *p;
assert( pSelect!=0 );
assert( pItem->fg.isSubquery==0 );
if( pItem->fg.fixedSchema ){
pItem->u4.pSchema = 0;
pItem->fg.fixedSchema = 0;
}else if( pItem->u4.zDatabase!=0 ){
sqlite3DbFree(pParse->db, pItem->u4.zDatabase);
pItem->u4.zDatabase = 0;
}
if( dupSelect ){
pSelect = sqlite3SelectDup(pParse->db, pSelect, 0);
if( pSelect==0 ) return 0;
}
p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery));
if( p==0 ){
sqlite3SelectDelete(pParse->db, pSelect);
return 0;
}
pItem->fg.isSubquery = 1;
p->pSelect = pSelect;
assert( offsetof(Subquery, pSelect)==0 );
memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect));
return 1;
}
/* /*
** This routine is called by the parser to add a new term to the ** This routine is called by the parser to add a new term to the
** end of a growing FROM clause. The "p" parameter is the part of ** end of a growing FROM clause. The "p" parameter is the part of
@ -4993,10 +5087,12 @@ SrcList *sqlite3SrcListAppendFromTerm(
if( pAlias->n ){ if( pAlias->n ){
pItem->zAlias = sqlite3NameFromToken(db, pAlias); pItem->zAlias = sqlite3NameFromToken(db, pAlias);
} }
assert( pSubquery==0 || pDatabase==0 );
if( pSubquery ){ if( pSubquery ){
pItem->pSelect = pSubquery; if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){
if( pSubquery->selFlags & SF_NestedFrom ){ if( pSubquery->selFlags & SF_NestedFrom ){
pItem->fg.isNestedFrom = 1; pItem->fg.isNestedFrom = 1;
}
} }
} }
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 ); assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );

View File

@ -24,8 +24,8 @@
** **
** The following fields are initialized appropriate in pSrc: ** The following fields are initialized appropriate in pSrc:
** **
** pSrc->a[0].pTab Pointer to the Table object ** pSrc->a[0].spTab Pointer to the Table object
** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one
** **
*/ */
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
@ -33,8 +33,8 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab; Table *pTab;
assert( pItem && pSrc->nSrc>=1 ); assert( pItem && pSrc->nSrc>=1 );
pTab = sqlite3LocateTableItem(pParse, 0, pItem); pTab = sqlite3LocateTableItem(pParse, 0, pItem);
if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab); if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab);
pItem->pTab = pTab; pItem->pSTab = pTab;
pItem->fg.notCte = 1; pItem->fg.notCte = 1;
if( pTab ){ if( pTab ){
pTab->nTabRef++; pTab->nTabRef++;
@ -156,7 +156,8 @@ void sqlite3MaterializeView(
if( pFrom ){ if( pFrom ){
assert( pFrom->nSrc==1 ); assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 );
pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].fg.isUsing==0 ); assert( pFrom->a[0].fg.isUsing==0 );
assert( pFrom->a[0].u3.pOn==0 ); assert( pFrom->a[0].u3.pOn==0 );
} }
@ -218,7 +219,7 @@ Expr *sqlite3LimitWhere(
** ); ** );
*/ */
pTab = pSrc->a[0].pTab; pTab = pSrc->a[0].pSTab;
if( HasRowid(pTab) ){ if( HasRowid(pTab) ){
pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
pEList = sqlite3ExprListAppend( pEList = sqlite3ExprListAppend(
@ -251,9 +252,9 @@ Expr *sqlite3LimitWhere(
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */ ** and the SELECT subtree. */
pSrc->a[0].pTab = 0; pSrc->a[0].pSTab = 0;
pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
pSrc->a[0].pTab = pTab; pSrc->a[0].pSTab = pTab;
if( pSrc->a[0].fg.isIndexedBy ){ if( pSrc->a[0].fg.isIndexedBy ){
assert( pSrc->a[0].fg.isCte==0 ); assert( pSrc->a[0].fg.isCte==0 );
pSrc->a[0].u2.pIBIndex = 0; pSrc->a[0].u2.pIBIndex = 0;

View File

@ -1877,15 +1877,30 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
SrcItem *pNewItem = &pNew->a[i]; SrcItem *pNewItem = &pNew->a[i];
const SrcItem *pOldItem = &p->a[i]; const SrcItem *pOldItem = &p->a[i];
Table *pTab; Table *pTab;
pNewItem->pSchema = pOldItem->pSchema; pNewItem->fg = pOldItem->fg;
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); if( pOldItem->fg.isSubquery ){
Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery));
if( pNewSubq==0 ){
assert( db->mallocFailed );
pNewItem->fg.isSubquery = 0;
}else{
memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq));
pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags);
if( pNewSubq->pSelect==0 ){
sqlite3DbFree(db, pNewSubq);
pNewSubq = 0;
pNewItem->fg.isSubquery = 0;
}
}
pNewItem->u4.pSubq = pNewSubq;
}else if( pOldItem->fg.fixedSchema ){
pNewItem->u4.pSchema = pOldItem->u4.pSchema;
}else{
pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase);
}
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
pNewItem->fg = pOldItem->fg;
pNewItem->iCursor = pOldItem->iCursor; pNewItem->iCursor = pOldItem->iCursor;
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
pNewItem->regResult = pOldItem->regResult;
if( pNewItem->fg.isIndexedBy ){ if( pNewItem->fg.isIndexedBy ){
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
}else if( pNewItem->fg.isTabFunc ){ }else if( pNewItem->fg.isTabFunc ){
@ -1898,11 +1913,10 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
if( pNewItem->fg.isCte ){ if( pNewItem->fg.isCte ){
pNewItem->u2.pCteUse->nUse++; pNewItem->u2.pCteUse->nUse++;
} }
pTab = pNewItem->pTab = pOldItem->pTab; pTab = pNewItem->pSTab = pOldItem->pSTab;
if( pTab ){ if( pTab ){
pTab->nTabRef++; pTab->nTabRef++;
} }
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
if( pOldItem->fg.isUsing ){ if( pOldItem->fg.isUsing ){
assert( pNewItem->fg.isUsing ); assert( pNewItem->fg.isUsing );
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing); pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
@ -1976,7 +1990,6 @@ Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){
pp = &pNew->pPrior; pp = &pNew->pPrior;
pNext = pNew; pNext = pNew;
} }
return pRet; return pRet;
} }
#else #else
@ -2996,8 +3009,8 @@ static Select *isCandidateForInOpt(const Expr *pX){
pSrc = p->pSrc; pSrc = p->pSrc;
assert( pSrc!=0 ); assert( pSrc!=0 );
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */
pTab = pSrc->a[0].pTab; pTab = pSrc->a[0].pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
assert( !IsView(pTab) ); /* FROM clause is not a view */ assert( !IsView(pTab) ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
@ -3180,7 +3193,7 @@ int sqlite3FindInIndex(
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
pTab = p->pSrc->a[0].pTab; pTab = p->pSrc->a[0].pSTab;
/* Code an OP_Transaction and OP_TableLock for <table>. */ /* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);

View File

@ -1043,9 +1043,9 @@ void sqlite3FkCheck(
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){ if( pSrc ){
SrcItem *pItem = pSrc->a; SrcItem *pItem = pSrc->a;
pItem->pTab = pFKey->pFrom; pItem->pSTab = pFKey->pFrom;
pItem->zName = pFKey->pFrom->zName; pItem->zName = pFKey->pFrom->zName;
pItem->pTab->nTabRef++; pItem->pSTab->nTabRef++;
pItem->iCursor = pParse->nTab++; pItem->iCursor = pParse->nTab++;
if( regNew!=0 ){ if( regNew!=0 ){
@ -1337,7 +1337,8 @@ static Trigger *fkActionTrigger(
if( pSrc ){ if( pSrc ){
assert( pSrc->nSrc==1 ); assert( pSrc->nSrc==1 );
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
} }
pSelect = sqlite3SelectNew(pParse, pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise), sqlite3ExprListAppend(pParse, 0, pRaise),

View File

@ -585,8 +585,11 @@ void sqlite3AutoincrementEnd(Parse *pParse){
void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){ if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
SrcItem *pItem = &pVal->pSrc->a[0]; SrcItem *pItem = &pVal->pSrc->a[0];
sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn); assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr );
sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1); if( pItem->fg.isSubquery ){
sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn);
sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1);
}
} }
} }
@ -714,6 +717,7 @@ Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
if( pRet ){ if( pRet ){
SelectDest dest; SelectDest dest;
Subquery *pSubq;
pRet->pSrc->nSrc = 1; pRet->pSrc->nSrc = 1;
pRet->pPrior = pLeft->pPrior; pRet->pPrior = pLeft->pPrior;
pRet->op = pLeft->op; pRet->op = pLeft->op;
@ -723,28 +727,32 @@ Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
assert( pLeft->pNext==0 ); assert( pLeft->pNext==0 );
assert( pRet->pNext==0 ); assert( pRet->pNext==0 );
p = &pRet->pSrc->a[0]; p = &pRet->pSrc->a[0];
p->pSelect = pLeft;
p->fg.viaCoroutine = 1; p->fg.viaCoroutine = 1;
p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
p->regReturn = ++pParse->nMem;
p->iCursor = -1; p->iCursor = -1;
assert( !p->fg.isIndexedBy && !p->fg.isTabFunc );
p->u1.nRow = 2; p->u1.nRow = 2;
sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub); if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){
sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn); pSubq = p->u4.pSubq;
pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
pSubq->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_InitCoroutine,
pSubq->regReturn, 0, pSubq->addrFillSub);
sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
/* Allocate registers for the output of the co-routine. Do so so /* Allocate registers for the output of the co-routine. Do so so
** that there are two unused registers immediately before those ** that there are two unused registers immediately before those
** used by the co-routine. This allows the code in sqlite3Insert() ** used by the co-routine. This allows the code in sqlite3Insert()
** to use these registers directly, instead of copying the output ** to use these registers directly, instead of copying the output
** of the co-routine to a separate array for processing. */ ** of the co-routine to a separate array for processing. */
dest.iSdst = pParse->nMem + 3; dest.iSdst = pParse->nMem + 3;
dest.nSdst = pLeft->pEList->nExpr; dest.nSdst = pLeft->pEList->nExpr;
pParse->nMem += 2 + dest.nSdst; pParse->nMem += 2 + dest.nSdst;
pLeft->selFlags |= SF_MultiValue; pLeft->selFlags |= SF_MultiValue;
sqlite3Select(pParse, pLeft, &dest); sqlite3Select(pParse, pLeft, &dest);
p->regResult = dest.iSdst; pSubq->regResult = dest.iSdst;
assert( pParse->nErr || dest.iSdst>0 ); assert( pParse->nErr || dest.iSdst>0 );
}
pLeft = pRet; pLeft = pRet;
} }
}else{ }else{
@ -754,12 +762,18 @@ Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
} }
if( pParse->nErr==0 ){ if( pParse->nErr==0 ){
Subquery *pSubq;
assert( p!=0 ); assert( p!=0 );
if( p->pSelect->pEList->nExpr!=pRow->nExpr ){ assert( p->fg.isSubquery );
sqlite3SelectWrongNumTermsError(pParse, p->pSelect); pSubq = p->u4.pSubq;
assert( pSubq!=0 );
assert( pSubq->pSelect!=0 );
assert( pSubq->pSelect->pEList!=0 );
if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){
sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect);
}else{ }else{
sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0); sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0);
sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn); sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn);
} }
} }
sqlite3ExprListDelete(pParse->db, pRow); sqlite3ExprListDelete(pParse->db, pRow);
@ -1110,9 +1124,14 @@ void sqlite3Insert(
&& pSelect->pPrior==0 && pSelect->pPrior==0
){ ){
SrcItem *pItem = &pSelect->pSrc->a[0]; SrcItem *pItem = &pSelect->pSrc->a[0];
dest.iSDParm = pItem->regReturn; Subquery *pSubq;
regFromSelect = pItem->regResult; assert( pItem->fg.isSubquery );
nColumn = pItem->pSelect->pEList->nExpr; pSubq = pItem->u4.pSubq;
dest.iSDParm = pSubq->regReturn;
regFromSelect = pSubq->regResult;
assert( pSubq->pSelect!=0 );
assert( pSubq->pSelect->pEList!=0 );
nColumn = pSubq->pSelect->pEList->nExpr;
ExplainQueryPlan((pParse, 0, "SCAN %S", pItem)); ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
if( bIdListInOrder && nColumn==pTab->nCol ){ if( bIdListInOrder && nColumn==pTab->nCol ){
regData = regFromSelect; regData = regFromSelect;
@ -3032,7 +3051,7 @@ static int xferOptimization(
if( pSelect->pSrc->nSrc!=1 ){ if( pSelect->pSrc->nSrc!=1 ){
return 0; /* FROM clause must have exactly one term */ return 0; /* FROM clause must have exactly one term */
} }
if( pSelect->pSrc->a[0].pSelect ){ if( pSelect->pSrc->a[0].fg.isSubquery ){
return 0; /* FROM clause cannot contain a subquery */ return 0; /* FROM clause cannot contain a subquery */
} }
if( pSelect->pWhere ){ if( pSelect->pWhere ){

View File

@ -740,11 +740,21 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
if( A ){ if( A ){
SrcItem *pNew = &A->a[A->nSrc-1]; SrcItem *pNew = &A->a[A->nSrc-1];
SrcItem *pOld = F->a; SrcItem *pOld = F->a;
assert( pOld->fg.fixedSchema==0 );
pNew->zName = pOld->zName; pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase; assert( pOld->fg.fixedSchema==0 );
pNew->pSelect = pOld->pSelect; if( pOld->fg.isSubquery ){
if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ pNew->fg.isSubquery = 1;
pNew->fg.isNestedFrom = 1; pNew->u4.pSubq = pOld->u4.pSubq;
pOld->u4.pSubq = 0;
pOld->fg.isSubquery = 0;
assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
pNew->fg.isNestedFrom = 1;
}
}else{
pNew->u4.zDatabase = pOld->u4.zDatabase;
pOld->u4.zDatabase = 0;
} }
if( pOld->fg.isTabFunc ){ if( pOld->fg.isTabFunc ){
pNew->u1.pFuncArg = pOld->u1.pFuncArg; pNew->u1.pFuncArg = pOld->u1.pFuncArg;
@ -752,8 +762,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
pOld->fg.isTabFunc = 0; pOld->fg.isTabFunc = 0;
pNew->fg.isTabFunc = 1; pNew->fg.isTabFunc = 1;
} }
pOld->zName = pOld->zDatabase = 0; pOld->zName = 0;
pOld->pSelect = 0;
} }
sqlite3SrcListDelete(pParse->db, F); sqlite3SrcListDelete(pParse->db, F);
}else{ }else{

View File

@ -848,16 +848,19 @@ void sqlite3_str_vappendf(
if( pItem->zAlias && !flag_altform2 ){ if( pItem->zAlias && !flag_altform2 ){
sqlite3_str_appendall(pAccum, pItem->zAlias); sqlite3_str_appendall(pAccum, pItem->zAlias);
}else if( pItem->zName ){ }else if( pItem->zName ){
if( pItem->zDatabase ){ if( pItem->fg.fixedSchema==0
sqlite3_str_appendall(pAccum, pItem->zDatabase); && pItem->fg.isSubquery==0
&& pItem->u4.zDatabase!=0
){
sqlite3_str_appendall(pAccum, pItem->u4.zDatabase);
sqlite3_str_append(pAccum, ".", 1); sqlite3_str_append(pAccum, ".", 1);
} }
sqlite3_str_appendall(pAccum, pItem->zName); sqlite3_str_appendall(pAccum, pItem->zName);
}else if( pItem->zAlias ){ }else if( pItem->zAlias ){
sqlite3_str_appendall(pAccum, pItem->zAlias); sqlite3_str_appendall(pAccum, pItem->zAlias);
}else{ }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */
Select *pSel = pItem->pSelect; Select *pSel = pItem->u4.pSubq->pSelect;
assert( pSel!=0 ); /* Because of tag-20240424-1 */ assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){ if( pSel->selFlags & SF_NestedFrom ){
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
}else if( pSel->selFlags & SF_MultiValue ){ }else if( pSel->selFlags & SF_MultiValue ){

View File

@ -215,7 +215,7 @@ static void extendFJMatch(
if( pNew ){ if( pNew ){
pNew->iTable = pMatch->iCursor; pNew->iTable = pMatch->iCursor;
pNew->iColumn = iColumn; pNew->iColumn = iColumn;
pNew->y.pTab = pMatch->pTab; pNew->y.pTab = pMatch->pSTab;
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ); assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
ExprSetProperty(pNew, EP_CanBeNull); ExprSetProperty(pNew, EP_CanBeNull);
*ppList = sqlite3ExprListAppend(pParse, *ppList, pNew); *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
@ -346,10 +346,10 @@ static int lookupName(
if( pSrcList ){ if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
u8 hCol; u8 hCol;
pTab = pItem->pTab; pTab = pItem->pSTab;
assert( pTab!=0 && pTab->zName!=0 ); assert( pTab!=0 && pTab->zName!=0 );
assert( pTab->nCol>0 || pParse->nErr ); assert( pTab->nCol>0 || pParse->nErr );
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem));
if( pItem->fg.isNestedFrom ){ if( pItem->fg.isNestedFrom ){
/* In this case, pItem is a subquery that has been formed from a /* In this case, pItem is a subquery that has been formed from a
** parenthesized subset of the FROM clause terms. Example: ** parenthesized subset of the FROM clause terms. Example:
@ -358,8 +358,12 @@ static int lookupName(
** This pItem -------------^ ** This pItem -------------^
*/ */
int hit = 0; int hit = 0;
assert( pItem->pSelect!=0 ); Select *pSel;
pEList = pItem->pSelect->pEList; assert( pItem->fg.isSubquery );
assert( pItem->u4.pSubq!=0 );
pSel = pItem->u4.pSubq->pSelect;
assert( pSel!=0 );
pEList = pSel->pEList;
assert( pEList!=0 ); assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol ); assert( pEList->nExpr==pTab->nCol );
for(j=0; j<pEList->nExpr; j++){ for(j=0; j<pEList->nExpr; j++){
@ -483,8 +487,8 @@ static int lookupName(
if( cntTab==0 if( cntTab==0
|| (cntTab==1 || (cntTab==1
&& ALWAYS(pMatch!=0) && ALWAYS(pMatch!=0)
&& ALWAYS(pMatch->pTab!=0) && ALWAYS(pMatch->pSTab!=0)
&& (pMatch->pTab->tabFlags & TF_Ephemeral)!=0 && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
&& (pTab->tabFlags & TF_Ephemeral)==0) && (pTab->tabFlags & TF_Ephemeral)==0)
){ ){
cntTab = 1; cntTab = 1;
@ -505,7 +509,7 @@ static int lookupName(
if( pMatch ){ if( pMatch ){
pExpr->iTable = pMatch->iCursor; pExpr->iTable = pMatch->iCursor;
assert( ExprUseYTab(pExpr) ); assert( ExprUseYTab(pExpr) );
pExpr->y.pTab = pMatch->pTab; pExpr->y.pTab = pMatch->pSTab;
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){ if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull); ExprSetProperty(pExpr, EP_CanBeNull);
} }
@ -547,7 +551,7 @@ static int lookupName(
if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
Upsert *pUpsert = pNC->uNC.pUpsert; Upsert *pUpsert = pNC->uNC.pUpsert;
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
pTab = pUpsert->pUpsertSrc->a[0].pTab; pTab = pUpsert->pUpsertSrc->a[0].pSTab;
pExpr->iTable = EXCLUDED_TABLE_NUMBER; pExpr->iTable = EXCLUDED_TABLE_NUMBER;
} }
} }
@ -630,11 +634,11 @@ static int lookupName(
&& pMatch && pMatch
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlite3IsRowid(zCol) && sqlite3IsRowid(zCol)
&& ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom)
){ ){
cnt = cntTab; cnt = cntTab;
#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2 #if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){ if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){
eNewExprOp = TK_NULL; eNewExprOp = TK_NULL;
} }
#endif #endif
@ -871,7 +875,7 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
SrcItem *pItem = &pSrc->a[iSrc]; SrcItem *pItem = &pSrc->a[iSrc];
Table *pTab; Table *pTab;
assert( ExprUseYTab(p) ); assert( ExprUseYTab(p) );
pTab = p->y.pTab = pItem->pTab; pTab = p->y.pTab = pItem->pSTab;
p->iTable = pItem->iCursor; p->iTable = pItem->iCursor;
if( p->y.pTab->iPKey==iCol ){ if( p->y.pTab->iPKey==iCol ){
p->iColumn = -1; p->iColumn = -1;
@ -990,7 +994,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pItem = pSrcList->a; pItem = pSrcList->a;
pExpr->op = TK_COLUMN; pExpr->op = TK_COLUMN;
assert( ExprUseYTab(pExpr) ); assert( ExprUseYTab(pExpr) );
pExpr->y.pTab = pItem->pTab; pExpr->y.pTab = pItem->pSTab;
pExpr->iTable = pItem->iCursor; pExpr->iTable = pItem->iCursor;
pExpr->iColumn--; pExpr->iColumn--;
pExpr->affExpr = SQLITE_AFF_INTEGER; pExpr->affExpr = SQLITE_AFF_INTEGER;
@ -1880,7 +1884,11 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** moves the pOrderBy down to the sub-query. It will be moved back ** moves the pOrderBy down to the sub-query. It will be moved back
** after the names have been resolved. */ ** after the names have been resolved. */
if( p->selFlags & SF_Converted ){ if( p->selFlags & SF_Converted ){
Select *pSub = p->pSrc->a[0].pSelect; Select *pSub;
assert( p->pSrc->a[0].fg.isSubquery );
assert( p->pSrc->a[0].u4.pSubq!=0 );
pSub = p->pSrc->a[0].u4.pSubq->pSelect;
assert( pSub!=0 );
assert( p->pSrc->nSrc==1 && p->pOrderBy ); assert( p->pSrc->nSrc==1 && p->pOrderBy );
assert( pSub->pPrior && pSub->pOrderBy==0 ); assert( pSub->pPrior && pSub->pOrderBy==0 );
pSub->pOrderBy = p->pOrderBy; pSub->pOrderBy = p->pOrderBy;
@ -1892,13 +1900,16 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
if( pOuterNC ) pOuterNC->nNestedSelect++; if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){ for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i]; SrcItem *pItem = &p->pSrc->a[i];
assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/ assert( pItem->zName!=0
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/
if( pItem->fg.isSubquery
&& (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0
){
int nRef = pOuterNC ? pOuterNC->nRef : 0; int nRef = pOuterNC ? pOuterNC->nRef : 0;
const char *zSavedContext = pParse->zAuthContext; const char *zSavedContext = pParse->zAuthContext;
if( pItem->zName ) pParse->zAuthContext = pItem->zName; if( pItem->zName ) pParse->zAuthContext = pItem->zName;
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC);
pParse->zAuthContext = zSavedContext; pParse->zAuthContext = zSavedContext;
if( pParse->nErr ) return WRC_Abort; if( pParse->nErr ) return WRC_Abort;
assert( db->mallocFailed==0 ); assert( db->mallocFailed==0 );
@ -2000,7 +2011,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** These integers will be replaced by copies of the corresponding result ** These integers will be replaced by copies of the corresponding result
** set expressions by the call to resolveOrderGroupBy() below. */ ** set expressions by the call to resolveOrderGroupBy() below. */
if( p->selFlags & SF_Converted ){ if( p->selFlags & SF_Converted ){
Select *pSub = p->pSrc->a[0].pSelect; Select *pSub;
assert( p->pSrc->a[0].fg.isSubquery );
pSub = p->pSrc->a[0].u4.pSubq->pSelect;
assert( pSub!=0 );
p->pOrderBy = pSub->pOrderBy; p->pOrderBy = pSub->pOrderBy;
pSub->pOrderBy = 0; pSub->pOrderBy = 0;
} }
@ -2267,7 +2281,7 @@ int sqlite3ResolveSelfReference(
if( pTab ){ if( pTab ){
sSrc.nSrc = 1; sSrc.nSrc = 1;
sSrc.a[0].zName = pTab->zName; sSrc.a[0].zName = pTab->zName;
sSrc.a[0].pTab = pTab; sSrc.a[0].pSTab = pTab;
sSrc.a[0].iCursor = -1; sSrc.a[0].iCursor = -1;
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP

View File

@ -332,11 +332,13 @@ int sqlite3ColumnIndex(Table *pTab, const char *zCol){
*/ */
void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){ void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
assert( pItem!=0 ); assert( pItem!=0 );
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
if( pItem->fg.isNestedFrom ){ if( pItem->fg.isNestedFrom ){
ExprList *pResults; ExprList *pResults;
assert( pItem->pSelect!=0 ); assert( pItem->fg.isSubquery );
pResults = pItem->pSelect->pEList; assert( pItem->u4.pSubq!=0 );
assert( pItem->u4.pSubq->pSelect!=0 );
pResults = pItem->u4.pSubq->pSelect->pEList;
assert( pResults!=0 ); assert( pResults!=0 );
assert( iCol>=0 && iCol<pResults->nExpr ); assert( iCol>=0 && iCol<pResults->nExpr );
pResults->a[iCol].fg.bUsed = 1; pResults->a[iCol].fg.bUsed = 1;
@ -370,9 +372,9 @@ static int tableAndColumnIndex(
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
for(i=iStart; i<=iEnd; i++){ for(i=iStart; i<=iEnd; i++){
iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol);
if( iCol>=0 if( iCol>=0
&& (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0)
){ ){
if( piTab ){ if( piTab ){
sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol); sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
@ -501,10 +503,10 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
pLeft = &pSrc->a[0]; pLeft = &pSrc->a[0];
pRight = &pLeft[1]; pRight = &pLeft[1];
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
Table *pRightTab = pRight->pTab; Table *pRightTab = pRight->pSTab;
u32 joinType; u32 joinType;
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue;
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON; joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
/* If this is a NATURAL join, synthesize an appropriate USING clause /* If this is a NATURAL join, synthesize an appropriate USING clause
@ -1930,8 +1932,12 @@ static const char *columnTypeImpl(
SrcList *pTabList = pNC->pSrcList; SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
if( j<pTabList->nSrc ){ if( j<pTabList->nSrc ){
pTab = pTabList->a[j].pTab; pTab = pTabList->a[j].pSTab;
pS = pTabList->a[j].pSelect; if( pTabList->a[j].fg.isSubquery ){
pS = pTabList->a[j].u4.pSubq->pSelect;
}else{
pS = 0;
}
}else{ }else{
pNC = pNC->pNext; pNC = pNC->pNext;
} }
@ -3983,7 +3989,9 @@ static void substSelect(
pSrc = p->pSrc; pSrc = p->pSrc;
assert( pSrc!=0 ); assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
substSelect(pSubst, pItem->pSelect, 1); if( pItem->fg.isSubquery ){
substSelect(pSubst, pItem->u4.pSubq->pSelect, 1);
}
if( pItem->fg.isTabFunc ){ if( pItem->fg.isTabFunc ){
substExprList(pSubst, pItem->u1.pFuncArg); substExprList(pSubst, pItem->u1.pFuncArg);
} }
@ -4014,7 +4022,7 @@ static void recomputeColumnsUsed(
SrcItem *pSrcItem /* Which FROM clause item to recompute */ SrcItem *pSrcItem /* Which FROM clause item to recompute */
){ ){
Walker w; Walker w;
if( NEVER(pSrcItem->pTab==0) ) return; if( NEVER(pSrcItem->pSTab==0) ) return;
memset(&w, 0, sizeof(w)); memset(&w, 0, sizeof(w));
w.xExprCallback = recomputeColumnsUsedExpr; w.xExprCallback = recomputeColumnsUsedExpr;
w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback = sqlite3SelectWalkNoop;
@ -4054,8 +4062,10 @@ static void srclistRenumberCursors(
aCsrMap[pItem->iCursor+1] = pParse->nTab++; aCsrMap[pItem->iCursor+1] = pParse->nTab++;
} }
pItem->iCursor = aCsrMap[pItem->iCursor+1]; pItem->iCursor = aCsrMap[pItem->iCursor+1];
for(p=pItem->pSelect; p; p=p->pPrior){ if( pItem->fg.isSubquery ){
srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){
srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
}
} }
} }
} }
@ -4366,7 +4376,8 @@ static int flattenSubquery(
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc ); assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
pSubitem = &pSrc->a[iFrom]; pSubitem = &pSrc->a[iFrom];
iParent = pSubitem->iCursor; iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect; assert( pSubitem->fg.isSubquery );
pSub = pSubitem->u4.pSubq->pSelect;
assert( pSub!=0 ); assert( pSub!=0 );
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
@ -4419,7 +4430,7 @@ static int flattenSubquery(
*/ */
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */ if( pSubSrc->nSrc>1 /* (3a) */
|| IsVirtual(pSubSrc->a[0].pTab) /* (3b) */ || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */ || (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
){ ){
@ -4505,14 +4516,18 @@ static int flattenSubquery(
pParse->zAuthContext = zSavedAuthContext; pParse->zAuthContext = zSavedAuthContext;
/* Delete the transient structures associated with the subquery */ /* Delete the transient structures associated with the subquery */
pSub1 = pSubitem->pSelect;
sqlite3DbFree(db, pSubitem->zDatabase); if( ALWAYS(pSubitem->fg.isSubquery) ){
pSub1 = sqlite3SubqueryDetach(db, pSubitem);
}else{
pSub1 = 0;
}
assert( pSubitem->fg.isSubquery==0 );
assert( pSubitem->fg.fixedSchema==0 );
sqlite3DbFree(db, pSubitem->zName); sqlite3DbFree(db, pSubitem->zName);
sqlite3DbFree(db, pSubitem->zAlias); sqlite3DbFree(db, pSubitem->zAlias);
pSubitem->zDatabase = 0;
pSubitem->zName = 0; pSubitem->zName = 0;
pSubitem->zAlias = 0; pSubitem->zAlias = 0;
pSubitem->pSelect = 0;
assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 ); assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
/* If the sub-query is a compound SELECT statement, then (by restrictions /* If the sub-query is a compound SELECT statement, then (by restrictions
@ -4553,8 +4568,8 @@ static int flattenSubquery(
ExprList *pOrderBy = p->pOrderBy; ExprList *pOrderBy = p->pOrderBy;
Expr *pLimit = p->pLimit; Expr *pLimit = p->pLimit;
Select *pPrior = p->pPrior; Select *pPrior = p->pPrior;
Table *pItemTab = pSubitem->pTab; Table *pItemTab = pSubitem->pSTab;
pSubitem->pTab = 0; pSubitem->pSTab = 0;
p->pOrderBy = 0; p->pOrderBy = 0;
p->pPrior = 0; p->pPrior = 0;
p->pLimit = 0; p->pLimit = 0;
@ -4562,7 +4577,7 @@ static int flattenSubquery(
p->pLimit = pLimit; p->pLimit = pLimit;
p->pOrderBy = pOrderBy; p->pOrderBy = pOrderBy;
p->op = TK_ALL; p->op = TK_ALL;
pSubitem->pTab = pItemTab; pSubitem->pSTab = pItemTab;
if( pNew==0 ){ if( pNew==0 ){
p->pPrior = pPrior; p->pPrior = pPrior;
}else{ }else{
@ -4577,11 +4592,14 @@ static int flattenSubquery(
TREETRACE(0x4,pParse,p,("compound-subquery flattener" TREETRACE(0x4,pParse,p,("compound-subquery flattener"
" creates %u as peer\n",pNew->selId)); " creates %u as peer\n",pNew->selId));
} }
assert( pSubitem->pSelect==0 ); assert( pSubitem->fg.isSubquery==0 );
} }
sqlite3DbFree(db, aCsrMap); sqlite3DbFree(db, aCsrMap);
if( db->mallocFailed ){ if( db->mallocFailed ){
pSubitem->pSelect = pSub1; assert( pSubitem->fg.fixedSchema==0 );
assert( pSubitem->fg.isSubquery==0 );
assert( pSubitem->u4.zDatabase==0 );
sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0);
return 1; return 1;
} }
@ -4592,8 +4610,8 @@ static int flattenSubquery(
** **
** pSubitem->pTab is always non-NULL by test restrictions and tests above. ** pSubitem->pTab is always non-NULL by test restrictions and tests above.
*/ */
if( ALWAYS(pSubitem->pTab!=0) ){ if( ALWAYS(pSubitem->pSTab!=0) ){
Table *pTabToDel = pSubitem->pTab; Table *pTabToDel = pSubitem->pSTab;
if( pTabToDel->nTabRef==1 ){ if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlite3ParseToplevel(pParse); Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
@ -4601,7 +4619,7 @@ static int flattenSubquery(
}else{ }else{
pTabToDel->nTabRef--; pTabToDel->nTabRef--;
} }
pSubitem->pTab = 0; pSubitem->pSTab = 0;
} }
/* The following loop runs once for each term in a compound-subquery /* The following loop runs once for each term in a compound-subquery
@ -4657,8 +4675,11 @@ static int flattenSubquery(
*/ */
for(i=0; i<nSubSrc; i++){ for(i=0; i<nSubSrc; i++){
SrcItem *pItem = &pSrc->a[i+iFrom]; SrcItem *pItem = &pSrc->a[i+iFrom];
if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
assert( pItem->fg.isTabFunc==0 ); assert( pItem->fg.isTabFunc==0 );
assert( pItem->fg.isSubquery
|| pItem->fg.fixedSchema
|| pItem->u4.zDatabase==0 );
if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
*pItem = pSubSrc->a[i]; *pItem = pSubSrc->a[i];
pItem->fg.jointype |= ltorj; pItem->fg.jointype |= ltorj;
iNewParent = pSubSrc->a[i].iCursor; iNewParent = pSubSrc->a[i].iCursor;
@ -5342,10 +5363,10 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
if( pItem->fg.isCorrelated || pItem->fg.isCte ){ if( pItem->fg.isCorrelated || pItem->fg.isCte ){
return 0; return 0;
} }
assert( pItem->pTab!=0 ); assert( pItem->pSTab!=0 );
pTab = pItem->pTab; pTab = pItem->pSTab;
assert( pItem->pSelect!=0 ); assert( pItem->fg.isSubquery );
pSub = pItem->pSelect; pSub = pItem->u4.pSubq->pSelect;
assert( pSub->pEList->nExpr==pTab->nCol ); assert( pSub->pEList->nExpr==pTab->nCol );
for(pX=pSub; pX; pX=pX->pPrior){ for(pX=pSub; pX; pX=pX->pPrior){
if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
@ -5474,13 +5495,13 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( p->pWhere if( p->pWhere
|| p->pEList->nExpr!=1 || p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1 || p->pSrc->nSrc!=1
|| p->pSrc->a[0].pSelect || p->pSrc->a[0].fg.isSubquery
|| pAggInfo->nFunc!=1 || pAggInfo->nFunc!=1
|| p->pHaving || p->pHaving
){ ){
return 0; return 0;
} }
pTab = p->pSrc->a[0].pTab; pTab = p->pSrc->a[0].pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
assert( !IsView(pTab) ); assert( !IsView(pTab) );
if( !IsOrdinaryTable(pTab) ) return 0; if( !IsOrdinaryTable(pTab) ) return 0;
@ -5505,7 +5526,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
** pFrom->pIndex and return SQLITE_OK. ** pFrom->pIndex and return SQLITE_OK.
*/ */
int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
Table *pTab = pFrom->pTab; Table *pTab = pFrom->pSTab;
char *zIndexedBy = pFrom->u1.zIndexedBy; char *zIndexedBy = pFrom->u1.zIndexedBy;
Index *pIdx; Index *pIdx;
assert( pTab!=0 ); assert( pTab!=0 );
@ -5582,7 +5603,11 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
if( pNew==0 ) return WRC_Abort; if( pNew==0 ) return WRC_Abort;
memset(&dummy, 0, sizeof(dummy)); memset(&dummy, 0, sizeof(dummy));
pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0); pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
if( pNewSrc==0 ) return WRC_Abort; assert( pNewSrc!=0 || pParse->nErr );
if( pParse->nErr ){
sqlite3SrcListDelete(db, pNewSrc);
return WRC_Abort;
}
*pNew = *p; *pNew = *p;
p->pSrc = pNewSrc; p->pSrc = pNewSrc;
p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
@ -5637,7 +5662,7 @@ static struct Cte *searchWith(
){ ){
const char *zName = pItem->zName; const char *zName = pItem->zName;
With *p; With *p;
assert( pItem->zDatabase==0 ); assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 );
assert( zName!=0 ); assert( zName!=0 );
for(p=pWith; p; p=p->pOuter){ for(p=pWith; p; p=p->pOuter){
int i; int i;
@ -5707,7 +5732,7 @@ static int resolveFromTermToCte(
Cte *pCte; /* Matched CTE (or NULL if no match) */ Cte *pCte; /* Matched CTE (or NULL if no match) */
With *pWith; /* The matching WITH */ With *pWith; /* The matching WITH */
assert( pFrom->pTab==0 ); assert( pFrom->pSTab==0 );
if( pParse->pWith==0 ){ if( pParse->pWith==0 ){
/* There are no WITH clauses in the stack. No match is possible */ /* There are no WITH clauses in the stack. No match is possible */
return 0; return 0;
@ -5717,7 +5742,8 @@ static int resolveFromTermToCte(
** go no further. */ ** go no further. */
return 0; return 0;
} }
if( pFrom->zDatabase!=0 ){ assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 );
if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){
/* The FROM term contains a schema qualifier (ex: main.t1) and so /* The FROM term contains a schema qualifier (ex: main.t1) and so
** it cannot possibly be a CTE reference. */ ** it cannot possibly be a CTE reference. */
return 0; return 0;
@ -5753,7 +5779,7 @@ static int resolveFromTermToCte(
} }
if( cannotBeFunction(pParse, pFrom) ) return 2; if( cannotBeFunction(pParse, pFrom) ) return 2;
assert( pFrom->pTab==0 ); assert( pFrom->pSTab==0 );
pTab = sqlite3DbMallocZero(db, sizeof(Table)); pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return 2; if( pTab==0 ) return 2;
pCteUse = pCte->pUse; pCteUse = pCte->pUse;
@ -5767,26 +5793,29 @@ static int resolveFromTermToCte(
} }
pCteUse->eM10d = pCte->eM10d; pCteUse->eM10d = pCte->eM10d;
} }
pFrom->pTab = pTab; pFrom->pSTab = pTab;
pTab->nTabRef = 1; pTab->nTabRef = 1;
pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->zName = sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1; pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1);
if( db->mallocFailed ) return 2; if( db->mallocFailed ) return 2;
pFrom->pSelect->selFlags |= SF_CopyCte; assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
assert( pFrom->pSelect ); pSel = pFrom->u4.pSubq->pSelect;
assert( pSel!=0 );
pSel->selFlags |= SF_CopyCte;
if( pFrom->fg.isIndexedBy ){ if( pFrom->fg.isIndexedBy ){
sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
return 2; return 2;
} }
assert( !pFrom->fg.isIndexedBy );
pFrom->fg.isCte = 1; pFrom->fg.isCte = 1;
pFrom->u2.pCteUse = pCteUse; pFrom->u2.pCteUse = pCteUse;
pCteUse->nUse++; pCteUse->nUse++;
/* Check if this is a recursive CTE. */ /* Check if this is a recursive CTE. */
pRecTerm = pSel = pFrom->pSelect; pRecTerm = pSel;
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
while( bMayRecursive && pRecTerm->op==pSel->op ){ while( bMayRecursive && pRecTerm->op==pSel->op ){
int i; int i;
@ -5794,11 +5823,13 @@ static int resolveFromTermToCte(
assert( pRecTerm->pPrior!=0 ); assert( pRecTerm->pPrior!=0 );
for(i=0; i<pSrc->nSrc; i++){ for(i=0; i<pSrc->nSrc; i++){
SrcItem *pItem = &pSrc->a[i]; SrcItem *pItem = &pSrc->a[i];
if( pItem->zDatabase==0 if( pItem->zName!=0
&& pItem->zName!=0 && !pItem->fg.hadSchema
&& ALWAYS( !pItem->fg.isSubquery )
&& (pItem->fg.fixedSchema || pItem->u4.zDatabase==0)
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName) && 0==sqlite3StrICmp(pItem->zName, pCte->zName)
){ ){
pItem->pTab = pTab; pItem->pSTab = pTab;
pTab->nTabRef++; pTab->nTabRef++;
pItem->fg.isRecursive = 1; pItem->fg.isRecursive = 1;
if( pRecTerm->selFlags & SF_Recursive ){ if( pRecTerm->selFlags & SF_Recursive ){
@ -5900,11 +5931,14 @@ void sqlite3SelectPopWith(Walker *pWalker, Select *p){
** SQLITE_NOMEM. ** SQLITE_NOMEM.
*/ */
int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
Select *pSel = pFrom->pSelect; Select *pSel;
Table *pTab; Table *pTab;
assert( pFrom->fg.isSubquery );
assert( pFrom->u4.pSubq!=0 );
pSel = pFrom->u4.pSubq->pSelect;
assert( pSel ); assert( pSel );
pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
if( pTab==0 ) return SQLITE_NOMEM; if( pTab==0 ) return SQLITE_NOMEM;
pTab->nTabRef = 1; pTab->nTabRef = 1;
if( pFrom->zAlias ){ if( pFrom->zAlias ){
@ -6024,33 +6058,35 @@ static int selectExpander(Walker *pWalker, Select *p){
*/ */
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab; Table *pTab;
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 );
if( pFrom->pTab ) continue; if( pFrom->pSTab ) continue;
assert( pFrom->fg.isRecursive==0 ); assert( pFrom->fg.isRecursive==0 );
if( pFrom->zName==0 ){ if( pFrom->zName==0 ){
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
Select *pSel = pFrom->pSelect; Select *pSel;
assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 );
pSel = pFrom->u4.pSubq->pSelect;
/* A sub-query in the FROM clause of a SELECT */ /* A sub-query in the FROM clause of a SELECT */
assert( pSel!=0 ); assert( pSel!=0 );
assert( pFrom->pTab==0 ); assert( pFrom->pSTab==0 );
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
#endif #endif
#ifndef SQLITE_OMIT_CTE #ifndef SQLITE_OMIT_CTE
}else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
if( rc>1 ) return WRC_Abort; if( rc>1 ) return WRC_Abort;
pTab = pFrom->pTab; pTab = pFrom->pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
#endif #endif
}else{ }else{
/* An ordinary table or view name in the FROM clause */ /* An ordinary table or view name in the FROM clause */
assert( pFrom->pTab==0 ); assert( pFrom->pSTab==0 );
pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort; if( pTab==0 ) return WRC_Abort;
if( pTab->nTabRef>=0xffff ){ if( pTab->nTabRef>=0xffff ){
sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
pTab->zName); pTab->zName);
pFrom->pTab = 0; pFrom->pSTab = 0;
return WRC_Abort; return WRC_Abort;
} }
pTab->nTabRef++; pTab->nTabRef++;
@ -6062,7 +6098,7 @@ static int selectExpander(Walker *pWalker, Select *p){
i16 nCol; i16 nCol;
u8 eCodeOrig = pWalker->eCode; u8 eCodeOrig = pWalker->eCode;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 ); assert( pFrom->fg.isSubquery==0 );
if( IsView(pTab) ){ if( IsView(pTab) ){
if( (db->flags & SQLITE_EnableView)==0 if( (db->flags & SQLITE_EnableView)==0
&& pTab->pSchema!=db->aDb[1].pSchema && pTab->pSchema!=db->aDb[1].pSchema
@ -6070,7 +6106,7 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
pTab->zName); pTab->zName);
} }
pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1);
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
else if( ALWAYS(IsVirtual(pTab)) else if( ALWAYS(IsVirtual(pTab))
@ -6086,7 +6122,9 @@ static int selectExpander(Walker *pWalker, Select *p){
nCol = pTab->nCol; nCol = pTab->nCol;
pTab->nCol = -1; pTab->nCol = -1;
pWalker->eCode = 1; /* Turn on Select.selId renumbering */ pWalker->eCode = 1; /* Turn on Select.selId renumbering */
sqlite3WalkSelect(pWalker, pFrom->pSelect); if( pFrom->fg.isSubquery ){
sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect);
}
pWalker->eCode = eCodeOrig; pWalker->eCode = eCodeOrig;
pTab->nCol = nCol; pTab->nCol = nCol;
} }
@ -6173,7 +6211,7 @@ static int selectExpander(Walker *pWalker, Select *p){
} }
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
int nAdd; /* Number of cols including rowid */ int nAdd; /* Number of cols including rowid */
Table *pTab = pFrom->pTab; /* Table for this data source */ Table *pTab = pFrom->pSTab; /* Table for this data source */
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */ ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
char *zTabName; /* AS name for this data source */ char *zTabName; /* AS name for this data source */
const char *zSchemaName = 0; /* Schema name for this data source */ const char *zSchemaName = 0; /* Schema name for this data source */
@ -6184,10 +6222,11 @@ static int selectExpander(Walker *pWalker, Select *p){
zTabName = pTab->zName; zTabName = pTab->zName;
} }
if( db->mallocFailed ) break; if( db->mallocFailed ) break;
assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) ); assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) );
if( pFrom->fg.isNestedFrom ){ if( pFrom->fg.isNestedFrom ){
assert( pFrom->pSelect!=0 ); assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
pNestedFrom = pFrom->pSelect->pEList; assert( pFrom->u4.pSubq->pSelect!=0 );
pNestedFrom = pFrom->u4.pSubq->pSelect->pEList;
assert( pNestedFrom!=0 ); assert( pNestedFrom!=0 );
assert( pNestedFrom->nExpr==pTab->nCol ); assert( pNestedFrom->nExpr==pTab->nCol );
assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
@ -6426,14 +6465,12 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
assert( (p->selFlags & SF_Resolved) ); assert( (p->selFlags & SF_Resolved) );
pTabList = p->pSrc; pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab; Table *pTab = pFrom->pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){
/* A sub-query in the FROM clause of a SELECT */ /* A sub-query in the FROM clause of a SELECT */
Select *pSel = pFrom->pSelect; Select *pSel = pFrom->u4.pSubq->pSelect;
if( pSel ){ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
}
} }
} }
} }
@ -7083,25 +7120,28 @@ static SrcItem *isSelfJoinView(
int iFirst, int iEnd /* Range of FROM-clause entries to search. */ int iFirst, int iEnd /* Range of FROM-clause entries to search. */
){ ){
SrcItem *pItem; SrcItem *pItem;
assert( pThis->pSelect!=0 ); Select *pSel;
if( pThis->pSelect->selFlags & SF_PushDown ) return 0; assert( pThis->fg.isSubquery );
pSel = pThis->u4.pSubq->pSelect;
assert( pSel!=0 );
if( pSel->selFlags & SF_PushDown ) return 0;
while( iFirst<iEnd ){ while( iFirst<iEnd ){
Select *pS1; Select *pS1;
pItem = &pTabList->a[iFirst++]; pItem = &pTabList->a[iFirst++];
if( pItem->pSelect==0 ) continue; if( !pItem->fg.isSubquery ) continue;
if( pItem->fg.viaCoroutine ) continue; if( pItem->fg.viaCoroutine ) continue;
if( pItem->zName==0 ) continue; if( pItem->zName==0 ) continue;
assert( pItem->pTab!=0 ); assert( pItem->pSTab!=0 );
assert( pThis->pTab!=0 ); assert( pThis->pSTab!=0 );
if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue;
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
pS1 = pItem->pSelect; pS1 = pItem->u4.pSubq->pSelect;
if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){
/* The query flattener left two different CTE tables with identical /* The query flattener left two different CTE tables with identical
** names in the same FROM clause. */ ** names in the same FROM clause. */
continue; continue;
} }
if( pItem->pSelect->selFlags & SF_PushDown ){ if( pS1->selFlags & SF_PushDown ){
/* The view was modified by some other optimization such as /* The view was modified by some other optimization such as
** pushDownWhereTerms() */ ** pushDownWhereTerms() */
continue; continue;
@ -7145,6 +7185,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
Expr *pExpr; Expr *pExpr;
Expr *pCount; Expr *pCount;
sqlite3 *db; sqlite3 *db;
SrcItem *pFrom;
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
if( p->pWhere ) return 0; if( p->pWhere ) return 0;
@ -7159,8 +7200,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
pSub = p->pSrc->a[0].pSelect; pFrom = p->pSrc->a;
if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */
pSub = pFrom->u4.pSubq->pSelect;
if( pSub->pPrior==0 ) return 0; /* Must be a compound */ if( pSub->pPrior==0 ) return 0; /* Must be a compound */
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
do{ do{
@ -7169,7 +7211,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
assert( pSub->pHaving==0 ); /* Due to the previous */ assert( pSub->pHaving==0 ); /* Due to the previous */
pSub = pSub->pPrior; /* Repeat over compound */ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub ); }while( pSub );
/* If we reach this point then it is OK to perform the transformation */ /* If we reach this point then it is OK to perform the transformation */
@ -7177,8 +7219,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
db = pParse->db; db = pParse->db;
pCount = pExpr; pCount = pExpr;
pExpr = 0; pExpr = 0;
pSub = p->pSrc->a[0].pSelect; pSub = sqlite3SubqueryDetach(db, pFrom);
p->pSrc->a[0].pSelect = 0;
sqlite3SrcListDelete(db, p->pSrc); sqlite3SrcListDelete(db, p->pSrc);
p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
while( pSub ){ while( pSub ){
@ -7223,12 +7264,12 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
for(i=0; i<pSrc->nSrc; i++){ for(i=0; i<pSrc->nSrc; i++){
SrcItem *p1 = &pSrc->a[i]; SrcItem *p1 = &pSrc->a[i];
if( p1==p0 ) continue; if( p1==p0 ) continue;
if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
return 1; return 1;
} }
if( p1->pSelect if( p1->fg.isSubquery
&& (p1->pSelect->selFlags & SF_NestedFrom)!=0 && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0
&& sameSrcAlias(p0, p1->pSelect->pSrc) && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc)
){ ){
return 1; return 1;
} }
@ -7293,7 +7334,7 @@ static int fromClauseTermCanBeCoroutine(
if( i==0 ) break; if( i==0 ) break;
i--; i--;
pItem--; pItem--;
if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ if( pItem->fg.isSubquery ) return 0; /* (1c-i) */
} }
return 1; return 1;
} }
@ -7404,7 +7445,7 @@ int sqlite3Select(
if( sameSrcAlias(p0, p->pSrc) ){ if( sameSrcAlias(p0, p->pSrc) ){
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"target object/alias may not appear in FROM clause: %s", "target object/alias may not appear in FROM clause: %s",
p0->zAlias ? p0->zAlias : p0->pTab->zName p0->zAlias ? p0->zAlias : p0->pSTab->zName
); );
goto select_end; goto select_end;
} }
@ -7443,8 +7484,8 @@ int sqlite3Select(
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
SrcItem *pItem = &pTabList->a[i]; SrcItem *pItem = &pTabList->a[i];
Select *pSub = pItem->pSelect; Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0;
Table *pTab = pItem->pTab; Table *pTab = pItem->pSTab;
/* The expander should have already created transient Table objects /* The expander should have already created transient Table objects
** even for FROM clause elements such as subqueries that do not correspond ** even for FROM clause elements such as subqueries that do not correspond
@ -7662,6 +7703,7 @@ int sqlite3Select(
SrcItem *pItem = &pTabList->a[i]; SrcItem *pItem = &pTabList->a[i];
SrcItem *pPrior; SrcItem *pPrior;
SelectDest dest; SelectDest dest;
Subquery *pSubq;
Select *pSub; Select *pSub;
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
const char *zSavedAuthContext; const char *zSavedAuthContext;
@ -7684,17 +7726,29 @@ int sqlite3Select(
** string for the fake column name seems safer. ** string for the fake column name seems safer.
*/ */
if( pItem->colUsed==0 && pItem->zName!=0 ){ if( pItem->colUsed==0 && pItem->zName!=0 ){
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); const char *zDb;
if( pItem->fg.fixedSchema ){
int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema);
zDb = db->aDb[iDb].zDbSName;
}else if( pItem->fg.isSubquery ){
zDb = 0;
}else{
zDb = pItem->u4.zDatabase;
}
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb);
} }
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Generate code for all sub-queries in the FROM clause /* Generate code for all sub-queries in the FROM clause
*/ */
pSub = pItem->pSelect; if( pItem->fg.isSubquery==0 ) continue;
if( pSub==0 || pItem->addrFillSub!=0 ) continue; pSubq = pItem->u4.pSubq;
assert( pSubq!=0 );
pSub = pSubq->pSelect;
if( pSubq->addrFillSub!=0 ) continue;
/* The code for a subquery should only be generated once. */ /* The code for a subquery should only be generated once. */
assert( pItem->addrFillSub==0 ); assert( pSubq->addrFillSub==0 );
/* Increment Parse.nHeight by the height of the largest expression /* Increment Parse.nHeight by the height of the largest expression
** tree referred to by this, the parent select. The child select ** tree referred to by this, the parent select. The child select
@ -7720,7 +7774,7 @@ int sqlite3Select(
sqlite3TreeViewSelect(0, p, 0); sqlite3TreeViewSelect(0, p, 0);
} }
#endif #endif
assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
}else{ }else{
TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n")); TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
} }
@ -7752,17 +7806,17 @@ int sqlite3Select(
*/ */
int addrTop = sqlite3VdbeCurrentAddr(v)+1; int addrTop = sqlite3VdbeCurrentAddr(v)+1;
pItem->regReturn = ++pParse->nMem; pSubq->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop);
VdbeComment((v, "%!S", pItem)); VdbeComment((v, "%!S", pItem));
pItem->addrFillSub = addrTop; pSubq->addrFillSub = addrTop;
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
sqlite3Select(pParse, pSub, &dest); sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->pSTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1; pItem->fg.viaCoroutine = 1;
pItem->regResult = dest.iSdst; pSubq->regResult = dest.iSdst;
sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeEndCoroutine(v, pSubq->regReturn);
sqlite3VdbeJumpHere(v, addrTop-1); sqlite3VdbeJumpHere(v, addrTop-1);
sqlite3ClearTempRegCache(pParse); sqlite3ClearTempRegCache(pParse);
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
@ -7780,11 +7834,16 @@ int sqlite3Select(
}else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
/* This view has already been materialized by a prior entry in /* This view has already been materialized by a prior entry in
** this same FROM clause. Reuse it. */ ** this same FROM clause. Reuse it. */
if( pPrior->addrFillSub ){ Subquery *pPriorSubq;
sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); assert( pPrior->fg.isSubquery );
pPriorSubq = pPrior->u4.pSubq;
assert( pPriorSubq!=0 );
if( pPriorSubq->addrFillSub ){
sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn,
pPriorSubq->addrFillSub);
} }
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
pSub->nSelectRow = pPrior->pSelect->nSelectRow; pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow;
}else{ }else{
/* Materialize the view. If the view is not correlated, generate a /* Materialize the view. If the view is not correlated, generate a
** subroutine to do the materialization so that subsequent uses of ** subroutine to do the materialization so that subsequent uses of
@ -7795,9 +7854,9 @@ int sqlite3Select(
int addrExplain; int addrExplain;
#endif #endif
pItem->regReturn = ++pParse->nMem; pSubq->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp0(v, OP_Goto); topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
pItem->addrFillSub = topAddr+1; pSubq->addrFillSub = topAddr+1;
pItem->fg.isMaterialized = 1; pItem->fg.isMaterialized = 1;
if( pItem->fg.isCorrelated==0 ){ if( pItem->fg.isCorrelated==0 ){
/* If the subquery is not correlated and if we are not inside of /* If the subquery is not correlated and if we are not inside of
@ -7812,17 +7871,17 @@ int sqlite3Select(
ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
sqlite3Select(pParse, pSub, &dest); sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->pSTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1);
VdbeComment((v, "end %!S", pItem)); VdbeComment((v, "end %!S", pItem));
sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
sqlite3VdbeJumpHere(v, topAddr); sqlite3VdbeJumpHere(v, topAddr);
sqlite3ClearTempRegCache(pParse); sqlite3ClearTempRegCache(pParse);
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
CteUse *pCteUse = pItem->u2.pCteUse; CteUse *pCteUse = pItem->u2.pCteUse;
pCteUse->addrM9e = pItem->addrFillSub; pCteUse->addrM9e = pSubq->addrFillSub;
pCteUse->regRtn = pItem->regReturn; pCteUse->regRtn = pSubq->regReturn;
pCteUse->iCur = pItem->iCursor; pCteUse->iCur = pItem->iCursor;
pCteUse->nRowEst = pSub->nSelectRow; pCteUse->nRowEst = pSub->nSelectRow;
} }

View File

@ -1335,6 +1335,7 @@ typedef struct Savepoint Savepoint;
typedef struct Select Select; typedef struct Select Select;
typedef struct SQLiteThread SQLiteThread; typedef struct SQLiteThread SQLiteThread;
typedef struct SelectDest SelectDest; typedef struct SelectDest SelectDest;
typedef struct Subquery Subquery;
typedef struct SrcItem SrcItem; typedef struct SrcItem SrcItem;
typedef struct SrcList SrcList; typedef struct SrcList SrcList;
typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
@ -3275,6 +3276,16 @@ struct IdList {
#define EU4_IDX 1 /* Uses IdList.a.u4.idx */ #define EU4_IDX 1 /* Uses IdList.a.u4.idx */
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
/*
** Details of the implementation of a subquery.
*/
struct Subquery {
Select *pSelect; /* A SELECT statement used in place of a table name */
int addrFillSub; /* Address of subroutine to initialize a subquery */
int regReturn; /* Register holding return address of addrFillSub */
int regResult; /* Registers holding results of a co-routine */
};
/* /*
** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems. ** The SrcList object is mostly an array of SrcItems.
@ -3287,29 +3298,40 @@ struct IdList {
** In the colUsed field, the high-order bit (bit 63) is set if the table ** In the colUsed field, the high-order bit (bit 63) is set if the table
** contains more than 63 columns and the 64-th or later column is used. ** contains more than 63 columns and the 64-th or later column is used.
** **
** Union member validity: ** Aggressive use of "union" helps keep the size of the object small. This
** has been shown to boost performance, in addition to saving memory.
** Access to union elements is gated by the following rules which should
** always be checked, either by an if-statement or by an assert().
** **
** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc ** Field Only access if this is true
** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy ** --------------- -----------------------------------
** u1.zIndexedBy fg.isIndexedBy
** u1.pFuncArg fg.isTabFunc
** u1.nRow !fg.isTabFunc && !fg.isIndexedBy ** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
** **
** u2.pIBIndex fg.isIndexedBy && !fg.isCte ** u2.pIBIndex fg.isIndexedBy
** u2.pCteUse fg.isCte && !fg.isIndexedBy ** u2.pCteUse fg.isCte
**
** u3.pOn !fg.isUsing
** u3.pUsing fg.isUsing
**
** u4.zDatabase !fg.fixedSchema && !fg.isSubquery
** u4.pSchema fg.fixedSchema
** u4.pSubq fg.isSubquery
**
** See also the sqlite3SrcListDelete() routine for assert() statements that
** check invariants on the fields of this object, especially the flags
** inside the fg struct.
*/ */
struct SrcItem { struct SrcItem {
Schema *pSchema; /* Schema to which this item is fixed */
char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */ char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */ Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */
Select *pSelect; /* A SELECT statement used in place of a table name */
int addrFillSub; /* Address of subroutine to manifest a subquery */
int regReturn; /* Register holding return address of addrFillSub */
int regResult; /* Registers holding results of a co-routine */
struct { struct {
u8 jointype; /* Type of join between this table and the previous */ u8 jointype; /* Type of join between this table and the previous */
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
unsigned isSubquery :1; /* True if this term is a subquery */
unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isTabFunc :1; /* True if table-valued-function syntax */
unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned isCorrelated :1; /* True if sub-query is correlated */
unsigned isMaterialized:1; /* This is a materialized view */ unsigned isMaterialized:1; /* This is a materialized view */
@ -3323,12 +3345,10 @@ struct SrcItem {
unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */ unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */ unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
unsigned rowidUsed :1; /* The ROWID of this table is referenced */ unsigned rowidUsed :1; /* The ROWID of this table is referenced */
unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */
unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */
} fg; } fg;
int iCursor; /* The VDBE cursor number used to access this table */ int iCursor; /* The VDBE cursor number used to access this table */
union {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union { union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
@ -3339,6 +3359,15 @@ struct SrcItem {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2; } u2;
union {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
union {
Schema *pSchema; /* Schema to which this item is fixed */
char *zDatabase; /* Name of database holding this table */
Subquery *pSubq; /* Description of a subquery */
} u4;
}; };
/* /*
@ -3598,8 +3627,10 @@ struct Select {
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
#define SF_Correlated 0x20000000 /* True if references the outer context */ #define SF_Correlated 0x20000000 /* True if references the outer context */
/* True if S exists and has SF_NestedFrom */ /* True if SrcItem X is a subquery that has SF_NestedFrom */
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) #define IsNestedFrom(X) \
((X)->fg.isSubquery && \
((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0)
/* /*
** The results of a SELECT can be distributed in several ways, as defined ** The results of a SELECT can be distributed in several ways, as defined
@ -4991,6 +5022,9 @@ int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
void sqlite3SubqueryDelete(sqlite3*,Subquery*);
Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*);
int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int);
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, OnOrUsing*); Token*, Select*, OnOrUsing*);
void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);

View File

@ -193,9 +193,9 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
x.printfFlags |= SQLITE_PRINTF_INTERNAL; x.printfFlags |= SQLITE_PRINTF_INTERNAL;
sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
if( pItem->pTab ){ if( pItem->pSTab ){
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s", sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab,
pItem->colUsed, pItem->colUsed,
pItem->fg.rowidUsed ? "+rowid" : ""); pItem->fg.rowidUsed ? "+rowid" : "");
} }
@ -230,19 +230,19 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
sqlite3StrAccumFinish(&x); sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
n = 0; n = 0;
if( pItem->pSelect ) n++; if( pItem->fg.isSubquery ) n++;
if( pItem->fg.isTabFunc ) n++; if( pItem->fg.isTabFunc ) n++;
if( pItem->fg.isUsing ) n++; if( pItem->fg.isUsing ) n++;
if( pItem->fg.isUsing ){ if( pItem->fg.isUsing ){
sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
} }
if( pItem->pSelect ){ if( pItem->fg.isSubquery ){
if( pItem->pTab ){ if( pItem->pSTab ){
Table *pTab = pItem->pTab; Table *pTab = pItem->pSTab;
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
} }
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, (--n)>0);
} }
if( pItem->fg.isTabFunc ){ if( pItem->fg.isTabFunc ){
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");

View File

@ -152,8 +152,10 @@ void sqlite3BeginTrigger(
** name on pTableName if we are reparsing out of the schema table ** name on pTableName if we are reparsing out of the schema table
*/ */
if( db->init.busy && iDb!=1 ){ if( db->init.busy && iDb!=1 ){
sqlite3DbFree(db, pTableName->a[0].zDatabase); assert( pTableName->a[0].fg.fixedSchema==0 );
pTableName->a[0].zDatabase = 0; assert( pTableName->a[0].fg.isSubquery==0 );
sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
pTableName->a[0].u4.zDatabase = 0;
} }
/* If the trigger name was unqualified, and the table is a temp table, /* If the trigger name was unqualified, and the table is a temp table,
@ -631,7 +633,8 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
} }
assert( pName->nSrc==1 ); assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase; assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
zDb = pName->a[0].u4.zDatabase;
zName = pName->a[0].zName; zName = pName->a[0].zName;
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){ for(i=OMIT_TEMPDB; i<db->nDb; i++){
@ -868,7 +871,9 @@ SrcList *sqlite3TriggerStepSrc(
Schema *pSchema = pStep->pTrig->pSchema; Schema *pSchema = pStep->pTrig->pSchema;
pSrc->a[0].zName = zName; pSrc->a[0].zName = zName;
if( pSchema!=db->aDb[1].pSchema ){ if( pSchema!=db->aDb[1].pSchema ){
pSrc->a[0].pSchema = pSchema; assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
pSrc->a[0].u4.pSchema = pSchema;
pSrc->a[0].fg.fixedSchema = 1;
} }
if( pStep->pFrom ){ if( pStep->pFrom ){
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
@ -981,7 +986,7 @@ static int sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){
pSrc = pSelect->pSrc; pSrc = pSelect->pSrc;
assert( pSrc!=0 ); assert( pSrc!=0 );
for(i=0; i<pSrc->nSrc; i++){ for(i=0; i<pSrc->nSrc; i++){
if( pSrc->a[i].pTab==pWalker->u.pTab ){ if( pSrc->a[i].pSTab==pWalker->u.pTab ){
testcase( pSelect->selFlags & SF_Correlated ); testcase( pSelect->selFlags & SF_Correlated );
pSelect->selFlags |= SF_Correlated; pSelect->selFlags |= SF_Correlated;
pWalker->eCode = 1; pWalker->eCode = 1;
@ -1052,7 +1057,7 @@ static void codeReturningTrigger(
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
sSelect.pSrc = &sFrom; sSelect.pSrc = &sFrom;
sFrom.nSrc = 1; sFrom.nSrc = 1;
sFrom.a[0].pTab = pTab; sFrom.a[0].pSTab = pTab;
sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
sFrom.a[0].iCursor = -1; sFrom.a[0].iCursor = -1;
sqlite3SelectPrep(pParse, &sSelect, 0); sqlite3SelectPrep(pParse, &sSelect, 0);

View File

@ -202,7 +202,7 @@ static void updateFromSelect(
Expr *pLimit2 = 0; Expr *pLimit2 = 0;
ExprList *pOrderBy2 = 0; ExprList *pOrderBy2 = 0;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
Table *pTab = pTabList->a[0].pTab; Table *pTab = pTabList->a[0].pSTab;
SrcList *pSrc; SrcList *pSrc;
Expr *pWhere2; Expr *pWhere2;
int eDest; int eDest;
@ -226,8 +226,8 @@ static void updateFromSelect(
if( pSrc ){ if( pSrc ){
assert( pSrc->a[0].fg.notCte ); assert( pSrc->a[0].fg.notCte );
pSrc->a[0].iCursor = -1; pSrc->a[0].iCursor = -1;
pSrc->a[0].pTab->nTabRef--; pSrc->a[0].pSTab->nTabRef--;
pSrc->a[0].pTab = 0; pSrc->a[0].pSTab = 0;
} }
if( pPk ){ if( pPk ){
for(i=0; i<pPk->nKeyCol; i++){ for(i=0; i<pPk->nKeyCol; i++){

View File

@ -104,7 +104,7 @@ int sqlite3UpsertAnalyzeTarget(
int nClause = 0; /* Counter of ON CONFLICT clauses */ int nClause = 0; /* Counter of ON CONFLICT clauses */
assert( pTabList->nSrc==1 ); assert( pTabList->nSrc==1 );
assert( pTabList->a[0].pTab!=0 ); assert( pTabList->a[0].pSTab!=0 );
assert( pUpsert!=0 ); assert( pUpsert!=0 );
assert( pUpsert->pUpsertTarget!=0 ); assert( pUpsert->pUpsertTarget!=0 );
@ -123,7 +123,7 @@ int sqlite3UpsertAnalyzeTarget(
if( rc ) return rc; if( rc ) return rc;
/* Check to see if the conflict target matches the rowid. */ /* Check to see if the conflict target matches the rowid. */
pTab = pTabList->a[0].pTab; pTab = pTabList->a[0].pSTab;
pTarget = pUpsert->pUpsertTarget; pTarget = pUpsert->pUpsertTarget;
iCursor = pTabList->a[0].iCursor; iCursor = pTabList->a[0].iCursor;
if( HasRowid(pTab) if( HasRowid(pTab)

View File

@ -171,7 +171,9 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
pSrc = p->pSrc; pSrc = p->pSrc;
if( ALWAYS(pSrc) ){ if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ if( pItem->fg.isSubquery
&& sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect)
){
return WRC_Abort; return WRC_Abort;
} }
if( pItem->fg.isTabFunc if( pItem->fg.isTabFunc

View File

@ -644,7 +644,7 @@ static int isDistinctRedundant(
** clause is redundant. */ ** clause is redundant. */
if( pTabList->nSrc!=1 ) return 0; if( pTabList->nSrc!=1 ) return 0;
iBase = pTabList->a[0].iCursor; iBase = pTabList->a[0].iCursor;
pTab = pTabList->a[0].pTab; pTab = pTabList->a[0].pSTab;
/* If any of the expressions is an IPK column on table iBase, then return /* If any of the expressions is an IPK column on table iBase, then return
** true. Note: The (p->iTable==iBase) part of this test may be false if the ** true. Note: The (p->iTable==iBase) part of this test may be false if the
@ -908,10 +908,10 @@ static int termCanDriveIndex(
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
leftCol = pTerm->u.x.leftColumn; leftCol = pTerm->u.x.leftColumn;
if( leftCol<0 ) return 0; if( leftCol<0 ) return 0;
aff = pSrc->pTab->aCol[leftCol].affinity; aff = pSrc->pSTab->aCol[leftCol].affinity;
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
testcase( pTerm->pExpr->op==TK_IS ); testcase( pTerm->pExpr->op==TK_IS );
return columnIsGoodIndexCandidate(pSrc->pTab, leftCol); return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol);
} }
#endif #endif
@ -1019,7 +1019,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
nKeyCol = 0; nKeyCol = 0;
pTabList = pWC->pWInfo->pTabList; pTabList = pWC->pWInfo->pTabList;
pSrc = &pTabList->a[pLevel->iFrom]; pSrc = &pTabList->a[pLevel->iFrom];
pTable = pSrc->pTab; pTable = pSrc->pSTab;
pWCEnd = &pWC->a[pWC->nTerm]; pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop; pLoop = pLevel->pWLoop;
idxCols = 0; idxCols = 0;
@ -1161,12 +1161,17 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Fill the automatic index with content */ /* Fill the automatic index with content */
assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] ); assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
if( pSrc->fg.viaCoroutine ){ if( pSrc->fg.viaCoroutine ){
int regYield = pSrc->regReturn; int regYield;
Subquery *pSubq;
assert( pSrc->fg.isSubquery );
pSubq = pSrc->u4.pSubq;
assert( pSubq!=0 );
regYield = pSubq->regReturn;
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub); sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v); VdbeCoverage(v);
VdbeComment((v, "next row of %s", pSrc->pTab->zName)); VdbeComment((v, "next row of %s", pSrc->pSTab->zName));
}else{ }else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
} }
@ -1188,11 +1193,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
if( pSrc->fg.viaCoroutine ){ if( pSrc->fg.viaCoroutine ){
assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 );
sqlite3VdbeChangeP2(v, addrCounter, regBase+n); sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed ); testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 ); assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
pSrc->regResult, pLevel->iIdxCur); pSrc->u4.pSubq->regResult, pLevel->iIdxCur);
sqlite3VdbeGoto(v, addrTop); sqlite3VdbeGoto(v, addrTop);
pSrc->fg.viaCoroutine = 0; pSrc->fg.viaCoroutine = 0;
}else{ }else{
@ -1283,7 +1289,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
iSrc = pLevel->iFrom; iSrc = pLevel->iFrom;
pItem = &pTabList->a[iSrc]; pItem = &pTabList->a[iSrc];
assert( pItem!=0 ); assert( pItem!=0 );
pTab = pItem->pTab; pTab = pItem->pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
sz = sqlite3LogEstToInt(pTab->nRowLogEst); sz = sqlite3LogEstToInt(pTab->nRowLogEst);
if( sz<10000 ){ if( sz<10000 ){
@ -1314,7 +1320,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
int r1 = sqlite3GetTempRange(pParse, n); int r1 = sqlite3GetTempRange(pParse, n);
int jj; int jj;
for(jj=0; jj<n; jj++){ for(jj=0; jj<n; jj++){
assert( pIdx->pTable==pItem->pTab ); assert( pIdx->pTable==pItem->pSTab );
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
} }
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
@ -1395,7 +1401,7 @@ static sqlite3_index_info *allocateIndexInfo(
WhereClause *p; WhereClause *p;
assert( pSrc!=0 ); assert( pSrc!=0 );
pTab = pSrc->pTab; pTab = pSrc->pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
assert( IsVirtual(pTab) ); assert( IsVirtual(pTab) );
@ -2403,7 +2409,7 @@ void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
WhereInfo *pWInfo = pWC->pWInfo; WhereInfo *pWInfo = pWC->pWInfo;
int nb = 1+(pWInfo->pTabList->nSrc+3)/4; int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
SrcItem *pItem = pWInfo->pTabList->a + p->iTab; SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
Table *pTab = pItem->pTab; Table *pTab = pItem->pSTab;
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
@ -3391,7 +3397,7 @@ static int whereLoopAddBtreeIndex(
** 2. Stepping forward in the index pNew->nOut times to find all ** 2. Stepping forward in the index pNew->nOut times to find all
** additional matching entries. ** additional matching entries.
*/ */
assert( pSrc->pTab->szTabRow>0 ); assert( pSrc->pSTab->szTabRow>0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* The pProbe->szIdxRow is low for an IPK table since the interior /* The pProbe->szIdxRow is low for an IPK table since the interior
** pages are small. Thus szIdxRow gives a good estimate of seek cost. ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
@ -3399,7 +3405,7 @@ static int whereLoopAddBtreeIndex(
** under-estimate the scanning cost. */ ** under-estimate the scanning cost. */
rCostIdx = pNew->nOut + 16; rCostIdx = pNew->nOut + 16;
}else{ }else{
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow;
} }
rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx); rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
@ -3864,9 +3870,9 @@ static int whereLoopAddBtree(
pWInfo = pBuilder->pWInfo; pWInfo = pBuilder->pWInfo;
pTabList = pWInfo->pTabList; pTabList = pWInfo->pTabList;
pSrc = pTabList->a + pNew->iTab; pSrc = pTabList->a + pNew->iTab;
pTab = pSrc->pTab; pTab = pSrc->pSTab;
pWC = pBuilder->pWC; pWC = pBuilder->pWC;
assert( !IsVirtual(pSrc->pTab) ); assert( !IsVirtual(pSrc->pSTab) );
if( pSrc->fg.isIndexedBy ){ if( pSrc->fg.isIndexedBy ){
assert( pSrc->fg.isCte==0 ); assert( pSrc->fg.isCte==0 );
@ -3891,7 +3897,7 @@ static int whereLoopAddBtree(
sPk.idxType = SQLITE_IDXTYPE_IPK; sPk.idxType = SQLITE_IDXTYPE_IPK;
aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0; aiRowEstPk[1] = 0;
pFirst = pSrc->pTab->pIndex; pFirst = pSrc->pSTab->pIndex;
if( pSrc->fg.notIndexed==0 ){ if( pSrc->fg.notIndexed==0 ){
/* The real indices of the table are only considered if the /* The real indices of the table are only considered if the
** NOT INDEXED qualifier is omitted from the FROM clause */ ** NOT INDEXED qualifier is omitted from the FROM clause */
@ -4010,9 +4016,9 @@ static int whereLoopAddBtree(
#endif #endif
ApplyCostMultiplier(pNew->rRun, pTab->costMult); ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize); whereLoopOutputAdjust(pWC, pNew, rSize);
if( pSrc->pSelect ){ if( pSrc->fg.isSubquery ){
if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE; if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
pNew->u.btree.pOrderBy = pSrc->pSelect->pOrderBy; pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
} }
rc = whereLoopInsert(pBuilder, pNew); rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize; pNew->nOut = rSize;
@ -4238,7 +4244,7 @@ static int whereLoopAddVirtualOne(
pHidden->mHandleIn = 0; pHidden->mHandleIn = 0;
/* Invoke the virtual table xBestIndex() method */ /* Invoke the virtual table xBestIndex() method */
rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo);
if( rc ){ if( rc ){
if( rc==SQLITE_CONSTRAINT ){ if( rc==SQLITE_CONSTRAINT ){
/* If the xBestIndex method returns SQLITE_CONSTRAINT, that means /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
@ -4268,7 +4274,7 @@ static int whereLoopAddVirtualOne(
|| pNew->aLTerm[iTerm]!=0 || pNew->aLTerm[iTerm]!=0
|| pIdxCons->usable==0 || pIdxCons->usable==0
){ ){
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
freeIdxStr(pIdxInfo); freeIdxStr(pIdxInfo);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@ -4331,7 +4337,7 @@ static int whereLoopAddVirtualOne(
if( pNew->aLTerm[i]==0 ){ if( pNew->aLTerm[i]==0 ){
/* The non-zero argvIdx values must be contiguous. Raise an /* The non-zero argvIdx values must be contiguous. Raise an
** error if they are not */ ** error if they are not */
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
freeIdxStr(pIdxInfo); freeIdxStr(pIdxInfo);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@ -4533,7 +4539,7 @@ static int whereLoopAddVirtual(
pWC = pBuilder->pWC; pWC = pBuilder->pWC;
pNew = pBuilder->pNew; pNew = pBuilder->pNew;
pSrc = &pWInfo->pTabList->a[pNew->iTab]; pSrc = &pWInfo->pTabList->a[pNew->iTab];
assert( IsVirtual(pSrc->pTab) ); assert( IsVirtual(pSrc->pSTab) );
p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
if( p==0 ) return SQLITE_NOMEM_BKPT; if( p==0 ) return SQLITE_NOMEM_BKPT;
pNew->rSetup = 0; pNew->rSetup = 0;
@ -4547,7 +4553,7 @@ static int whereLoopAddVirtual(
} }
/* First call xBestIndex() with all constraints usable. */ /* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName));
WHERETRACE(0x800, (" VirtualOne: all usable\n")); WHERETRACE(0x800, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne( rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
@ -4629,7 +4635,7 @@ static int whereLoopAddVirtual(
} }
freeIndexInfo(pParse->db, p); freeIndexInfo(pParse->db, p);
WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc));
return rc; return rc;
} }
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
@ -4701,7 +4707,7 @@ static int whereLoopAddOr(
} }
#endif #endif
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){ if( IsVirtual(pItem->pSTab) ){
rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
}else }else
#endif #endif
@ -4815,7 +4821,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
mPrereq = 0; mPrereq = 0;
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){ if( IsVirtual(pItem->pSTab) ){
SrcItem *p; SrcItem *p;
for(p=&pItem[1]; p<pEnd; p++){ for(p=&pItem[1]; p<pEnd; p++){
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){ if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
@ -5451,7 +5457,7 @@ static int computeMxChoice(WhereInfo *pWInfo, LogEst nRowEst){
if( sqlite3WhereTrace&0x4 ){ if( sqlite3WhereTrace&0x4 ){
SrcItem *pItem = pWInfo->pTabList->a + iLoop; SrcItem *pItem = pWInfo->pTabList->a + iLoop;
sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n", sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
pItem->zAlias ? pItem->zAlias : pItem->pTab->zName, pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName,
nDep, rDelta); nDep, rDelta);
} }
#endif #endif
@ -6001,7 +6007,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
assert( pWInfo->pTabList->nSrc>=1 ); assert( pWInfo->pTabList->nSrc>=1 );
pItem = pWInfo->pTabList->a; pItem = pWInfo->pTabList->a;
pTab = pItem->pTab; pTab = pItem->pSTab;
if( IsVirtual(pTab) ) return 0; if( IsVirtual(pTab) ) return 0;
if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){ if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
testcase( pItem->fg.isIndexedBy ); testcase( pItem->fg.isIndexedBy );
@ -6264,7 +6270,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
WhereLoop *pLoop = pWInfo->a[i].pWLoop; WhereLoop *pLoop = pWInfo->a[i].pWLoop;
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
Table *pTab = pItem->pTab; Table *pTab = pItem->pSTab;
if( (pTab->tabFlags & TF_HasStat1)==0 ) break; if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
pTab->tabFlags |= TF_MaybeReanalyze; pTab->tabFlags |= TF_MaybeReanalyze;
if( i>=1 if( i>=1
@ -6421,8 +6427,8 @@ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
SrcItem *pItem = &pWInfo->pTabList->a[ii]; SrcItem *pItem = &pWInfo->pTabList->a[ii];
if( !pItem->fg.isCte if( !pItem->fg.isCte
|| pItem->u2.pCteUse->eM10d!=M10d_Yes || pItem->u2.pCteUse->eM10d!=M10d_Yes
|| NEVER(pItem->pSelect==0) || NEVER(pItem->fg.isSubquery==0)
|| pItem->pSelect->pOrderBy==0 || pItem->u4.pSubq->pSelect->pOrderBy==0
){ ){
pWInfo->revMask |= MASKBIT(ii); pWInfo->revMask |= MASKBIT(ii);
} }
@ -6912,15 +6918,15 @@ WhereInfo *sqlite3WhereBegin(
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
int bOnerow = (wsFlags & WHERE_ONEROW)!=0; int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) );
if( bOnerow || ( if( bOnerow || (
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
&& !IsVirtual(pTabList->a[0].pTab) && !IsVirtual(pTabList->a[0].pSTab)
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
&& OptimizationEnabled(db, SQLITE_OnePass) && OptimizationEnabled(db, SQLITE_OnePass)
)){ )){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){
if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
bFordelete = OPFLAG_FORDELETE; bFordelete = OPFLAG_FORDELETE;
} }
@ -6938,7 +6944,7 @@ WhereInfo *sqlite3WhereBegin(
SrcItem *pTabItem; SrcItem *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom]; pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab; pTab = pTabItem->pSTab;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
pLoop = pLevel->pWLoop; pLoop = pLevel->pWLoop;
if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
@ -7009,7 +7015,7 @@ WhereInfo *sqlite3WhereBegin(
iIndexCur = pLevel->iTabCur; iIndexCur = pLevel->iTabCur;
op = 0; op = 0;
}else if( pWInfo->eOnePass!=ONEPASS_OFF ){ }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
Index *pJ = pTabItem->pTab->pIndex; Index *pJ = pTabItem->pSTab->pIndex;
iIndexCur = iAuxArg; iIndexCur = iAuxArg;
assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
while( ALWAYS(pJ) && pJ!=pIx ){ while( ALWAYS(pJ) && pJ!=pIx ){
@ -7076,7 +7082,7 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
pRJ->regReturn = ++pParse->nMem; pRJ->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
assert( pTab==pTabItem->pTab ); assert( pTab==pTabItem->pSTab );
if( HasRowid(pTab) ){ if( HasRowid(pTab) ){
KeyInfo *pInfo; KeyInfo *pInfo;
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
@ -7115,11 +7121,14 @@ WhereInfo *sqlite3WhereBegin(
wsFlags = pLevel->pWLoop->wsFlags; wsFlags = pLevel->pWLoop->wsFlags;
pSrc = &pTabList->a[pLevel->iFrom]; pSrc = &pTabList->a[pLevel->iFrom];
if( pSrc->fg.isMaterialized ){ if( pSrc->fg.isMaterialized ){
Subquery *pSubq;
assert( pSrc->fg.isSubquery );
pSubq = pSrc->u4.pSubq;
if( pSrc->fg.isCorrelated ){ if( pSrc->fg.isCorrelated ){
sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
}else{ }else{
int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
sqlite3VdbeJumpHere(v, iOnce); sqlite3VdbeJumpHere(v, iOnce);
} }
} }
@ -7334,9 +7343,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
assert( pLevel->iTabCur==pSrc->iCursor ); assert( pLevel->iTabCur==pSrc->iCursor );
if( pSrc->fg.viaCoroutine ){ if( pSrc->fg.viaCoroutine ){
int m, n; int m, n;
n = pSrc->regResult; assert( pSrc->fg.isSubquery );
assert( pSrc->pTab!=0 ); n = pSrc->u4.pSubq->regResult;
m = pSrc->pTab->nCol; assert( pSrc->pSTab!=0 );
m = pSrc->pSTab->nCol;
sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1); sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
} }
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
@ -7360,7 +7370,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
} }
VdbeModuleComment((v, "End WHERE-loop%d: %s", i, VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName));
} }
assert( pWInfo->nLevel<=pTabList->nSrc ); assert( pWInfo->nLevel<=pTabList->nSrc );
@ -7369,7 +7379,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
VdbeOp *pOp, *pLastOp; VdbeOp *pOp, *pLastOp;
Index *pIdx = 0; Index *pIdx = 0;
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab; Table *pTab = pTabItem->pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
pLoop = pLevel->pWLoop; pLoop = pLevel->pWLoop;
@ -7388,9 +7398,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
*/ */
if( pTabItem->fg.viaCoroutine ){ if( pTabItem->fg.viaCoroutine ){
testcase( pParse->db->mallocFailed ); testcase( pParse->db->mallocFailed );
assert( pTabItem->regResult>=0 ); assert( pTabItem->fg.isSubquery );
assert( pTabItem->u4.pSubq->regResult>=0 );
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult, 0); pTabItem->u4.pSubq->regResult, 0);
continue; continue;
} }

View File

@ -157,7 +157,7 @@ int sqlite3WhereExplainOneScan(
assert( pLoop->u.btree.pIndex!=0 ); assert( pLoop->u.btree.pIndex!=0 );
pIdx = pLoop->u.btree.pIndex; pIdx = pLoop->u.btree.pIndex;
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){
if( isSearch ){ if( isSearch ){
zFmt = "PRIMARY KEY"; zFmt = "PRIMARY KEY";
} }
@ -254,7 +254,7 @@ int sqlite3WhereExplainBloomFilter(
sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem); sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
pLoop = pLevel->pWLoop; pLoop = pLevel->pWLoop;
if( pLoop->wsFlags & WHERE_IPK ){ if( pLoop->wsFlags & WHERE_IPK ){
const Table *pTab = pItem->pTab; const Table *pTab = pItem->pSTab;
if( pTab->iPKey>=0 ){ if( pTab->iPKey>=0 ){
sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName); sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
}else{ }else{
@ -317,7 +317,9 @@ void sqlite3WhereAddScanStatus(
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
} }
}else{ }else{
int addr = pSrclist->a[pLvl->iFrom].addrFillSub; int addr;
assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
@ -1454,7 +1456,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
iCur = pTabItem->iCursor; iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1; bRev = (pWInfo->revMask>>iLevel)&1;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); VdbeModuleComment((v, "Begin WHERE-loop%d: %s",
iLevel, pTabItem->pSTab->zName));
#if WHERETRACE_ENABLED /* 0x4001 */ #if WHERETRACE_ENABLED /* 0x4001 */
if( sqlite3WhereTrace & 0x1 ){ if( sqlite3WhereTrace & 0x1 ){
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
@ -1509,11 +1512,15 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Special case of a FROM clause subquery implemented as a co-routine */ /* Special case of a FROM clause subquery implemented as a co-routine */
if( pTabItem->fg.viaCoroutine ){ if( pTabItem->fg.viaCoroutine ){
int regYield = pTabItem->regReturn; int regYield;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); Subquery *pSubq;
assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 );
pSubq = pTabItem->u4.pSubq;
regYield = pSubq->regReturn;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeCoverage(v); VdbeCoverage(v);
VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); VdbeComment((v, "next row of %s", pTabItem->pSTab->zName));
pLevel->op = OP_Goto; pLevel->op = OP_Goto;
}else }else
@ -2242,7 +2249,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
int untestedTerms = 0; /* Some terms not completely tested */ int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */ int ii; /* Loop counter */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
Table *pTab = pTabItem->pTab; Table *pTab = pTabItem->pSTab;
pTerm = pLoop->aLTerm[0]; pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 ); assert( pTerm!=0 );
@ -2701,7 +2708,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** least once. This is accomplished by storing the PK for the row in ** least once. This is accomplished by storing the PK for the row in
** both the iMatch index and the regBloom Bloom filter. ** both the iMatch index and the regBloom Bloom filter.
*/ */
pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab;
if( HasRowid(pTab) ){ if( HasRowid(pTab) ){
r = sqlite3GetTempRange(pParse, 2); r = sqlite3GetTempRange(pParse, 2);
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1); sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
@ -2808,7 +2815,7 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
Bitmask mAll = 0; Bitmask mAll = 0;
int k; int k;
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName)); ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn, sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
pRJ->regReturn); pRJ->regReturn);
for(k=0; k<iLevel; k++){ for(k=0; k<iLevel; k++){
@ -2818,9 +2825,13 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom]; pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
mAll |= pWInfo->a[k].pWLoop->maskSelf; mAll |= pWInfo->a[k].pWLoop->maskSelf;
if( pRight->fg.viaCoroutine ){ if( pRight->fg.viaCoroutine ){
Subquery *pSubq;
assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 );
pSubq = pRight->u4.pSubq;
assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 );
sqlite3VdbeAddOp3( sqlite3VdbeAddOp3(
v, OP_Null, 0, pRight->regResult, v, OP_Null, 0, pSubq->regResult,
pRight->regResult + pRight->pSelect->pEList->nExpr-1 pSubq->regResult + pSubq->pSelect->pEList->nExpr-1
); );
} }
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
@ -2858,7 +2869,7 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
int nPk; int nPk;
int jmp; int jmp;
int addrCont = sqlite3WhereContinueLabel(pSubWInfo); int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
Table *pTab = pTabItem->pTab; Table *pTab = pTabItem->pSTab;
if( HasRowid(pTab) ){ if( HasRowid(pTab) ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
nPk = 1; nPk = 1;

View File

@ -967,7 +967,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
if( ALWAYS(pSrc!=0) ){ if( ALWAYS(pSrc!=0) ){
int i; int i;
for(i=0; i<pSrc->nSrc; i++){ for(i=0; i<pSrc->nSrc; i++){
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); if( pSrc->a[i].fg.isSubquery ){
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect);
}
if( pSrc->a[i].fg.isUsing==0 ){ if( pSrc->a[i].fg.isUsing==0 ){
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn); mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
} }
@ -1005,7 +1007,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
int iCur; int iCur;
do{ do{
iCur = pFrom->a[j].iCursor; iCur = pFrom->a[j].iCursor;
for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue; if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){ for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue; if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
@ -1049,7 +1051,7 @@ static int exprMightBeIndexed(
for(i=0; i<pFrom->nSrc; i++){ for(i=0; i<pFrom->nSrc; i++){
Index *pIdx; Index *pIdx;
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr ){ if( pIdx->aColExpr ){
return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i); return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
} }
@ -1637,7 +1639,7 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */ assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
if( p->pGroupBy==0 if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */ && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */ && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */
){ ){
ExprList *pOrderBy = p->pOrderBy; ExprList *pOrderBy = p->pOrderBy;
int iCsr = p->pSrc->a[0].iCursor; int iCsr = p->pSrc->a[0].iCursor;
@ -1858,7 +1860,7 @@ void sqlite3WhereTabFuncArgs(
Expr *pColRef; Expr *pColRef;
Expr *pTerm; Expr *pTerm;
if( pItem->fg.isTabFunc==0 ) return; if( pItem->fg.isTabFunc==0 ) return;
pTab = pItem->pTab; pTab = pItem->pSTab;
assert( pTab!=0 ); assert( pTab!=0 );
pArgs = pItem->u1.pFuncArg; pArgs = pItem->u1.pFuncArg;
if( pArgs==0 ) return; if( pArgs==0 ) return;

View File

@ -1077,9 +1077,10 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
** of sqlite3DbMallocRawNN() called from ** of sqlite3DbMallocRawNN() called from
** sqlite3SrcListAppend() */ ** sqlite3SrcListAppend() */
if( p->pSrc ){ if( p->pSrc==0 ){
sqlite3SelectDelete(db, pSub);
}else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){
Table *pTab2; Table *pTab2;
p->pSrc->a[0].pSelect = pSub;
p->pSrc->a[0].fg.isCorrelated = 1; p->pSrc->a[0].fg.isCorrelated = 1;
sqlite3SrcListAssignCursors(pParse, p->pSrc); sqlite3SrcListAssignCursors(pParse, p->pSrc);
pSub->selFlags |= SF_Expanded|SF_OrderByReqd; pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
@ -1093,7 +1094,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
}else{ }else{
memcpy(pTab, pTab2, sizeof(Table)); memcpy(pTab, pTab2, sizeof(Table));
pTab->tabFlags |= TF_Ephemeral; pTab->tabFlags |= TF_Ephemeral;
p->pSrc->a[0].pTab = pTab; p->pSrc->a[0].pSTab = pTab;
pTab = pTab2; pTab = pTab2;
memset(&w, 0, sizeof(w)); memset(&w, 0, sizeof(w));
w.xExprCallback = sqlite3WindowExtraAggFuncDepth; w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
@ -1101,8 +1102,6 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
w.xSelectCallback2 = sqlite3WalkerDepthDecrease; w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
sqlite3WalkSelect(&w, pSub); sqlite3WalkSelect(&w, pSub);
} }
}else{
sqlite3SelectDelete(db, pSub);
} }
if( db->mallocFailed ) rc = SQLITE_NOMEM; if( db->mallocFailed ) rc = SQLITE_NOMEM;
@ -1389,10 +1388,15 @@ int sqlite3WindowCompare(
** and initialize registers and cursors used by sqlite3WindowCodeStep(). ** and initialize registers and cursors used by sqlite3WindowCodeStep().
*/ */
void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
Window *pMWin = pSelect->pWin;
Window *pWin; Window *pWin;
Vdbe *v = sqlite3GetVdbe(pParse); int nEphExpr;
Window *pMWin;
Vdbe *v;
assert( pSelect->pSrc->a[0].fg.isSubquery );
nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr;
pMWin = pSelect->pWin;
v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
@ -2789,7 +2793,7 @@ void sqlite3WindowCodeStep(
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
int csrWrite; /* Cursor used to write to eph. table */ int csrWrite; /* Cursor used to write to eph. table */
int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */
int iInput; /* To iterate through sub cols */ int iInput; /* To iterate through sub cols */
int addrNe; /* Address of OP_Ne */ int addrNe; /* Address of OP_Ne */
int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */

View File

@ -156,6 +156,16 @@ do_execsql_test 1.15 {
SELECT * FROM t4; SELECT * FROM t4;
} {4 5} } {4 5}
do_execsql_test 1.15.2 {
WITH
t4(x) AS (
VALUES(4)
UNION ALL
SELECT x+1 FROM (SELECT * FROM main.t4) WHERE x<10
)
SELECT * FROM t4;
} {4 5}
do_catchsql_test 1.16 { do_catchsql_test 1.16 {
WITH WITH
t4(x) AS ( t4(x) AS (