Compare commits
181 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eeada07457 | |||
| 00e5d3d59e | |||
| 8aa7f4d813 | |||
| 207f626356 | |||
| d88fd53989 | |||
| 689f1b9246 | |||
| 63879a2c99 | |||
| 72d620bdb1 | |||
| 56f38db700 | |||
| c35f02d676 | |||
| 7a8809907f | |||
| 85f93850f7 | |||
| 3a45d30ea5 | |||
| b94182bdc6 | |||
| bae50d6719 | |||
| 7497364749 | |||
| 2aa1086cab | |||
| a25bbaf74a | |||
| c64f0e71c1 | |||
| 3d5665366f | |||
| 8e8e9de87e | |||
| 0c0d0526dc | |||
| 08e1a6a29b | |||
| de7a820fd0 | |||
| 07fd1bf323 | |||
| a087eb8f6d | |||
| 4bea8c6b56 | |||
| 09121b0523 | |||
| 22b541b55a | |||
| 609959285b | |||
| 9684d71081 | |||
| 5487cdcc0a | |||
| 3e4314b4f8 | |||
| 0e464b5f51 | |||
| 5eb6e09795 | |||
| a9cdb90421 | |||
| 95fe38f2fc | |||
| 7f417569f7 | |||
| 1a6bac0d2f | |||
| 7980fadcef | |||
| ecb386b71f | |||
| 30d2aab5fd | |||
| 6c7e89b48a | |||
| b77c312956 | |||
| d63c07e6c5 | |||
| 0748e8bf9a | |||
| ab843a51d3 | |||
| 45e41b7371 | |||
| f054c34372 | |||
| d6bb6000ef | |||
| da653b897d | |||
| 67f70bea06 | |||
| 9b843f0ce0 | |||
| 1ca14b74ed | |||
| 9c2d7aa7d0 | |||
| 8318b55d87 | |||
| 1c69bc912d | |||
| abb4e7598c | |||
| 11140addbb | |||
| 6dab33bf40 | |||
| a74b4c4d45 | |||
| 7e9a56f70f | |||
| 503ad9c72d | |||
| 825a6bffc4 | |||
| 18f8600fe6 | |||
| 6403e77d3b | |||
| 22b410d894 | |||
| e60ffa3350 | |||
| 910e57b9df | |||
| 41150bf35b | |||
| bc656e220f | |||
| 815b782e99 | |||
| b465a83353 | |||
| d4e9caf987 | |||
| 2627cbd4b5 | |||
| befbb40f44 | |||
| cbde37d8e4 | |||
| 4d0d071a53 | |||
| 3117b7b081 | |||
| e32d6a0bbf | |||
| de75638b33 | |||
| 2e61588931 | |||
| d737b16f92 | |||
| 3b8c7545df | |||
| 1c2bf41a12 | |||
| ec39c96473 | |||
| f80bb195b3 | |||
| 7466d5665a | |||
| 23f240b325 | |||
| a20922cb20 | |||
| 25f2ce6e71 | |||
| 7348ca4e0b | |||
| 2e1bcc9dd0 | |||
| 1942d1f236 | |||
| 41db500274 | |||
| e98b71e65d | |||
| 088b615acd | |||
| 01a6c16e0c | |||
| a1848a5d22 | |||
| d875c7eefe | |||
| d973268ccf | |||
| abf86bd313 | |||
| 79a25ee021 | |||
| d0453f7ec5 | |||
| a3e2518bb3 | |||
| f68621fe83 | |||
| 2bd9f44a18 | |||
| fe14699765 | |||
| 6fda176ba6 | |||
| 052953a4e6 | |||
| fdc621aece | |||
| cebc8009ed | |||
| 2d27d36cba | |||
| b192970809 | |||
| 977eef6cdc | |||
| bdbda1eb1f | |||
| be60896485 | |||
| e62d9149a6 | |||
| bb3c62a758 | |||
| 4ce7bf9156 | |||
| 22c4bc8991 | |||
| a99e325468 | |||
| 358424aeff | |||
| a51379ad78 | |||
| b3ebf3043f | |||
| 79f60034ee | |||
| d549a702b3 | |||
| 2c31c00bfa | |||
| 37f5584a2f | |||
| d345dcf39a | |||
| 375f182b1d | |||
| c504f677b6 | |||
| eab6c125bd | |||
| 95b1036e9a | |||
| b60d1fbe8e | |||
| 7c96039492 | |||
| 3ac624344d | |||
| f7ecd956ce | |||
| 94e615a6ac | |||
| 12c35ec322 | |||
| 3b79f7580a | |||
| 146e64d2e4 | |||
| f7309bce10 | |||
| 0879d5f9e0 | |||
| 949e2ab49a | |||
| 57d4b5bde1 | |||
| 6625d6d873 | |||
| 61dac44eb9 | |||
| a70782407d | |||
| f7413d9acf | |||
| b087de063b | |||
| c133bab72a | |||
| ec27077c4f | |||
| 6134b2dff2 | |||
| ff02ac7f07 | |||
| c583719b65 | |||
| 37259f4e6b | |||
| 3a6e4c59c4 | |||
| b77c07a715 | |||
| 189c065942 | |||
| d198526289 | |||
| 79d2658671 | |||
| 8a28ce7bc2 | |||
| 41798d5bbc | |||
| 529394e5c1 | |||
| 9debb58e48 | |||
| 62ed36bb5d | |||
| fcde633f7c | |||
| e21e36dd2c | |||
| a20c71e9e8 | |||
| ac8c438a79 | |||
| 039132be20 | |||
| de24dd706e | |||
| 86c1beb402 | |||
| 7c1734b09e | |||
| c2308ad2a0 | |||
| c187163090 | |||
| f8bdcfa3f1 | |||
| a76ac88af8 | |||
| 7d0ae00361 | |||
| 81a23623d8 |
@@ -296,7 +296,7 @@ struct Fts5Index {
|
||||
sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */
|
||||
sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */
|
||||
sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
|
||||
sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */
|
||||
sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */
|
||||
sqlite3_stmt *pIdxSelect;
|
||||
int nRead; /* Total number of blocks read */
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# 2014 August 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set ::testprefix rbubusy
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
test_sqlite3_log xLog
|
||||
reset_db
|
||||
|
||||
set db_sql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b, c);
|
||||
INSERT INTO t1 VALUES(1000, 2000, 3000);
|
||||
}
|
||||
|
||||
set rbu_sql {
|
||||
CREATE TABLE data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 2, 3, 0);
|
||||
INSERT INTO data_t1 VALUES(4, 5, 6, 0);
|
||||
INSERT INTO data_t1 VALUES(7, 8, 9, 0);
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
forcedelete rbu.db
|
||||
sqlite3 rbu rbu.db
|
||||
rbu eval $rbu_sql
|
||||
rbu close
|
||||
|
||||
db eval $db_sql
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
BEGIN;
|
||||
SELECT * FROM t1
|
||||
} {1000 2000 3000}
|
||||
|
||||
do_test 1.3 {
|
||||
sqlite3rbu rbu test.db rbu.db
|
||||
rbu step
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 1.4 {
|
||||
while 1 {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
}
|
||||
set rc
|
||||
} {SQLITE_BUSY}
|
||||
|
||||
do_test 1.5 {
|
||||
rbu step
|
||||
} {SQLITE_BUSY}
|
||||
|
||||
do_test 1.6 {
|
||||
db eval COMMIT
|
||||
rbu step
|
||||
} {SQLITE_BUSY}
|
||||
catch { rbu close }
|
||||
|
||||
do_test 1.7 {
|
||||
sqlite3rbu rbu test.db rbu.db
|
||||
while 1 {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
}
|
||||
set rc
|
||||
} {SQLITE_DONE}
|
||||
|
||||
rbu close
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
test_sqlite3_log
|
||||
sqlite3_initialize
|
||||
finish_test
|
||||
|
||||
@@ -342,7 +342,7 @@ do_eqp_execsql_test 7.2 {
|
||||
QUERY PLAN
|
||||
|--SCAN xdir
|
||||
|--SCAN rt VIRTUAL TABLE INDEX 2:B0D1
|
||||
`--SCAN ydir
|
||||
`--SCAN ydir LEFT-JOIN
|
||||
} {
|
||||
5 1 2 7 12 14 {}
|
||||
5 2 2 7 8 12 10
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Tokenizer\sand\sgrammar\srules\ssufficient\sfor\sthe\sMERGE\scommand.
|
||||
D 2022-04-08T10:35:32.552
|
||||
C Merge\sBloom\sfilter\sbug\sfix\sfrom\strunk\sinto\sthe\sright-join\sbranch.
|
||||
D 2022-05-03T16:26:50.091
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -119,7 +119,7 @@ F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b7292
|
||||
F ext/fts5/fts5_config.c 501e7d3566bc92766b0e11c0109a7c5a6146bc41144195459af5422f6c2078aa
|
||||
F ext/fts5/fts5_expr.c 40174a64829d30cc86e8266306ad24980f6911edd5ca0b8c1ce7821ea1341b88
|
||||
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
|
||||
F ext/fts5/fts5_index.c fdfbc8a62827ec1d1b6f207a1e59c1c4986c3ce245592b5128ffe738867cfcd1
|
||||
F ext/fts5/fts5_index.c 3e47d9c56e4e9a6dee78bc32e006d6a28a3b5ec9ff84f3b8c381c78323201720
|
||||
F ext/fts5/fts5_main.c 6078ae86d3b813753a4f1201054550aff21a3f660e97b30f200d2b1472874151
|
||||
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
|
||||
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
|
||||
@@ -358,6 +358,7 @@ F ext/rbu/rbuA.test b34a90cb495682c25b5fc03a9d5e7a4fc99541c29256f25e2e2a4f6542b4
|
||||
F ext/rbu/rbuB.test 52b07158824c6927b7e25554ace92a695cdebfc296ae3d308ac386984aded9bc
|
||||
F ext/rbu/rbuC.test 80f1cc2fb74f44b1128fd0ed8eedab3a76fefeb72a947860e2869ef76fc8dc6b
|
||||
F ext/rbu/rbu_common.tcl 60d904133ff843fe72cc0514e9dd2486707181e6e0fbab20979da28c48d21de9
|
||||
F ext/rbu/rbubusy.test f38ef557358564491b8a2ee70e4cad31e40fcea57a16f27bc56ba40a59bbde50
|
||||
F ext/rbu/rbucollate.test cac528a9a46318cba42e61258bb42660bbbf4fdb9a8c863de5a54ad0c658d197
|
||||
F ext/rbu/rbucrash.test 000981a1fe8a6e4d9a684232f6a129e66a3ef595f5ed74655e2f9c68ffa613b4
|
||||
F ext/rbu/rbucrash2.test efa143cc94228eb0266d3f1abfbee60a5838a84cef7cc3fcb8c145b74d96fd41
|
||||
@@ -409,7 +410,7 @@ F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719
|
||||
F ext/rtree/rtree9.test fd3c9384ef8aabbc127b3878764070398f136eebc551cd20484b570f2cc1956a
|
||||
F ext/rtree/rtreeA.test a7fd235d8194115fa2e14d300337931eb2e960fe8a46cdfb66add2206412ea41
|
||||
F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
|
||||
F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f
|
||||
F ext/rtree/rtreeC.test 2978b194d09b13e106bdb0e1c5b408b9d42eb338c1082bf43c87ef43bd626147
|
||||
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
|
||||
F ext/rtree/rtreeE.test e65d3fc625da1800b412fc8785817327d43ccfec5f5973912d8c9e471928caa9
|
||||
F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd450ed331
|
||||
@@ -485,39 +486,39 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 9395ece9850ad57c6fbb453aeb5185be4bae3b159c4b37611425c565124ee849
|
||||
F src/analyze.c 3a119baeb03053c154029877454d41bb8fd79d4d1eb583392f2289b3554a75bc
|
||||
F src/alter.c d8872f9d1863d8e31c37475e318de746e1b5ca57c0e477e35042a9ebbb6e0298
|
||||
F src/analyze.c aabdf3769c7fd9954a8ec508eb7041ae174b66f88d12c47199fabbea9a646467
|
||||
F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8
|
||||
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
|
||||
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
|
||||
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 45161c2d5c9527b9c9bbfd7478daf3e0a619cf4bbe3278378aaea3d4b4e4f5b5
|
||||
F src/btree.c df695e953c2ce78ce4878ee5016751df9bc9a921dc0500a0f53ab3bb3196e505
|
||||
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
|
||||
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
|
||||
F src/build.c ff119be98394a65bc8be7afc39d4a791a66f03a778d396de3ec456f5dfaf39e8
|
||||
F src/build.c 23f874642825d7eaaeeb7a3281b2b1a75e1d4c4dd9ae4dceddcd908266634214
|
||||
F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 026dbdcdbd8c3cde98a88483ee88310ff43150ab164ad768f12cc700a11495ad
|
||||
F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f
|
||||
F src/dbpage.c a70be9a4879ac5392673a1050d526a72b8b2f9938df7049f65348566a2637db3
|
||||
F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68
|
||||
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
|
||||
F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce
|
||||
F src/expr.c 5e247a8dfabb92e9fd10b78a675dc5d25430433dfd9e316471b4447b548635ba
|
||||
F src/expr.c d955e8954e03e637c19033241806b04f6a937d0657f6261f2d9e4cdfe674b478
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 94927f9b46d72a9cb858c208febf04ceb0a3270c5fa5fd0b7f436cf16e09f72a
|
||||
F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e
|
||||
F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761
|
||||
F src/global.c e83ee571b79ee3adc32e380cf554cf1254bc43763d23786c71721fbcdfbbb965
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 221ae0496a53fcf74321d6dcdd7fa2d3c17ede1c17fa1d9020e2465da4a4505a
|
||||
F src/insert.c 173845e5a6bac96ae937409e4f876b631f26b31dabb9df8fd0eb3b130b2bb3a7
|
||||
F src/json.c 7749b98c62f691697c7ee536b570c744c0583cab4a89200fdd0fc2aa8cc8cbd6
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 2ecb1441f9b1c22e9e022ee0776e67d259facf34b56ba892b206f0a294ee6f8c
|
||||
F src/loadext.c 0705c2747212934183398f09891415d2f7f3113d0f543ccb205640210b20e617
|
||||
F src/main.c 135858d2ede0b83d779e71b07ede9c1d6b6eaab7b77bc2a85729584152769faf
|
||||
F src/malloc.c fec841aa0a0400a6f7d20706178a5d8e8219a6bf562b6fe712c17f6c26813266
|
||||
F src/malloc.c a9127efdcef92d6934c6339ea9813075b90edc0ce2e5c723556381a3828fb720
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
|
||||
@@ -541,23 +542,23 @@ F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356
|
||||
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
|
||||
F src/parse.y ff8f0f6f1086c6c480503f21386422f1dcd3d37dfe1011c9089abc7a14772c50
|
||||
F src/parse.y b86d56b446afb9c203d8354dc6c422818a62b4bbab52b76ab3da06d7b1d07e44
|
||||
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
|
||||
F src/pragma.c d1aead03e8418ff586c7cfca344c50a914b8eb06abd841e8e91a982d823671da
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c fd940149c691684e7c1073c3787a7170e44852b02d1275d2e30a5b58e89cfcaf
|
||||
F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32
|
||||
F src/printf.c 512574910a45341c8ad244bd3d4939968ebdfde215645b676fff01cc46e90757
|
||||
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
|
||||
F src/resolve.c 18d99e7146852d6064559561769fcca0743eb32b14a97da6dbed373a30ee0e76
|
||||
F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c d6c04eb93395024af80f61a8c278a33c2a0333aeb7d57bb6aa737a6f1c4af4b8
|
||||
F src/shell.c.in 1a8fbf932ecd582b1a5f66c1e8294f92c30d954616f5c7cc54c9623fcdbb028d
|
||||
F src/select.c 151adca2c9ea6f51215e4351bb8eb4f0012bf98c3d5a5c991d4a019c7cbb143e
|
||||
F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35
|
||||
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
|
||||
F src/sqliteInt.h 8262a5a484ffc0c0899537c9d99fff381f2d76061e256592a342bc098860a6ec
|
||||
F src/sqliteInt.h 7c8146fc57f2e009152eb93ad41eab28490f9c31691559f281a80f9077ec1f2a
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -617,18 +618,18 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98
|
||||
F src/treeview.c 80a3d70bbc112399aa3cc7e777acc5d07c452e44c652630fc158d4594d86afd1
|
||||
F src/trigger.c 372ada38f667c6823a3db15749eb668338e65c793394e55a37e56a489f2d1b55
|
||||
F src/treeview.c 4153f2f044d13a3216e64271dfd1e59a3fa40222a45e6da248708088634e6f06
|
||||
F src/trigger.c 4fe4c1ac811755aff49d669d2e52e414eb5dfa6e172e849ab7b6825e70a571c0
|
||||
F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92
|
||||
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
|
||||
F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3
|
||||
F src/vdbe.c eefc5a96938cc113a95e36a42b626bf594a7f0b8bb56ae299accbbf015b973cd
|
||||
F src/vdbe.h 89f5edb1422c8783a0b29db836e409876f2b3e847f78e2b21b1fbcc48a93f85f
|
||||
F src/vdbeInt.h 5f3d0abcf30c2b7a6672ad4386f18be0fca9c9b2cefe18f85a2e3df74f2613bf
|
||||
F src/vdbe.c a6a20956fa128c0b8d3c5592a9a3db890a46cf626f46ffee0cab2ac5bf8d04b2
|
||||
F src/vdbe.h 07641758ca8b4f4c6d81ea667ea167c541e6ece21f5574da11e3d21ec37e2662
|
||||
F src/vdbeInt.h ef43f7fdc5fde29fc3fd29c506c12830f366178fdb4edbbf0cbc3dfbd1278b5f
|
||||
F src/vdbeapi.c 354c893f1500cf524cc45c32879b9c68893a28b77e3442c24668d6afe4236217
|
||||
F src/vdbeaux.c baafd56664ccca4cf361a48b912f7ff37f95ee19aaf7cada420ce2ca73396833
|
||||
F src/vdbeaux.c f406d8d8b461f260aeaa69d265c5d175ff0a9f84d6153c87975cdfbf9d681922
|
||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||
F src/vdbemem.c 7189090b72baa025f945a1ac8c61ee420c645254476e8a191d555db76dfea5d4
|
||||
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
|
||||
@@ -639,16 +640,16 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c a2483d4fe7cde88638cd3140dd5d6ee3dc0c80d3b3fe20322a8d08dc451f97ae
|
||||
F src/whereInt.h 15d2975c3b4c193c78c26674400a840da8647fe1777ae3b026e2d15937b38a03
|
||||
F src/wherecode.c 6292d7bf2d751b1ce68139a70e5468dd6615a9a9dab5b5e61c0053836723bb7a
|
||||
F src/whereexpr.c 612f58f5f6e3e3bb94d10e2c56672ade8bbf94d4a928d3edb4e84e2ed3c00dca
|
||||
F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f
|
||||
F src/where.c eb86c068e8e24a1e0a650beb20573bd5648fe1584f11d5bdffaf17ec3de52b5d
|
||||
F src/whereInt.h 4db5a877a9d1f38b5c928c1c84297c07f30b9a3bc1f5f66214cf1a8ef90a0556
|
||||
F src/wherecode.c cd9da760d391a51013f9ab8bc8ca7ad67f3b96e4857efe0d1dd85f538b3494a6
|
||||
F src/whereexpr.c e036477ac8424de50ae5b36a71103405d3f86b33ba11125ec7a2a99d501b0622
|
||||
F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
|
||||
F test/affinity3.test b5c19d504dec222c0dc66642673d23dce915d35737b68e74d9f237b80493eb53
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test cc47afa5e11e0d6771a85a4993fa6ff721480ddb53ea538ec3fdbafb720bd505
|
||||
F test/aggnested.test 7269d07ac879fce161cb26c8fabe65cba5715742fac8a1fccac570dcdaf28f00
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||
F test/alter.test 313073774ab5c3f2ef1d3f0d03757c9d3a81284ae7e1b4a6ca34db088f886896
|
||||
@@ -669,7 +670,7 @@ F test/altermalloc3.test 55e606edf4b0acfbbd851ddfe93cfdddfae43d103644dcfd6008ae4
|
||||
F test/alterqf.test ff6c6f881485c29ed699b8ef4774864ca1b0c01a6c08f5cdd624a008e4b40fca
|
||||
F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912
|
||||
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
|
||||
F test/altertab3.test 5929f522fd6fd708396ad9f317d4af9ff1a93e460df85bb1d54d4499eeb94960
|
||||
F test/altertab3.test 8af5c6eb4a7dd2fc73235b865b53561bf07428d1d6a9cd59a067abf51141891e
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
|
||||
F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324
|
||||
@@ -704,10 +705,10 @@ F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39
|
||||
F test/autoindex1.test fe27af92eaf884bd9c38f94be3e8afa04ec494e5eefb189902026181a6175f5e
|
||||
F test/autoindex1.test cdc336e80cfd586c0e09426d58bec412db7527ca22dfabe88eab690e3acbb406
|
||||
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
|
||||
F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5
|
||||
F test/autoindex4.test 75cb1191a552b8201351f5a50d160fcb9387a0fbbfb820c77798bfee7da3f8cf
|
||||
F test/autoindex4.test 5df39313526b6f22a26bd119bbd97ca69f28386ab3c671fc10568d921c41eb08
|
||||
F test/autoindex5.test 2ee94f033b87ca0160e08d81034c507aff8e230df2627f0304fa309b2fee19a3
|
||||
F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df
|
||||
F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7
|
||||
@@ -752,7 +753,7 @@ F test/boundary3.tcl 23361e108a125dca9c4080c2feb884fe54d69243
|
||||
F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
|
||||
F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
|
||||
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/btree01.test 8e1ba2f857608ad8fbf9fcc11f33b15b083711162f9566b0a21fb573f2008593
|
||||
F test/btree01.test fef17d9e999ac4f04095948e3438fbe674f4e07bb2c63bb1cad41d87baee077f
|
||||
F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc
|
||||
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
|
||||
@@ -777,7 +778,7 @@ F test/close.test eccbad8ecd611d974cbf47278c3d4e5874faf02d811338d5d348af42d56d64
|
||||
F test/closure01.test 9905883f1b171a4638f98fc764879f154e214a306d3d8daf412a15e7f3a9b1e0
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test 71a6f27fdc93a92f14d8ab80c05e1937656a5a03197e1a10157314554d630ce8
|
||||
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
|
||||
F test/collate2.test 471c6f74573382b89b0f8b88a05256faa52f7964f9e4799e76708a3b1ece6ba4
|
||||
F test/collate3.test 89defc49983ddfbf0a0555aca8c0521a676f56a5
|
||||
F test/collate4.test c953715fb498b87163e3e73dd94356bff1f317bd
|
||||
F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6
|
||||
@@ -814,7 +815,7 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
|
||||
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
|
||||
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
|
||||
F test/corruptL.test 7d3440831ca24ba64305583c4d4506d417d3f89f5775c0b7cc8102db078f8ff5
|
||||
F test/corruptL.test ecce40d7b9b909a670a42a45d86e30d927735d7e7f09041af438b19529d35532
|
||||
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
|
||||
F test/corruptN.test 60b5a62944b4f0029ba07edaa5fd8e670539d6b0a8d99db26c068d435675cbfe
|
||||
F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576
|
||||
@@ -893,7 +894,7 @@ F test/enc.test 9a7be5479da985381d740b15f432800f65e2c87029ee57a318f42cb2eb43763a
|
||||
F test/enc2.test 848bf05f15b011719f478dddb7b5e9aea35e39e457493cba4c4eef75d849a5ec
|
||||
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test bfe979eb1f4b8ab7a3bd7db6d16c2e6c6be0e5a3aada2227716f3fd3a9d76b69
|
||||
F test/eqp.test 473aea9599b4b7af46614b55198cd78167e4eccd48e60812a40db47c5c41dea9
|
||||
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
|
||||
F test/eval.test 73969a2d43a511bf44080c44485a8c4d796b6a4f038d19e491867081155692c0
|
||||
F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650bf0747
|
||||
@@ -920,7 +921,7 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 6727452e163a427147e84e739da18713da553d79f9783559b04fdcd36d5c7421
|
||||
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
|
||||
F test/fkey7.test 64fb28da03da5dfe3cdef5967aa7e832c2507bf7fb8f0780cacbca1f2338d031
|
||||
F test/fkey8.test 48ef829d63f5f7b37aabd4df9363ac05f65539d1da8c4a44251631769d920579
|
||||
F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84bf
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
|
||||
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
|
||||
@@ -1008,7 +1009,7 @@ F test/fts3fault.test 798e45af84be7978ca33d5bdc94246eb44724db24174b5d8e9b1ac46c5
|
||||
F test/fts3fault2.test 6a17a11d8034b1c4eca9f3091649273d56c49ff049e2173df8060f94341e9da0
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11eb18aaf56
|
||||
F test/fts3join.test b285c919559af5b093c51abb2c07ce7ec0156dbc9573f444b78dabd9f3040db2
|
||||
F test/fts3join.test ee25def5e763ea8879c19e74f862d5191410ccc7259338887a3685e97f512662
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
|
||||
F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58
|
||||
@@ -1110,12 +1111,12 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
|
||||
F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
|
||||
F test/index6.test 5a7ab531c692ff3b3d139ef8ea6709fab40f9c6862ed418b4976752a5481da3a
|
||||
F test/index6.test 6e5b6943f6a97a34898e48c4d0d4990caf55c12c00465a43a9c33d2fd9a3a820
|
||||
F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6eb3
|
||||
F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3
|
||||
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
|
||||
F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0
|
||||
F test/indexexpr1.test 8f7241410e351679010f14cd7cd30357622d04a784508ff54ba5ce99f64a2228
|
||||
F test/indexexpr1.test 3360c2a29a8844e7c4b13293567025281257f9e13a31854cfff6959cede11502
|
||||
F test/indexexpr2.test 2c7abe3c48f8aaa5a448615ab4d13df3662185d28419c00999670834a3f0b484
|
||||
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
@@ -1140,12 +1141,18 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
|
||||
F test/join.test 85e9c88bf4700b45a48a6362cd47e0c0aefc572629827c31aa58a5978cabdfc5
|
||||
F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990
|
||||
F test/join.test e5f165dfd84fd46406ddae6614b0122c3bfa23a26ef62966442e1503c40d96aa
|
||||
F test/join2.test 466b07233820f5deee66a6c3bf6e4500c8bbf7b83649e67606f5f649c07928c0
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc
|
||||
F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a
|
||||
F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c
|
||||
F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0
|
||||
F test/join8.test 9a4b2f53d5358abb29e6356e357c0cd40f4d8f282589300dcb76728dce050b51
|
||||
F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05
|
||||
F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a
|
||||
F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded
|
||||
F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f207
|
||||
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
|
||||
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
||||
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
|
||||
@@ -1357,7 +1364,7 @@ F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce
|
||||
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
|
||||
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/select1.test 3d23f66bf9ba77570acfe2ca5f1540ece17037cc64ab1a00efec9758ac29c268
|
||||
F test/select1.test 692e84cfa29c405854c69e8a4027183d64c22952866a123fabbce741a379e889
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c
|
||||
F test/select4.test f0684d3da3bccacbe2a1ebadf6fb49d9df6f53acb4c6ebc228a88d0d6054cc7b
|
||||
@@ -1389,11 +1396,11 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test b224e0793c5f48aa3749e65d8c64b93a30731bd206f2e41e6c5f1bee1bdb16c6
|
||||
F test/shell1.test f7a2ef8260aa01f20be3185118213b1ae70518fdcd2105f3e25b021b5ca800ac
|
||||
F test/shell2.test 7a3a23a9f57b99453f1679b1fe8072cb30e382a622874c0c4d97695fadb0a787
|
||||
F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c
|
||||
F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
|
||||
F test/shell5.test 0a9920d81fae28c45cd5dbd1deb809487a23c5f4b422a49f9d31c85f926d4a9c
|
||||
F test/shell5.test 78a7a8516b1e7de560748881424f621321549023d3e5f7ed2e1c56497f64c06c
|
||||
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
|
||||
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
|
||||
F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
|
||||
@@ -1474,7 +1481,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl f577d040078dd4fb56ea1ccaa71f6bfd0ebf0bd0ac373304db4269b5474f9cb7
|
||||
F test/tester.tcl 18448c7801d44cc5f2690f54f803da49ed994b3968f73a393cff329e55926679
|
||||
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1711,7 +1718,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
|
||||
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
|
||||
F test/vtab6.test 7167e8e526bc2e719e7818e18b2fd7bb8c455fa018b74e611943a86782e10125
|
||||
F test/vtab6.test fa609a4af96da30beceefa3cb624abe9be38c4747ab373d98179b24027d6b798
|
||||
F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c
|
||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||
@@ -1769,7 +1776,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a
|
||||
F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656
|
||||
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
|
||||
F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x
|
||||
F test/where.test f114842c1851d257a26770f2ad55119b084001c0e1b8c214f886f45152d37cd8
|
||||
F test/where.test 8c6bbd0cae8feae142a7946e3484a802fa566bacf38452b1c3e48cb77321f9a4
|
||||
F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6
|
||||
F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753
|
||||
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
|
||||
@@ -1777,7 +1784,7 @@ F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 1c1bf436bf31b913d4764a2b62ac6e98b9681e5c7ae2b562605592a56b7e946b
|
||||
F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f
|
||||
F test/where9.test 1ffb75edc50a8faa6e7bd77f8221d783febb00b44b0bdb32fb48cec6e38eca95
|
||||
F test/where9.test 2db942671a002621eff4f713e347bb25243295f79d8990297cd160bebcfde3f7
|
||||
F test/whereA.test 9d1077b117f1b68d5f739d94f36956c36cf995eb87bb19b77b2e81af020edd20
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
|
||||
@@ -1814,18 +1821,18 @@ F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f
|
||||
F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed
|
||||
F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836
|
||||
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
|
||||
F test/windowB.test b67bda5645f3226790e1a360c4225241840b84adb5aa2e69bfb0b27eef3b84d9
|
||||
F test/windowB.test f2fb42b864b0cf431c956407583e9478a74c3642bdf8737fdcb6ff4a40298b07
|
||||
F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2
|
||||
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
|
||||
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
|
||||
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
|
||||
F test/windowpushd.test d8895d08870b7226f7693665bd292eb177e62ca06799184957b3ca7dc03067df
|
||||
F test/with1.test 7bc5abfe4c80c0cef8a90f5a66d60b9982e8ccd7350c8eb70611323a3b8e07ba
|
||||
F test/with1.test 9ad67fdeb2bbd808a5763c9060e214ea232f9b18d846ea3a59756dc38bdc3880
|
||||
F test/with2.test a1df41b987198383b9b70bf5e5fda390582e46398653858dbc6ceb24253b28df
|
||||
F test/with3.test ad32d13ad50661e6fa305f62a0717649c348792e7b658bf2644976227a9e0373
|
||||
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
|
||||
F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
|
||||
F test/with6.test 661d7e416bef6c0a2556b2c9f0c8178a5b15932bed65246abed99723a8d4e7c0
|
||||
F test/with6.test c18592592b5a1c5802fd4e933d506f7b34ebbe8fdd585229793e960ae58d433f
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test a5210b8770dc4736bca4e74bc96588f43025ad03ad6a80f885afd36d9890e217
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
@@ -1873,7 +1880,7 @@ F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a19
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl ac96a74f5e6d9dac672d5229f79c583d3357a50e7d098e473e6b2ce2f8ae1704 x
|
||||
F tool/mkkeywordhash.c eb57113139c6a37d80a3247026c5acc1efa0711678d6f76d54d2c46d39db5a8f
|
||||
F tool/mkkeywordhash.c 35bfc41adacc4aa6ef6fca7fd0c63e0ec0534b78daf4d0cfdebe398216bbffc3
|
||||
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
|
||||
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
|
||||
F tool/mkopcodeh.tcl 5dab48c49a25452257494e9601702ab63adaba6bd54a9b382615fa52661c8f8c
|
||||
@@ -1945,11 +1952,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 1b5475d212cf9de0bff69eee8c607b4fcd8e04bf4df72171429e7609c4153951
|
||||
R 6aa4900a9c6f26de4fb4a6a1056c6eed
|
||||
T *branch * merge-statement
|
||||
T *sym-merge-statement *
|
||||
T -sym-trunk *
|
||||
P c19c3c48698bf2543d775411c62d01e629791e2f3c5317970fdbb830eacafac6 6eda9b1a7784cf6d58c8876551f67ab98e78a08e726a0579d4def5ba881985bb
|
||||
R 2d89cb1e36090ec16d6f7a3a0d57b198
|
||||
U drh
|
||||
Z b59368f7e6309c70d89f64cbb029dfb3
|
||||
Z bc3c00e875924c9bd573570421780b97
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2deee326e850e829a73535930aecc5d512eb87790862c16c0993e92766d5c779
|
||||
72131ad1bda3d087e59cd4a51d87f10f65a55e658645397e1ede15f9fb1f5143
|
||||
+3
-3
@@ -880,7 +880,7 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
if( ALWAYS(p->pEList) ){
|
||||
ExprList *pList = p->pEList;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
|
||||
if( pList->a[i].zEName && pList->a[i].fg.eEName==ENAME_NAME ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
|
||||
}
|
||||
}
|
||||
@@ -929,7 +929,7 @@ void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
|
||||
sWalker.xExprCallback = renameUnmapExprCb;
|
||||
sqlite3WalkExprList(&sWalker, pEList);
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
|
||||
if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME) ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1087,7 @@ static void renameColumnElistNames(
|
||||
int i;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
const char *zName = pEList->a[i].zEName;
|
||||
if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
|
||||
if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME)
|
||||
&& ALWAYS(zName!=0)
|
||||
&& 0==sqlite3_stricmp(zName, zOld)
|
||||
){
|
||||
|
||||
+7
-1
@@ -847,9 +847,14 @@ static void statGet(
|
||||
** * "WHERE a=? AND b=?" matches 2 rows.
|
||||
**
|
||||
** If D is the count of distinct values and K is the total number of
|
||||
** rows, then each estimate is computed as:
|
||||
** rows, then each estimate is usually computed as:
|
||||
**
|
||||
** I = (K+D-1)/D
|
||||
**
|
||||
** In other words, I is K/D rounded up to the next whole integer.
|
||||
** However, if I is between 1.0 and 1.1 (in other words if I is
|
||||
** close to 1.0 but just a little larger) then do not round up but
|
||||
** instead keep the I value at 1.0.
|
||||
*/
|
||||
sqlite3_str sStat; /* Text of the constructed "stat" line */
|
||||
int i; /* Loop counter */
|
||||
@@ -860,6 +865,7 @@ static void statGet(
|
||||
for(i=0; i<p->nKeyCol; i++){
|
||||
u64 nDistinct = p->current.anDLt[i] + 1;
|
||||
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
|
||||
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
|
||||
sqlite3_str_appendf(&sStat, " %llu", iVal);
|
||||
assert( p->current.anEq[i] );
|
||||
}
|
||||
|
||||
+4
-2
@@ -1657,6 +1657,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
** fragmented bytes within the page. */
|
||||
memcpy(&aData[iAddr], &aData[pc], 2);
|
||||
aData[hdr+7] += (u8)x;
|
||||
testcase( pc+x>maxPC );
|
||||
return &aData[pc];
|
||||
}else if( x+pc > maxPC ){
|
||||
/* This slot extends off the end of the usable part of the page */
|
||||
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
||||
@@ -5967,7 +5969,7 @@ bypass_moveto_root:
|
||||
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
||||
assert( pPage->isInit );
|
||||
if( pPage->leaf ){
|
||||
assert( pCur->ix<pCur->pPage->nCell );
|
||||
assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB );
|
||||
pCur->ix = (u16)idx;
|
||||
*pRes = c;
|
||||
rc = SQLITE_OK;
|
||||
@@ -8491,7 +8493,7 @@ static int balance_nonroot(
|
||||
iOvflSpace += sz;
|
||||
assert( sz<=pBt->maxLocal+23 );
|
||||
assert( iOvflSpace <= (int)pBt->pageSize );
|
||||
for(k=0; b.ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||
for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){}
|
||||
pSrcEnd = b.apEnd[k];
|
||||
if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
|
||||
+55
-33
@@ -172,9 +172,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
int i;
|
||||
int reg;
|
||||
|
||||
if( NEVER(pReturning->nRetCol==0) ){
|
||||
assert( CORRUPT_DB );
|
||||
}else{
|
||||
if( pReturning->nRetCol ){
|
||||
sqlite3VdbeAddOp0(v, OP_FkCheck);
|
||||
addrRewind =
|
||||
sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
|
||||
@@ -270,9 +268,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
|
||||
if( pParse->bReturning ){
|
||||
Returning *pRet = pParse->u1.pReturning;
|
||||
if( NEVER(pRet->nRetCol==0) ){
|
||||
assert( CORRUPT_DB );
|
||||
}else{
|
||||
if( pRet->nRetCol ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
|
||||
}
|
||||
}
|
||||
@@ -1894,7 +1890,7 @@ void sqlite3AddPrimaryKey(
|
||||
pTab->keyConf = (u8)onError;
|
||||
assert( autoInc==0 || autoInc==1 );
|
||||
pTab->tabFlags |= autoInc*TF_Autoincrement;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].fg.sortFlags;
|
||||
(void)sqlite3HasExplicitNulls(pParse, pList);
|
||||
}else if( autoInc ){
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
@@ -2388,7 +2384,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey);
|
||||
}
|
||||
pList->a[0].sortFlags = pParse->iPkSortOrder;
|
||||
pList->a[0].fg.sortFlags = pParse->iPkSortOrder;
|
||||
assert( pParse->pNewTable==pTab );
|
||||
pTab->iPKey = -1;
|
||||
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
|
||||
@@ -3059,7 +3055,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
Table *pSelTab; /* A fake table from which we get the result set */
|
||||
Select *pSel; /* Copy of the SELECT that implements the view */
|
||||
int nErr = 0; /* Number of errors encountered */
|
||||
int n; /* Temporarily holds the number of cursors assigned */
|
||||
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int rc;
|
||||
@@ -3117,8 +3112,9 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0);
|
||||
if( pSel ){
|
||||
u8 eParseMode = pParse->eParseMode;
|
||||
int nTab = pParse->nTab;
|
||||
int nSelect = pParse->nSelect;
|
||||
pParse->eParseMode = PARSE_MODE_NORMAL;
|
||||
n = pParse->nTab;
|
||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||
pTable->nCol = -1;
|
||||
DisableLookaside;
|
||||
@@ -3130,7 +3126,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
#else
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
|
||||
#endif
|
||||
pParse->nTab = n;
|
||||
pParse->nTab = nTab;
|
||||
pParse->nSelect = nSelect;
|
||||
if( pSelTab==0 ){
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
@@ -3875,8 +3872,8 @@ int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
|
||||
if( pList ){
|
||||
int i;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].bNulls ){
|
||||
u8 sf = pList->a[i].sortFlags;
|
||||
if( pList->a[i].fg.bNulls ){
|
||||
u8 sf = pList->a[i].fg.sortFlags;
|
||||
sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
|
||||
(sf==0 || sf==3) ? "FIRST" : "LAST"
|
||||
);
|
||||
@@ -4229,7 +4226,7 @@ void sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->azColl[i] = zColl;
|
||||
requestedSortOrder = pListItem->sortFlags & sortOrderMask;
|
||||
requestedSortOrder = pListItem->fg.sortFlags & sortOrderMask;
|
||||
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
|
||||
}
|
||||
|
||||
@@ -4672,18 +4669,17 @@ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
|
||||
if( pList==0 ){
|
||||
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
||||
if( pList==0 ) return 0;
|
||||
}else{
|
||||
IdList *pNew;
|
||||
pNew = sqlite3DbRealloc(db, pList,
|
||||
sizeof(IdList) + pList->nId*sizeof(pList->a));
|
||||
if( pNew==0 ){
|
||||
sqlite3IdListDelete(db, pList);
|
||||
return 0;
|
||||
}
|
||||
pList = pNew;
|
||||
}
|
||||
pList->a = sqlite3ArrayAllocate(
|
||||
db,
|
||||
pList->a,
|
||||
sizeof(pList->a[0]),
|
||||
&pList->nId,
|
||||
&i
|
||||
);
|
||||
if( i<0 ){
|
||||
sqlite3IdListDelete(db, pList);
|
||||
return 0;
|
||||
}
|
||||
i = pList->nId++;
|
||||
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
|
||||
if( IN_RENAME_OBJECT && pList->a[i].zName ){
|
||||
sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
|
||||
@@ -4697,10 +4693,10 @@ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
|
||||
void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
||||
int i;
|
||||
if( pList==0 ) return;
|
||||
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
|
||||
for(i=0; i<pList->nId; i++){
|
||||
sqlite3DbFree(db, pList->a[i].zName);
|
||||
}
|
||||
sqlite3DbFree(db, pList->a);
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
|
||||
@@ -4971,7 +4967,12 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
if( pAlias->n ){
|
||||
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
||||
}
|
||||
pItem->pSelect = pSubquery;
|
||||
if( pSubquery ){
|
||||
pItem->pSelect = pSubquery;
|
||||
if( pSubquery->selFlags & SF_NestedFrom ){
|
||||
pItem->fg.isNestedFrom = 1;
|
||||
}
|
||||
}
|
||||
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
|
||||
assert( pItem->fg.isUsing==0 );
|
||||
if( pOnUsing==0 ){
|
||||
@@ -5031,6 +5032,7 @@ SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
|
||||
p1 = pNew;
|
||||
memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem));
|
||||
sqlite3DbFree(pParse->db, p2);
|
||||
p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype);
|
||||
}
|
||||
}
|
||||
return p1;
|
||||
@@ -5067,14 +5069,34 @@ void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
|
||||
** The operator is "natural cross join". The A and B operands are stored
|
||||
** in p->a[0] and p->a[1], respectively. The parser initially stores the
|
||||
** operator with A. This routine shifts that operator over to B.
|
||||
**
|
||||
** Additional changes:
|
||||
**
|
||||
** * All tables to the left of the right-most RIGHT JOIN are tagged with
|
||||
** JT_LTORJ (mnemonic: Left Table Of Right Join) so that the
|
||||
** code generator can easily tell that the table is part of
|
||||
** the left operand of at least one RIGHT JOIN.
|
||||
*/
|
||||
void sqlite3SrcListShiftJoinType(SrcList *p){
|
||||
if( p ){
|
||||
int i;
|
||||
for(i=p->nSrc-1; i>0; i--){
|
||||
p->a[i].fg.jointype = p->a[i-1].fg.jointype;
|
||||
}
|
||||
void sqlite3SrcListShiftJoinType(Parse *pParse, SrcList *p){
|
||||
(void)pParse;
|
||||
if( p && p->nSrc>1 ){
|
||||
int i = p->nSrc-1;
|
||||
u8 allFlags = 0;
|
||||
do{
|
||||
allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype;
|
||||
}while( (--i)>0 );
|
||||
p->a[0].fg.jointype = 0;
|
||||
|
||||
/* All terms to the left of a RIGHT JOIN should be tagged with the
|
||||
** JT_LTORJ flags */
|
||||
if( allFlags & JT_RIGHT ){
|
||||
for(i=p->nSrc-1; ALWAYS(i>0) && (p->a[i].fg.jointype&JT_RIGHT)==0; i--){}
|
||||
i--;
|
||||
assert( i>=0 );
|
||||
do{
|
||||
p->a[i].fg.jointype |= JT_LTORJ;
|
||||
}while( (--i)>=0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
){
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
sqlite3VtabWriteAll(pIdxInfo);
|
||||
sqlite3VtabUsesAllSchemas(pIdxInfo);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+88
-43
@@ -1527,6 +1527,7 @@ With *sqlite3WithDup(sqlite3 *db, With *p){
|
||||
pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0);
|
||||
pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0);
|
||||
pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName);
|
||||
pRet->a[i].eM10d = p->a[i].eM10d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1627,11 +1628,8 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
|
||||
}
|
||||
}
|
||||
pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
|
||||
pItem->sortFlags = pOldItem->sortFlags;
|
||||
pItem->eEName = pOldItem->eEName;
|
||||
pItem->done = 0;
|
||||
pItem->bNulls = pOldItem->bNulls;
|
||||
pItem->bSorterRef = pOldItem->bSorterRef;
|
||||
pItem->fg = pOldItem->fg;
|
||||
pItem->fg.done = 0;
|
||||
pItem->u = pOldItem->u;
|
||||
}
|
||||
return pNew;
|
||||
@@ -1698,22 +1696,16 @@ IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
|
||||
int i;
|
||||
assert( db!=0 );
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
|
||||
assert( p->eU4!=EU4_EXPR );
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->nId = p->nId;
|
||||
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
|
||||
if( pNew->a==0 ){
|
||||
sqlite3DbFreeNN(db, pNew);
|
||||
return 0;
|
||||
}
|
||||
/* Note that because the size of the allocation for p->a[] is not
|
||||
** necessarily a power of two, sqlite3IdListAppend() may not be called
|
||||
** on the duplicate created by this function. */
|
||||
pNew->eU4 = p->eU4;
|
||||
for(i=0; i<p->nId; i++){
|
||||
struct IdList_item *pNewItem = &pNew->a[i];
|
||||
struct IdList_item *pOldItem = &p->a[i];
|
||||
const struct IdList_item *pOldItem = &p->a[i];
|
||||
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
||||
pNewItem->idx = pOldItem->idx;
|
||||
pNewItem->u4 = pOldItem->u4;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
@@ -1937,16 +1929,16 @@ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
|
||||
);
|
||||
|
||||
pItem = &p->a[p->nExpr-1];
|
||||
assert( pItem->bNulls==0 );
|
||||
assert( pItem->fg.bNulls==0 );
|
||||
if( iSortOrder==SQLITE_SO_UNDEFINED ){
|
||||
iSortOrder = SQLITE_SO_ASC;
|
||||
}
|
||||
pItem->sortFlags = (u8)iSortOrder;
|
||||
pItem->fg.sortFlags = (u8)iSortOrder;
|
||||
|
||||
if( eNulls!=SQLITE_SO_UNDEFINED ){
|
||||
pItem->bNulls = 1;
|
||||
pItem->fg.bNulls = 1;
|
||||
if( iSortOrder!=eNulls ){
|
||||
pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
|
||||
pItem->fg.sortFlags |= KEYINFO_ORDER_BIGNULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1972,7 +1964,7 @@ void sqlite3ExprListSetName(
|
||||
assert( pList->nExpr>0 );
|
||||
pItem = &pList->a[pList->nExpr-1];
|
||||
assert( pItem->zEName==0 );
|
||||
assert( pItem->eEName==ENAME_NAME );
|
||||
assert( pItem->fg.eEName==ENAME_NAME );
|
||||
pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
|
||||
if( dequote ){
|
||||
/* If dequote==0, then pName->z does not point to part of a DDL
|
||||
@@ -2007,7 +1999,7 @@ void sqlite3ExprListSetSpan(
|
||||
assert( pList->nExpr>0 );
|
||||
if( pItem->zEName==0 ){
|
||||
pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd);
|
||||
pItem->eEName = ENAME_SPAN;
|
||||
pItem->fg.eEName = ENAME_SPAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2179,7 +2171,7 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
|
||||
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
|
||||
/* If pWalker->eCode is 2 then any term of the expression that comes from
|
||||
** the ON or USING clauses of a left join disqualifies the expression
|
||||
** the ON or USING clauses of an outer join disqualifies the expression
|
||||
** from being considered constant. */
|
||||
if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
pWalker->eCode = 0;
|
||||
@@ -2300,6 +2292,42 @@ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
||||
return exprIsConst(p, 3, iCur);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check pExpr to see if it is an invariant constraint on data source pSrc.
|
||||
** This is an optimization. False negatives will perhaps cause slower
|
||||
** queries, but false positives will yield incorrect answers. So when in
|
||||
** doubt, return 0.
|
||||
**
|
||||
** To be an invariant constraint, the following must be true:
|
||||
**
|
||||
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
|
||||
**
|
||||
** (2) pExpr cannot use subqueries or non-deterministic functions.
|
||||
**
|
||||
** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
|
||||
** (Is there some way to relax this constraint?)
|
||||
**
|
||||
** (4) If pSrc is the right operand of a LEFT JOIN, then...
|
||||
** (4a) pExpr must come from an ON clause..
|
||||
(4b) and specifically the ON clause associated with the LEFT JOIN.
|
||||
**
|
||||
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
|
||||
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
|
||||
** clause, not an ON clause.
|
||||
*/
|
||||
int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
|
||||
if( pSrc->fg.jointype & JT_LTORJ ){
|
||||
return 0; /* rule (3) */
|
||||
}
|
||||
if( pSrc->fg.jointype & JT_LEFT ){
|
||||
if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (4a) */
|
||||
if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */
|
||||
}else{
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (5) */
|
||||
}
|
||||
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
|
||||
@@ -2627,7 +2655,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
** all members of the RHS set, skipping duplicates.
|
||||
**
|
||||
** A cursor is opened on the b-tree object that is the RHS of the IN operator
|
||||
** and pX->iTable is set to the index of that cursor.
|
||||
** and the *piTab parameter is set to the index of that cursor.
|
||||
**
|
||||
** The returned value of this function indicates the b-tree type, as follows:
|
||||
**
|
||||
@@ -2647,7 +2675,10 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
** If the RHS of the IN operator is a list or a more complex subquery, then
|
||||
** an ephemeral table might need to be generated from the RHS and then
|
||||
** pX->iTable made to point to the ephemeral table instead of an
|
||||
** existing table.
|
||||
** existing table. In this case, the creation and initialization of the
|
||||
** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
|
||||
** will be set on pX and the pX->y.sub fields will be set to show where
|
||||
** the subroutine is coded.
|
||||
**
|
||||
** The inFlags parameter must contain, at a minimum, one of the bits
|
||||
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains
|
||||
@@ -2708,12 +2739,17 @@ int sqlite3FindInIndex(
|
||||
){
|
||||
Select *p; /* SELECT to the right of IN operator */
|
||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||
int iTab = pParse->nTab++; /* Cursor of the RHS table */
|
||||
int iTab; /* Cursor of the RHS table */
|
||||
int mustBeUnique; /* True if RHS must be unique */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
|
||||
assert( pX->op==TK_IN );
|
||||
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
|
||||
if( pX->iTable && (inFlags & IN_INDEX_REUSE_CUR)!=0 ){
|
||||
iTab = pX->iTable;
|
||||
}else{
|
||||
iTab = pParse->nTab++;
|
||||
}
|
||||
|
||||
/* If the RHS of this IN(...) operator is a SELECT, and if it matters
|
||||
** whether or not the SELECT result contains NULL values, check whether
|
||||
@@ -2879,6 +2915,8 @@ int sqlite3FindInIndex(
|
||||
&& ExprUseXList(pX)
|
||||
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
|
||||
){
|
||||
pParse->nTab--; /* Back out the allocation of the unused cursor */
|
||||
iTab = -1; /* Cursor is not allocated */
|
||||
eType = IN_INDEX_NOOP;
|
||||
}
|
||||
|
||||
@@ -3045,7 +3083,9 @@ void sqlite3CodeRhsOfIN(
|
||||
assert( ExprUseYSub(pExpr) );
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
|
||||
pExpr->y.sub.iAddr);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
|
||||
if( iTab!=pExpr->iTable ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addrOnce);
|
||||
return;
|
||||
}
|
||||
@@ -3181,9 +3221,9 @@ void sqlite3CodeRhsOfIN(
|
||||
assert( ExprUseYSub(pExpr) );
|
||||
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|
||||
|| pParse->nErr );
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn, 0,
|
||||
pExpr->y.sub.iAddr-1);
|
||||
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
|
||||
pExpr->y.sub.iAddr, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
}
|
||||
@@ -3312,9 +3352,9 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
assert( ExprUseYSub(pExpr) );
|
||||
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|
||||
|| pParse->nErr );
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn, 0,
|
||||
pExpr->y.sub.iAddr-1);
|
||||
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
|
||||
pExpr->y.sub.iAddr, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
return rReg;
|
||||
}
|
||||
@@ -3748,6 +3788,7 @@ void sqlite3ExprCodeGetColumnOfTable(
|
||||
}
|
||||
if( iCol<0 || iCol==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
|
||||
VdbeComment((v, "%s.rowid", pTab->zName));
|
||||
}else{
|
||||
int op;
|
||||
int x;
|
||||
@@ -4500,16 +4541,18 @@ expr_code_doover:
|
||||
}
|
||||
case TK_SELECT_COLUMN: {
|
||||
int n;
|
||||
if( pExpr->pLeft->iTable==0 ){
|
||||
pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft);
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
if( pLeft->iTable==0 || pParse->withinRJSubrtn > pLeft->op2 ){
|
||||
pLeft->iTable = sqlite3CodeSubselect(pParse, pLeft);
|
||||
pLeft->op2 = pParse->withinRJSubrtn;
|
||||
}
|
||||
assert( pExpr->pLeft->op==TK_SELECT || pExpr->pLeft->op==TK_ERROR );
|
||||
n = sqlite3ExprVectorSize(pExpr->pLeft);
|
||||
assert( pLeft->op==TK_SELECT || pLeft->op==TK_ERROR );
|
||||
n = sqlite3ExprVectorSize(pLeft);
|
||||
if( pExpr->iTable!=n ){
|
||||
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
|
||||
pExpr->iTable, n);
|
||||
}
|
||||
return pExpr->pLeft->iTable + pExpr->iColumn;
|
||||
return pLeft->iTable + pExpr->iColumn;
|
||||
}
|
||||
case TK_IN: {
|
||||
int destIfFalse = sqlite3VdbeMakeLabel(pParse);
|
||||
@@ -4782,7 +4825,9 @@ int sqlite3ExprCodeRunJustOnce(
|
||||
struct ExprList_item *pItem;
|
||||
int i;
|
||||
for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
|
||||
if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
|
||||
if( pItem->fg.reusable
|
||||
&& sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0
|
||||
){
|
||||
return pItem->u.iConstExprReg;
|
||||
}
|
||||
}
|
||||
@@ -4805,7 +4850,7 @@ int sqlite3ExprCodeRunJustOnce(
|
||||
p = sqlite3ExprListAppend(pParse, p, pExpr);
|
||||
if( p ){
|
||||
struct ExprList_item *pItem = &p->a[p->nExpr-1];
|
||||
pItem->reusable = regDest<0;
|
||||
pItem->fg.reusable = regDest<0;
|
||||
if( regDest<0 ) regDest = ++pParse->nMem;
|
||||
pItem->u.iConstExprReg = regDest;
|
||||
}
|
||||
@@ -4939,7 +4984,7 @@ int sqlite3ExprCodeExprList(
|
||||
for(pItem=pList->a, i=0; i<n; i++, pItem++){
|
||||
Expr *pExpr = pItem->pExpr;
|
||||
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
||||
if( pItem->bSorterRef ){
|
||||
if( pItem->fg.bSorterRef ){
|
||||
i--;
|
||||
n--;
|
||||
}else
|
||||
@@ -5564,7 +5609,7 @@ int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){
|
||||
int res;
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
|
||||
if( pA->a[i].fg.sortFlags!=pB->a[i].fg.sortFlags ) return 1;
|
||||
if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
|
||||
}
|
||||
return 0;
|
||||
@@ -5817,7 +5862,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
** in an incorrect answer.
|
||||
**
|
||||
** Terms of p that are marked with EP_FromJoin (and hence that come from
|
||||
** the ON or USING clauses of LEFT JOINS) are excluded from the analysis.
|
||||
** the ON or USING clauses of OUTER JOINS) are excluded from the analysis.
|
||||
**
|
||||
** This routine is used to check if a LEFT JOIN can be converted into
|
||||
** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE
|
||||
|
||||
+9
-8
@@ -534,14 +534,10 @@ static Expr *exprTableColumn(
|
||||
** Operation | FK type | Action taken
|
||||
** --------------------------------------------------------------------------
|
||||
** DELETE immediate Increment the "immediate constraint counter".
|
||||
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
|
||||
** throw a "FOREIGN KEY constraint failed" exception.
|
||||
**
|
||||
** INSERT immediate Decrement the "immediate constraint counter".
|
||||
**
|
||||
** DELETE deferred Increment the "deferred constraint counter".
|
||||
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
|
||||
** throw a "FOREIGN KEY constraint failed" exception.
|
||||
**
|
||||
** INSERT deferred Decrement the "deferred constraint counter".
|
||||
**
|
||||
@@ -1189,9 +1185,9 @@ int sqlite3FkRequired(
|
||||
**
|
||||
** It returns a pointer to a Trigger structure containing a trigger
|
||||
** equivalent to the ON UPDATE or ON DELETE action specified by pFKey.
|
||||
** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is
|
||||
** returned (these actions require no special handling by the triggers
|
||||
** sub-system, code for them is created by fkScanChildren()).
|
||||
** If the action is "NO ACTION" then a NULL pointer is returned (these actions
|
||||
** require no special handling by the triggers sub-system, code for them is
|
||||
** created by fkScanChildren()).
|
||||
**
|
||||
** For example, if pFKey is the foreign key and pTab is table "p" in
|
||||
** the following schema:
|
||||
@@ -1320,18 +1316,23 @@ static Trigger *fkActionTrigger(
|
||||
nFrom = sqlite3Strlen30(zFrom);
|
||||
|
||||
if( action==OE_Restrict ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
Token tFrom;
|
||||
Token tDb;
|
||||
Expr *pRaise;
|
||||
|
||||
tFrom.z = zFrom;
|
||||
tFrom.n = nFrom;
|
||||
tDb.z = db->aDb[iDb].zDbSName;
|
||||
tDb.n = sqlite3Strlen30(tDb.z);
|
||||
|
||||
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
|
||||
if( pRaise ){
|
||||
pRaise->affExpr = OE_Abort;
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse,
|
||||
sqlite3ExprListAppend(pParse, 0, pRaise),
|
||||
sqlite3SrcListAppend(pParse, 0, &tFrom, 0),
|
||||
sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
|
||||
pWhere,
|
||||
0, 0, 0, 0, 0
|
||||
);
|
||||
|
||||
+6
-3
@@ -851,13 +851,15 @@ void sqlite3Insert(
|
||||
*/
|
||||
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
|
||||
if( pColumn ){
|
||||
assert( pColumn->eU4!=EU4_EXPR );
|
||||
pColumn->eU4 = EU4_IDX;
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
pColumn->a[i].idx = -1;
|
||||
pColumn->a[i].u4.idx = -1;
|
||||
}
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
|
||||
pColumn->a[i].idx = j;
|
||||
pColumn->a[i].u4.idx = j;
|
||||
if( i!=j ) bIdListInOrder = 0;
|
||||
if( j==pTab->iPKey ){
|
||||
ipkColumn = i; assert( !withoutRowid );
|
||||
@@ -1159,7 +1161,8 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
if( pColumn ){
|
||||
for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){}
|
||||
assert( pColumn->eU4==EU4_IDX );
|
||||
for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
|
||||
if( j>=pColumn->nId ){
|
||||
/* A column not named in the insert column list gets its
|
||||
** default value */
|
||||
|
||||
@@ -487,11 +487,19 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_autovacuum_pages,
|
||||
/* Version 3.38.0 and later */
|
||||
sqlite3_error_offset,
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3_vtab_rhs_value,
|
||||
sqlite3_vtab_distinct,
|
||||
sqlite3_vtab_in,
|
||||
sqlite3_vtab_in_first,
|
||||
sqlite3_vtab_in_next,
|
||||
#else
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
#endif
|
||||
/* Version 3.39.0 and later */
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
sqlite3_deserialize,
|
||||
|
||||
+2
-1
@@ -750,8 +750,9 @@ char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
|
||||
** Free any prior content in *pz and replace it with a copy of zNew.
|
||||
*/
|
||||
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
|
||||
char *z = sqlite3DbStrDup(db, zNew);
|
||||
sqlite3DbFree(db, *pz);
|
||||
*pz = sqlite3DbStrDup(db, zNew);
|
||||
*pz = z;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+5
-30
@@ -263,9 +263,6 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
|
||||
%endif
|
||||
MATERIALIZED
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
%ifndef SQLITE_OMIT_MERGE
|
||||
MERGE MATCHED SOURCE TARGET
|
||||
%endif
|
||||
.
|
||||
%wildcard ANY.
|
||||
|
||||
@@ -688,7 +685,7 @@ as(X) ::= . {X.n = 0; X.z = 0;}
|
||||
from(A) ::= . {A = 0;}
|
||||
from(A) ::= FROM seltablist(X). {
|
||||
A = X;
|
||||
sqlite3SrcListShiftJoinType(A);
|
||||
sqlite3SrcListShiftJoinType(pParse,A);
|
||||
}
|
||||
|
||||
// "seltablist" is a "Select Table List" - the content of the FROM clause
|
||||
@@ -724,6 +721,9 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
|
||||
pNew->zName = pOld->zName;
|
||||
pNew->zDatabase = pOld->zDatabase;
|
||||
pNew->pSelect = pOld->pSelect;
|
||||
if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
|
||||
pNew->fg.isNestedFrom = 1;
|
||||
}
|
||||
if( pOld->fg.isTabFunc ){
|
||||
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
|
||||
pOld->u1.pFuncArg = 0;
|
||||
@@ -736,7 +736,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
|
||||
sqlite3SrcListDelete(pParse->db, F);
|
||||
}else{
|
||||
Select *pSubquery;
|
||||
sqlite3SrcListShiftJoinType(F);
|
||||
sqlite3SrcListShiftJoinType(pParse,F);
|
||||
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N);
|
||||
}
|
||||
@@ -1014,30 +1014,6 @@ idlist(A) ::= idlist(A) COMMA nm(Y).
|
||||
idlist(A) ::= nm(Y).
|
||||
{A = sqlite3IdListAppend(pParse,0,&Y); /*A-overwrites-Y*/}
|
||||
|
||||
|
||||
////////////////////////// The MERGE command //////////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_MERGE
|
||||
cmd ::= mergecmd.
|
||||
mergecmd ::= with MERGE INTO nm dbnm as USING nm dbnm as ON expr whenclause.
|
||||
mergecmd ::= with MERGE INTO nm dbnm as USING LP select RP as ON expr whenclause.
|
||||
whenclause ::= when.
|
||||
whenclause ::= whenclause when.
|
||||
when ::= WHEN MATCHED whencond THEN whenaction1.
|
||||
when ::= WHEN NOT MATCHED whencond THEN whenaction2.
|
||||
when ::= WHEN NOT MATCHED BY TARGET whencond THEN whenaction2.
|
||||
when ::= WHEN NOT MATCHED BY SOURCE whencond THEN whenaction1.
|
||||
whencond ::= .
|
||||
whencond ::= AND expr.
|
||||
whenaction1 ::= UPDATE SET setlist.
|
||||
whenaction1 ::= DELETE.
|
||||
whenaction1 ::= DO NOTHING.
|
||||
whenaction2 ::= INSERT DEFAULT VALUES.
|
||||
whenaction2 ::= INSERT idlist_opt values.
|
||||
whenaction2 ::= DO NOTHING.
|
||||
%endif /* SQLITE_OMIT_MERGE */
|
||||
|
||||
|
||||
/////////////////////////// Expression Processing /////////////////////////////
|
||||
//
|
||||
|
||||
@@ -1879,7 +1855,6 @@ over_clause(A) ::= OVER nm(Z). {
|
||||
filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
|
||||
%endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
|
||||
/*
|
||||
** The code generator needs some extra TK_ token values for tokens that
|
||||
** are synthesized and do not actually appear in the grammar:
|
||||
|
||||
+8
-2
@@ -884,8 +884,14 @@ void sqlite3_str_vappendf(
|
||||
sqlite3_str_appendall(pAccum, pItem->zName);
|
||||
}else if( pItem->zAlias ){
|
||||
sqlite3_str_appendall(pAccum, pItem->zAlias);
|
||||
}else if( ALWAYS(pItem->pSelect) ){
|
||||
sqlite3_str_appendf(pAccum, "SUBQUERY %u", pItem->pSelect->selId);
|
||||
}else{
|
||||
Select *pSel = pItem->pSelect;
|
||||
assert( pSel!=0 );
|
||||
if( pSel->selFlags & SF_NestedFrom ){
|
||||
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
|
||||
}else{
|
||||
sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
|
||||
}
|
||||
}
|
||||
length = width = 0;
|
||||
break;
|
||||
|
||||
+146
-58
@@ -115,22 +115,6 @@ static void resolveAlias(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return TRUE if the name zCol occurs anywhere in the USING clause.
|
||||
**
|
||||
** Return FALSE if the USING clause is NULL or if it does not contain
|
||||
** zCol.
|
||||
*/
|
||||
static int nameInUsingClause(IdList *pUsing, const char *zCol){
|
||||
int k;
|
||||
assert( pUsing!=0 );
|
||||
for(k=0; k<pUsing->nId; k++){
|
||||
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Subqueries stores the original database, table and column names for their
|
||||
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
|
||||
@@ -146,7 +130,7 @@ int sqlite3MatchEName(
|
||||
){
|
||||
int n;
|
||||
const char *zSpan;
|
||||
if( pItem->eEName!=ENAME_TAB ) return 0;
|
||||
if( pItem->fg.eEName!=ENAME_TAB ) return 0;
|
||||
zSpan = pItem->zEName;
|
||||
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
|
||||
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
|
||||
@@ -207,6 +191,29 @@ Bitmask sqlite3ExprColUsed(Expr *pExpr){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new expression term for the column specified by pMatch and
|
||||
** iColumn. Append this new expression term to the FULL JOIN Match set
|
||||
** in *ppList. Create a new *ppList if this is the first term in the
|
||||
** set.
|
||||
*/
|
||||
static void extendFJMatch(
|
||||
Parse *pParse, /* Parsing context */
|
||||
ExprList **ppList, /* ExprList to extend */
|
||||
SrcItem *pMatch, /* Source table containing the column */
|
||||
i16 iColumn /* The column number */
|
||||
){
|
||||
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
|
||||
if( pNew ){
|
||||
pNew->iTable = pMatch->iCursor;
|
||||
pNew->iColumn = iColumn;
|
||||
pNew->y.pTab = pMatch->pTab;
|
||||
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
|
||||
ExprSetProperty(pNew, EP_CanBeNull);
|
||||
*ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
|
||||
** that name in the set of source tables in pSrcList and make the pExpr
|
||||
@@ -252,11 +259,13 @@ static int lookupName(
|
||||
NameContext *pTopNC = pNC; /* First namecontext in the list */
|
||||
Schema *pSchema = 0; /* Schema of the expression */
|
||||
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
|
||||
Table *pTab = 0; /* Table hold the row */
|
||||
Table *pTab = 0; /* Table holding the row */
|
||||
Column *pCol; /* A column of pTab */
|
||||
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
|
||||
|
||||
assert( pNC ); /* the name context cannot be NULL. */
|
||||
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
|
||||
assert( zDb==0 || zTab!=0 );
|
||||
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
||||
|
||||
/* Initialize the node to no-match */
|
||||
@@ -305,26 +314,65 @@ static int lookupName(
|
||||
pTab = pItem->pTab;
|
||||
assert( pTab!=0 && pTab->zName!=0 );
|
||||
assert( pTab->nCol>0 || pParse->nErr );
|
||||
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
|
||||
assert( pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
||||
if( pItem->fg.isNestedFrom ){
|
||||
/* In this case, pItem is a subquery that has been formed from a
|
||||
** parenthesized subset of the FROM clause terms. Example:
|
||||
** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ...
|
||||
** \_________________________/
|
||||
** This pItem -------------^
|
||||
*/
|
||||
int hit = 0;
|
||||
assert( pItem->pSelect!=0 );
|
||||
pEList = pItem->pSelect->pEList;
|
||||
assert( pEList!=0 );
|
||||
assert( pEList->nExpr==pTab->nCol );
|
||||
for(j=0; j<pEList->nExpr; j++){
|
||||
if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
|
||||
cnt++;
|
||||
cntTab = 2;
|
||||
pMatch = pItem;
|
||||
pExpr->iColumn = j;
|
||||
hit = 1;
|
||||
if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
|
||||
continue;
|
||||
}
|
||||
if( cnt>0 ){
|
||||
if( pItem->fg.isUsing==0
|
||||
|| sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
|
||||
){
|
||||
/* Two or more tables have the same column name which is
|
||||
** not joined by USING. This is an error. Signal as much
|
||||
** by clearing pFJMatch and letting cnt go above 1. */
|
||||
sqlite3ExprListDelete(db, pFJMatch);
|
||||
pFJMatch = 0;
|
||||
}else
|
||||
if( (pItem->fg.jointype & JT_RIGHT)==0 ){
|
||||
/* An INNER or LEFT JOIN. Use the left-most table */
|
||||
continue;
|
||||
}else
|
||||
if( (pItem->fg.jointype & JT_LEFT)==0 ){
|
||||
/* A RIGHT JOIN. Use the right-most table */
|
||||
cnt = 0;
|
||||
sqlite3ExprListDelete(db, pFJMatch);
|
||||
pFJMatch = 0;
|
||||
}else{
|
||||
/* For a FULL JOIN, we must construct a coalesce() func */
|
||||
extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
cntTab = 2;
|
||||
pMatch = pItem;
|
||||
pExpr->iColumn = j;
|
||||
pEList->a[j].fg.bUsed = 1;
|
||||
hit = 1;
|
||||
if( pEList->a[j].fg.bUsingTerm ) break;
|
||||
}
|
||||
if( hit || zTab==0 ) continue;
|
||||
}
|
||||
if( zDb ){
|
||||
if( pTab->pSchema!=pSchema ) continue;
|
||||
if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
|
||||
}
|
||||
assert( zDb==0 || zTab!=0 );
|
||||
if( zTab ){
|
||||
const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
|
||||
const char *zTabName;
|
||||
if( zDb ){
|
||||
if( pTab->pSchema!=pSchema ) continue;
|
||||
if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
|
||||
}
|
||||
zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
|
||||
assert( zTabName!=0 );
|
||||
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
|
||||
continue;
|
||||
@@ -339,22 +387,37 @@ static int lookupName(
|
||||
if( pCol->hName==hCol
|
||||
&& sqlite3StrICmp(pCol->zCnName, zCol)==0
|
||||
){
|
||||
/* If there has been exactly one prior match and this match
|
||||
** is for the right-hand table of a NATURAL JOIN or is in a
|
||||
** USING clause, then skip this match.
|
||||
*/
|
||||
if( cnt==1 ){
|
||||
if( pItem->fg.jointype & JT_NATURAL ) continue;
|
||||
if( pItem->fg.isUsing
|
||||
&& nameInUsingClause(pItem->u3.pUsing, zCol)
|
||||
if( cnt>0 ){
|
||||
if( pItem->fg.isUsing==0
|
||||
|| sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
|
||||
){
|
||||
/* Two or more tables have the same column name which is
|
||||
** not joined by USING. This is an error. Signal as much
|
||||
** by clearing pFJMatch and letting cnt go above 1. */
|
||||
sqlite3ExprListDelete(db, pFJMatch);
|
||||
pFJMatch = 0;
|
||||
}else
|
||||
if( (pItem->fg.jointype & JT_RIGHT)==0 ){
|
||||
/* An INNER or LEFT JOIN. Use the left-most table */
|
||||
continue;
|
||||
}else
|
||||
if( (pItem->fg.jointype & JT_LEFT)==0 ){
|
||||
/* A RIGHT JOIN. Use the right-most table */
|
||||
cnt = 0;
|
||||
sqlite3ExprListDelete(db, pFJMatch);
|
||||
pFJMatch = 0;
|
||||
}else{
|
||||
/* For a FULL JOIN, we must construct a coalesce() func */
|
||||
extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
pMatch = pItem;
|
||||
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
||||
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
|
||||
if( pItem->fg.isNestedFrom ){
|
||||
sqlite3SrcItemColumnUsed(pItem, j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -367,9 +430,7 @@ static int lookupName(
|
||||
pExpr->iTable = pMatch->iCursor;
|
||||
assert( ExprUseYTab(pExpr) );
|
||||
pExpr->y.pTab = pMatch->pTab;
|
||||
/* RIGHT JOIN not (yet) supported */
|
||||
assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
|
||||
if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
|
||||
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
|
||||
ExprSetProperty(pExpr, EP_CanBeNull);
|
||||
}
|
||||
pSchema = pExpr->y.pTab->pSchema;
|
||||
@@ -523,7 +584,7 @@ static int lookupName(
|
||||
assert( pEList!=0 );
|
||||
for(j=0; j<pEList->nExpr; j++){
|
||||
char *zAs = pEList->a[j].zEName;
|
||||
if( pEList->a[j].eEName==ENAME_NAME
|
||||
if( pEList->a[j].fg.eEName==ENAME_NAME
|
||||
&& sqlite3_stricmp(zAs, zCol)==0
|
||||
){
|
||||
Expr *pOrig;
|
||||
@@ -610,11 +671,37 @@ static int lookupName(
|
||||
}
|
||||
|
||||
/*
|
||||
** cnt==0 means there was not match. cnt>1 means there were two or
|
||||
** more matches. Either way, we have an error.
|
||||
** cnt==0 means there was not match.
|
||||
** cnt>1 means there were two or more matches.
|
||||
**
|
||||
** cnt==0 is always an error. cnt>1 is often an error, but might
|
||||
** be multiple matches for a NATURAL LEFT JOIN or a LEFT JOIN USING.
|
||||
*/
|
||||
assert( pFJMatch==0 || cnt>0 );
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
|
||||
if( cnt!=1 ){
|
||||
const char *zErr;
|
||||
if( pFJMatch ){
|
||||
if( pFJMatch->nExpr==cnt-1 ){
|
||||
if( ExprHasProperty(pExpr,EP_Leaf) ){
|
||||
ExprClearProperty(pExpr,EP_Leaf);
|
||||
}else{
|
||||
sqlite3ExprDelete(db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pExpr->pRight);
|
||||
pExpr->pRight = 0;
|
||||
}
|
||||
extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
||||
pExpr->op = TK_FUNCTION;
|
||||
pExpr->u.zToken = "coalesce";
|
||||
pExpr->x.pList = pFJMatch;
|
||||
cnt = 1;
|
||||
goto lookupname_end;
|
||||
}else{
|
||||
sqlite3ExprListDelete(db, pFJMatch);
|
||||
pFJMatch = 0;
|
||||
}
|
||||
}
|
||||
zErr = cnt==0 ? "no such column" : "ambiguous column name";
|
||||
if( zDb ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
|
||||
@@ -627,6 +714,16 @@ static int lookupName(
|
||||
pParse->checkSchema = 1;
|
||||
pTopNC->nNcErr++;
|
||||
}
|
||||
assert( pFJMatch==0 );
|
||||
|
||||
/* Remove all substructure from pExpr */
|
||||
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
|
||||
sqlite3ExprDelete(db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pExpr->pRight);
|
||||
pExpr->pRight = 0;
|
||||
ExprSetProperty(pExpr, EP_Leaf);
|
||||
}
|
||||
|
||||
/* If a column from a table in pSrcList is referenced, then record
|
||||
** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes
|
||||
@@ -646,16 +743,7 @@ static int lookupName(
|
||||
pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
|
||||
}
|
||||
|
||||
/* Clean up and return
|
||||
*/
|
||||
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
|
||||
sqlite3ExprDelete(db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pExpr->pRight);
|
||||
pExpr->pRight = 0;
|
||||
}
|
||||
pExpr->op = eNewExprOp;
|
||||
ExprSetProperty(pExpr, EP_Leaf);
|
||||
lookupname_end:
|
||||
if( cnt==1 ){
|
||||
assert( pNC!=0 );
|
||||
@@ -1249,7 +1337,7 @@ static int resolveAsName(
|
||||
assert( !ExprHasProperty(pE, EP_IntValue) );
|
||||
zCol = pE->u.zToken;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( pEList->a[i].eEName==ENAME_NAME
|
||||
if( pEList->a[i].fg.eEName==ENAME_NAME
|
||||
&& sqlite3_stricmp(pEList->a[i].zEName, zCol)==0
|
||||
){
|
||||
return i+1;
|
||||
@@ -1370,7 +1458,7 @@ static int resolveCompoundOrderBy(
|
||||
return 1;
|
||||
}
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
pOrderBy->a[i].done = 0;
|
||||
pOrderBy->a[i].fg.done = 0;
|
||||
}
|
||||
pSelect->pNext = 0;
|
||||
while( pSelect->pPrior ){
|
||||
@@ -1385,7 +1473,7 @@ static int resolveCompoundOrderBy(
|
||||
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
||||
int iCol = -1;
|
||||
Expr *pE, *pDup;
|
||||
if( pItem->done ) continue;
|
||||
if( pItem->fg.done ) continue;
|
||||
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
|
||||
if( NEVER(pE==0) ) continue;
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
@@ -1438,7 +1526,7 @@ static int resolveCompoundOrderBy(
|
||||
sqlite3ExprDelete(db, pE);
|
||||
pItem->u.x.iOrderByCol = (u16)iCol;
|
||||
}
|
||||
pItem->done = 1;
|
||||
pItem->fg.done = 1;
|
||||
}else{
|
||||
moreToDo = 1;
|
||||
}
|
||||
@@ -1446,7 +1534,7 @@ static int resolveCompoundOrderBy(
|
||||
pSelect = pSelect->pNext;
|
||||
}
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
if( pOrderBy->a[i].done==0 ){
|
||||
if( pOrderBy->a[i].fg.done==0 ){
|
||||
sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any "
|
||||
"column in the result set", i+1);
|
||||
return 1;
|
||||
|
||||
+444
-205
File diff suppressed because it is too large
Load Diff
+19
-9
@@ -3350,6 +3350,8 @@ static void exec_prepared_stmt_columnar(
|
||||
int bNextLine = 0;
|
||||
int bMultiLineRowExists = 0;
|
||||
int bw = p->cmOpts.bWordWrap;
|
||||
const char *zEmpty = "";
|
||||
const char *zShowNull = p->nullValue;
|
||||
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc!=SQLITE_ROW ) return;
|
||||
@@ -3411,12 +3413,14 @@ static void exec_prepared_stmt_columnar(
|
||||
if( wx<0 ) wx = -wx;
|
||||
if( useNextLine ){
|
||||
uz = azNextLine[i];
|
||||
if( uz==0 ) uz = (u8*)zEmpty;
|
||||
}else if( p->cmOpts.bQuote ){
|
||||
sqlite3_free(azQuoted[i]);
|
||||
azQuoted[i] = quoted_column(pStmt,i);
|
||||
uz = (const unsigned char*)azQuoted[i];
|
||||
}else{
|
||||
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
|
||||
if( uz==0 ) uz = (u8*)zShowNull;
|
||||
}
|
||||
azData[nRow*nColumn + i]
|
||||
= translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
|
||||
@@ -3430,7 +3434,7 @@ static void exec_prepared_stmt_columnar(
|
||||
nTotal = nColumn*(nRow+1);
|
||||
for(i=0; i<nTotal; i++){
|
||||
z = azData[i];
|
||||
if( z==0 ) z = p->nullValue;
|
||||
if( z==0 ) z = (char*)zEmpty;
|
||||
n = strlenChar(z);
|
||||
j = i%nColumn;
|
||||
if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
|
||||
@@ -3534,7 +3538,10 @@ columnar_end:
|
||||
utf8_printf(p->out, "Interrupt\n");
|
||||
}
|
||||
nData = (nRow+1)*nColumn;
|
||||
for(i=0; i<nData; i++) free(azData[i]);
|
||||
for(i=0; i<nData; i++){
|
||||
z = azData[i];
|
||||
if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
|
||||
}
|
||||
sqlite3_free(azData);
|
||||
sqlite3_free((void*)azNextLine);
|
||||
sqlite3_free(abRowDiv);
|
||||
@@ -7833,7 +7840,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
|
||||
* zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE,
|
||||
* close db and set it to 0, and return the columns spec, to later
|
||||
@@ -7916,6 +7923,13 @@ UPDATE ColNames AS t SET reps=\
|
||||
static const char * const zColDigits = "\
|
||||
SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
|
||||
";
|
||||
#else
|
||||
/* Counting on SQLITE_MAX_COLUMN < 100,000 here. (32767 is the hard limit.) */
|
||||
static const char * const zColDigits = "\
|
||||
SELECT CASE WHEN (nc < 10) THEN 1 WHEN (nc < 100) THEN 2 \
|
||||
WHEN (nc < 1000) THEN 3 WHEN (nc < 10000) THEN 4 \
|
||||
ELSE 5 FROM (SELECT count(*) AS nc FROM ColNames) \
|
||||
";
|
||||
#endif
|
||||
static const char * const zRenameRank =
|
||||
#ifdef SHELL_COLUMN_RENAME_CLEAN
|
||||
@@ -7962,12 +7976,12 @@ SELECT\
|
||||
','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\
|
||||
||')' AS ColsSpec \
|
||||
FROM (\
|
||||
SELECT cpos, printf('\"%w\"',printf('%.*s%s', nlen-chop,name,suff)) AS cname \
|
||||
SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \
|
||||
FROM ColNames ORDER BY cpos\
|
||||
)";
|
||||
static const char * const zRenamesDone =
|
||||
"SELECT group_concat("
|
||||
" printf('\"%w\" to \"%w\"',name,printf('%.*s%s', nlen-chop, name, suff)),"
|
||||
" printf('\"%w\" to \"%w\"',name,printf('%!.*s%s', nlen-chop, name, suff)),"
|
||||
" ','||x'0a')"
|
||||
"FROM ColNames WHERE suff<>'' OR chop!=0"
|
||||
;
|
||||
@@ -8001,11 +8015,7 @@ FROM (\
|
||||
/* Formulate the columns spec, close the DB, zero *pDb. */
|
||||
char *zColsSpec = 0;
|
||||
int hasDupes = db_int(*pDb, zHasDupes);
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
|
||||
#else
|
||||
# define nDigits 2
|
||||
#endif
|
||||
if( hasDupes ){
|
||||
#ifdef SHELL_COLUMN_RENAME_CLEAN
|
||||
rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
|
||||
|
||||
+55
-23
@@ -1780,6 +1780,8 @@ struct sqlite3 {
|
||||
#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */
|
||||
#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
|
||||
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
|
||||
#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
|
||||
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
|
||||
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -2125,6 +2127,7 @@ struct Column {
|
||||
#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */
|
||||
#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */
|
||||
#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */
|
||||
#define COLFLAG_NOEXPAND 0x0400 /* Omit this column when expanding "*" */
|
||||
#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
|
||||
#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */
|
||||
|
||||
@@ -2844,7 +2847,7 @@ struct Expr {
|
||||
** TK_SELECT_COLUMN: column of the result vector */
|
||||
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||
union {
|
||||
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||
int iJoin; /* If EP_FromJoin, the right table of the join */
|
||||
int iOfst; /* else: start of token from start of statement */
|
||||
} w;
|
||||
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
||||
@@ -2887,7 +2890,7 @@ struct Expr {
|
||||
#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
|
||||
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
|
||||
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
|
||||
/* 0x400000 // Available */
|
||||
#define EP_InnerJoin 0x400000 /* Originates in ON/USING of an inner join */
|
||||
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
||||
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
||||
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
|
||||
@@ -2998,12 +3001,18 @@ struct ExprList {
|
||||
struct ExprList_item { /* For each expression in the list */
|
||||
Expr *pExpr; /* The parse tree for this expression */
|
||||
char *zEName; /* Token associated with this expression */
|
||||
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
||||
unsigned eEName :2; /* Meaning of zEName */
|
||||
unsigned done :1; /* A flag to indicate when processing is finished */
|
||||
unsigned reusable :1; /* Constant expression is reusable */
|
||||
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
||||
unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
|
||||
struct {
|
||||
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
||||
unsigned eEName :2; /* Meaning of zEName */
|
||||
unsigned done :1; /* Indicates when processing is finished */
|
||||
unsigned reusable :1; /* Constant expression is reusable */
|
||||
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
||||
unsigned bNulls :1; /* True if explicit "NULLS FIRST/LAST" */
|
||||
unsigned bUsed :1; /* This column used in a SF_NestedFrom subquery */
|
||||
unsigned bUsingTerm:1; /* Term from the USING clause of a NestedFrom */
|
||||
unsigned bNoExpand: 1; /* Term is an auxiliary in NestedFrom and should
|
||||
** not be expanded by "*" in parent queries */
|
||||
} fg;
|
||||
union {
|
||||
struct { /* Used by any ExprList other than Parse.pConsExpr */
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
@@ -3038,13 +3047,25 @@ struct ExprList {
|
||||
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
|
||||
*/
|
||||
struct IdList {
|
||||
int nId; /* Number of identifiers on the list */
|
||||
u8 eU4; /* Which element of a.u4 is valid */
|
||||
struct IdList_item {
|
||||
char *zName; /* Name of the identifier */
|
||||
int idx; /* Index in some Table.aCol[] of a column named zName */
|
||||
} *a;
|
||||
int nId; /* Number of identifiers on the list */
|
||||
union {
|
||||
int idx; /* Index in some Table.aCol[] of a column named zName */
|
||||
Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */
|
||||
} u4;
|
||||
} a[1];
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for IdList.eType, which determines which value of the a.u4
|
||||
** is valid.
|
||||
*/
|
||||
#define EU4_NONE 0 /* Does not use IdList.a.u4 */
|
||||
#define EU4_IDX 1 /* Uses IdList.a.u4.idx */
|
||||
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
|
||||
|
||||
/*
|
||||
** The SrcItem object represents a single term in the FROM clause of a query.
|
||||
** The SrcList object is mostly an array of SrcItems.
|
||||
@@ -3078,6 +3099,8 @@ struct SrcItem {
|
||||
unsigned isCte :1; /* This is a CTE */
|
||||
unsigned notCte :1; /* This item may not match a CTE */
|
||||
unsigned isUsing :1; /* u3.pUsing is valid */
|
||||
unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */
|
||||
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
|
||||
} fg;
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
union {
|
||||
@@ -3132,14 +3155,15 @@ struct SrcList {
|
||||
/*
|
||||
** Permitted values of the SrcList.a.jointype field
|
||||
*/
|
||||
#define JT_INNER 0x0001 /* Any kind of inner or cross join */
|
||||
#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */
|
||||
#define JT_NATURAL 0x0004 /* True for a "natural" join */
|
||||
#define JT_LEFT 0x0008 /* Left outer join */
|
||||
#define JT_RIGHT 0x0010 /* Right outer join */
|
||||
#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
|
||||
#define JT_ERROR 0x0040 /* unknown or unsupported join type */
|
||||
|
||||
#define JT_INNER 0x01 /* Any kind of inner or cross join */
|
||||
#define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */
|
||||
#define JT_NATURAL 0x04 /* True for a "natural" join */
|
||||
#define JT_LEFT 0x08 /* Left outer join */
|
||||
#define JT_RIGHT 0x10 /* Right outer join */
|
||||
#define JT_OUTER 0x20 /* The "OUTER" keyword is present */
|
||||
#define JT_LTORJ 0x40 /* One of the LEFT operands of a RIGHT JOIN
|
||||
** Mnemonic: Left Table Of Right Join */
|
||||
#define JT_ERROR 0x80 /* unknown or unsupported join type */
|
||||
|
||||
/*
|
||||
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
|
||||
@@ -3162,7 +3186,7 @@ struct SrcList {
|
||||
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
|
||||
#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
|
||||
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
|
||||
/* 0x1000 not currently used */
|
||||
#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
|
||||
/* 0x2000 not currently used */
|
||||
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
|
||||
/* 0x8000 not currently used */
|
||||
@@ -3358,6 +3382,9 @@ struct Select {
|
||||
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
|
||||
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
|
||||
|
||||
/* True if S exists and has SF_NestedFrom */
|
||||
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
** by one of the following macros. The "SRT" prefix means "SELECT Result
|
||||
@@ -3569,6 +3596,7 @@ struct Parse {
|
||||
u8 okConstFactor; /* OK to factor out constants */
|
||||
u8 disableLookaside; /* Number of times lookaside has been disabled */
|
||||
u8 disableVtab; /* Disable all virtual tables for this parse */
|
||||
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
|
||||
#endif
|
||||
@@ -4438,6 +4466,7 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
||||
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
|
||||
void sqlite3TreeViewBareIdList(TreeView*, const IdList*, const char*);
|
||||
void sqlite3TreeViewIdList(TreeView*, const IdList*, u8, const char*);
|
||||
void sqlite3TreeViewColumnList(TreeView*, const Column*, int, u8);
|
||||
void sqlite3TreeViewSrcList(TreeView*, const SrcList*);
|
||||
void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
|
||||
void sqlite3TreeViewWith(TreeView*, const With*, u8);
|
||||
@@ -4628,7 +4657,7 @@ SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
||||
void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
|
||||
void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
|
||||
int sqlite3IndexedByLookup(Parse *, SrcItem *);
|
||||
void sqlite3SrcListShiftJoinType(SrcList*);
|
||||
void sqlite3SrcListShiftJoinType(Parse*,SrcList*);
|
||||
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||
void sqlite3IdListDelete(sqlite3*, IdList*);
|
||||
void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
|
||||
@@ -4731,6 +4760,7 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
|
||||
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
|
||||
int sqlite3ExprIsTableConstant(Expr*,int);
|
||||
int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
|
||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
||||
int sqlite3ExprContainsSubquery(Expr*);
|
||||
#endif
|
||||
@@ -4828,7 +4858,8 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
|
||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||
int sqlite3ColumnIndex(Table *pTab, const char *zCol);
|
||||
void sqlite3SetJoinExpr(Expr*,int);
|
||||
void sqlite3SrcItemColumnUsed(SrcItem*,int);
|
||||
void sqlite3SetJoinExpr(Expr*,int,u32);
|
||||
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
|
||||
void sqlite3DeferForeignKey(Parse*, int);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
@@ -5174,7 +5205,7 @@ int sqlite3VtabBegin(sqlite3 *, VTable *);
|
||||
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
|
||||
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
|
||||
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
void sqlite3VtabWriteAll(sqlite3_index_info*);
|
||||
void sqlite3VtabUsesAllSchemas(sqlite3_index_info*);
|
||||
#endif
|
||||
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
@@ -5291,6 +5322,7 @@ const char *sqlite3JournalModename(int);
|
||||
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
|
||||
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
|
||||
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
|
||||
#define IN_INDEX_REUSE_CUR 0x0008 /* Reuse prior table cursor */
|
||||
int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*);
|
||||
|
||||
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
||||
|
||||
+118
-8
@@ -86,6 +86,53 @@ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
|
||||
sqlite3TreeViewLine(p, "%s", zLabel);
|
||||
}
|
||||
|
||||
/*
|
||||
** Show a list of Column objects in tree format.
|
||||
*/
|
||||
void sqlite3TreeViewColumnList(
|
||||
TreeView *pView,
|
||||
const Column *aCol,
|
||||
int nCol,
|
||||
u8 moreToFollow
|
||||
){
|
||||
int i;
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
sqlite3TreeViewLine(pView, "COLUMNS");
|
||||
for(i=0; i<nCol; i++){
|
||||
u16 flg = aCol[i].colFlags;
|
||||
int moreToFollow = i<(nCol - 1);
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
sqlite3TreeViewLine(pView, 0);
|
||||
printf(" %s", aCol[i].zCnName);
|
||||
switch( aCol[i].eCType ){
|
||||
case COLTYPE_ANY: printf(" ANY"); break;
|
||||
case COLTYPE_BLOB: printf(" BLOB"); break;
|
||||
case COLTYPE_INT: printf(" INT"); break;
|
||||
case COLTYPE_INTEGER: printf(" INTEGER"); break;
|
||||
case COLTYPE_REAL: printf(" REAL"); break;
|
||||
case COLTYPE_TEXT: printf(" TEXT"); break;
|
||||
case COLTYPE_CUSTOM: {
|
||||
if( flg & COLFLAG_HASTYPE ){
|
||||
const char *z = aCol[i].zCnName;
|
||||
z += strlen(z)+1;
|
||||
printf(" X-%s", z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( flg & COLFLAG_PRIMKEY ) printf(" PRIMARY KEY");
|
||||
if( flg & COLFLAG_HIDDEN ) printf(" HIDDEN");
|
||||
#ifdef COLFLAG_NOEXPAND
|
||||
if( flg & COLFLAG_NOEXPAND ) printf(" NO-EXPAND");
|
||||
#endif
|
||||
if( flg ) printf(" flags=%04x", flg);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable description of a WITH clause.
|
||||
*/
|
||||
@@ -115,6 +162,10 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
}
|
||||
sqlite3_str_appendf(&x, ")");
|
||||
}
|
||||
if( pCte->eM10d!=M10d_Any ){
|
||||
sqlite3_str_appendf(&x, " %sMATERIALIZED",
|
||||
pCte->eM10d==M10d_No ? "NOT " : "");
|
||||
}
|
||||
if( pCte->pUse ){
|
||||
sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse,
|
||||
pCte->pUse->nUse);
|
||||
@@ -133,9 +184,11 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
*/
|
||||
void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
int i;
|
||||
if( pSrc==0 ) return;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
const SrcItem *pItem = &pSrc->a[i];
|
||||
StrAccum x;
|
||||
int n = 0;
|
||||
char zLine[100];
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
x.printfFlags |= SQLITE_PRINTF_INTERNAL;
|
||||
@@ -144,11 +197,18 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
|
||||
pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
|
||||
}
|
||||
if( pItem->fg.jointype & JT_LEFT ){
|
||||
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
|
||||
sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
|
||||
}else if( pItem->fg.jointype & JT_LEFT ){
|
||||
sqlite3_str_appendf(&x, " LEFT-JOIN");
|
||||
}else if( pItem->fg.jointype & JT_RIGHT ){
|
||||
sqlite3_str_appendf(&x, " RIGHT-JOIN");
|
||||
}else if( pItem->fg.jointype & JT_CROSS ){
|
||||
sqlite3_str_appendf(&x, " CROSS-JOIN");
|
||||
}
|
||||
if( pItem->fg.jointype & JT_LTORJ ){
|
||||
sqlite3_str_appendf(&x, " LTORJ");
|
||||
}
|
||||
if( pItem->fg.fromDDL ){
|
||||
sqlite3_str_appendf(&x, " DDL");
|
||||
}
|
||||
@@ -156,9 +216,21 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
||||
n = 0;
|
||||
if( pItem->pSelect ) n++;
|
||||
if( pItem->fg.isTabFunc ) n++;
|
||||
if( pItem->fg.isUsing ) n++;
|
||||
if( pItem->fg.isUsing ){
|
||||
sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
|
||||
}
|
||||
if( pItem->pSelect ){
|
||||
sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
|
||||
if( pItem->pTab ){
|
||||
Table *pTab = pItem->pTab;
|
||||
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
|
||||
}
|
||||
assert( pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
||||
sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
|
||||
}
|
||||
if( pItem->fg.isTabFunc ){
|
||||
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
|
||||
@@ -325,6 +397,7 @@ void sqlite3TreeViewBound(
|
||||
*/
|
||||
void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
int nElement = 0;
|
||||
if( pWin==0 ) return;
|
||||
if( pWin->pFilter ){
|
||||
sqlite3TreeViewItem(pView, "FILTER", 1);
|
||||
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
|
||||
@@ -389,6 +462,7 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
** Generate a human-readable explanation for a Window Function object
|
||||
*/
|
||||
void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
|
||||
if( pWin==0 ) return;
|
||||
sqlite3TreeViewPush(&pView, more);
|
||||
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
|
||||
pWin->pWFunc->zName, pWin->pWFunc->nArg);
|
||||
@@ -416,7 +490,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3_str_appendf(&x, " fg.af=%x.%c",
|
||||
pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
sqlite3_str_appendf(&x, " iRJT=%d", pExpr->w.iRightJoinTable);
|
||||
sqlite3_str_appendf(&x, " iJoin=%d", pExpr->w.iJoin);
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_FromDDL) ){
|
||||
sqlite3_str_appendf(&x, " DDL");
|
||||
@@ -640,7 +714,17 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
break;
|
||||
}
|
||||
case TK_IN: {
|
||||
sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags);
|
||||
sqlite3_str *pStr = sqlite3_str_new(0);
|
||||
char *z;
|
||||
sqlite3_str_appendf(pStr, "IN flags=0x%x", pExpr->flags);
|
||||
if( pExpr->iTable ) sqlite3_str_appendf(pStr, " iTable=%d",pExpr->iTable);
|
||||
if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||
sqlite3_str_appendf(pStr, " subrtn(%d,%d)",
|
||||
pExpr->y.sub.regReturn, pExpr->y.sub.iAddr);
|
||||
}
|
||||
z = sqlite3_str_finish(pStr);
|
||||
sqlite3TreeViewLine(pView, z);
|
||||
sqlite3_free(z);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
if( ExprUseXSelect(pExpr) ){
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
@@ -786,13 +870,25 @@ void sqlite3TreeViewBareExprList(
|
||||
int j = pList->a[i].u.x.iOrderByCol;
|
||||
char *zName = pList->a[i].zEName;
|
||||
int moreToFollow = i<pList->nExpr - 1;
|
||||
if( pList->a[i].eEName!=ENAME_NAME ) zName = 0;
|
||||
if( j || zName ){
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
moreToFollow = 0;
|
||||
sqlite3TreeViewLine(pView, 0);
|
||||
if( zName ){
|
||||
fprintf(stdout, "AS %s ", zName);
|
||||
switch( pList->a[i].fg.eEName ){
|
||||
default:
|
||||
fprintf(stdout, "AS %s ", zName);
|
||||
break;
|
||||
case ENAME_TAB:
|
||||
fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName);
|
||||
if( pList->a[i].fg.bUsed ) fprintf(stdout, "(used) ");
|
||||
if( pList->a[i].fg.bUsingTerm ) fprintf(stdout, "(USING-term) ");
|
||||
if( pList->a[i].fg.bNoExpand ) fprintf(stdout, "(NoExpand) ");
|
||||
break;
|
||||
case ENAME_SPAN:
|
||||
fprintf(stdout, "SPAN(\"%s\") ", zName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j ){
|
||||
fprintf(stdout, "iOrderByCol=%d", j);
|
||||
@@ -838,7 +934,21 @@ void sqlite3TreeViewBareIdList(
|
||||
if( zName==0 ) zName = "(null)";
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
sqlite3TreeViewLine(pView, 0);
|
||||
fprintf(stdout, "%s (%d)\n", zName, pList->a[i].idx);
|
||||
if( pList->eU4==EU4_NONE ){
|
||||
fprintf(stdout, "%s\n", zName);
|
||||
}else if( pList->eU4==EU4_IDX ){
|
||||
fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx);
|
||||
}else{
|
||||
assert( pList->eU4==EU4_EXPR );
|
||||
if( pList->a[i].u4.pExpr==0 ){
|
||||
fprintf(stdout, "%s (pExpr=NULL)\n", zName);
|
||||
}else{
|
||||
fprintf(stdout, "%s\n", zName);
|
||||
sqlite3TreeViewPush(&pView, i<pList->nId-1);
|
||||
sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -905,7 +905,7 @@ static ExprList *sqlite3ExpandReturning(
|
||||
if( !db->mallocFailed ){
|
||||
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
||||
pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName);
|
||||
pItem->eEName = ENAME_NAME;
|
||||
pItem->fg.eEName = ENAME_NAME;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -914,7 +914,7 @@ static ExprList *sqlite3ExpandReturning(
|
||||
if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){
|
||||
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
||||
pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName);
|
||||
pItem->eEName = pList->a[i].eEName;
|
||||
pItem->fg.eEName = pList->a[i].fg.eEName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+73
-45
@@ -983,18 +983,22 @@ case OP_Gosub: { /* jump */
|
||||
pIn1->flags = MEM_Int;
|
||||
pIn1->u.i = (int)(pOp-aOp);
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
|
||||
/* Most jump operations do a goto to this spot in order to update
|
||||
** the pOp pointer. */
|
||||
jump_to_p2:
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
break;
|
||||
goto jump_to_p2_and_check_for_interrupt;
|
||||
}
|
||||
|
||||
/* Opcode: Return P1 P2 P3 * *
|
||||
**
|
||||
** Jump to the next instruction after the address in register P1. After
|
||||
** the jump, register P1 becomes undefined.
|
||||
** Jump to the address stored in register P1. If P1 is a return address
|
||||
** register, then this accomplishes a return from a subroutine.
|
||||
**
|
||||
** If P3 is 1, then the jump is only taken if register P1 holds an integer
|
||||
** values, otherwise execution falls through to the next opcode, and the
|
||||
** OP_Return becomes a no-op. If P3 is 0, then register P1 must hold an
|
||||
** integer or else an assert() is raised. P3 should be set to 1 when
|
||||
** this opcode is used in combination with OP_BeginSubrtn, and set to 0
|
||||
** otherwise.
|
||||
**
|
||||
** The value in register P1 is unchanged by this opcode.
|
||||
**
|
||||
** P2 is not used by the byte-code engine. However, if P2 is positive
|
||||
** and also less than the current address, then the "EXPLAIN" output
|
||||
@@ -1003,16 +1007,15 @@ jump_to_p2:
|
||||
** in the subroutine from which this opcode is returnning. Thus the P2
|
||||
** value is a byte-code indentation hint. See tag-20220407a in
|
||||
** wherecode.c and shell.c.
|
||||
**
|
||||
** P3 is not used by the byte-code engine. However, the code generator
|
||||
** sets P3 to address of the associated OP_BeginSubrtn opcode, if there is
|
||||
** one.
|
||||
*/
|
||||
case OP_Return: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
pOp = &aOp[pIn1->u.i];
|
||||
pIn1->flags = MEM_Undefined;
|
||||
if( pIn1->flags & MEM_Int ){
|
||||
if( pOp->p3 ){ VdbeBranchTaken(1, 2); }
|
||||
pOp = &aOp[pIn1->u.i];
|
||||
}else if( ALWAYS(pOp->p3) ){
|
||||
VdbeBranchTaken(0, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1035,7 +1038,14 @@ case OP_InitCoroutine: { /* jump */
|
||||
assert( !VdbeMemDynamic(pOut) );
|
||||
pOut->u.i = pOp->p3 - 1;
|
||||
pOut->flags = MEM_Int;
|
||||
if( pOp->p2 ) goto jump_to_p2;
|
||||
if( pOp->p2==0 ) break;
|
||||
|
||||
/* Most jump operations do a goto to this spot in order to update
|
||||
** the pOp pointer. */
|
||||
jump_to_p2:
|
||||
assert( pOp->p2>0 ); /* There are never any jumps to instruction 0 */
|
||||
assert( pOp->p2<p->nOp ); /* Jumps must be in range */
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1193,22 +1203,11 @@ case OP_Halt: {
|
||||
goto vdbe_return;
|
||||
}
|
||||
|
||||
/* Opcode: BeginSubrtn P1 P2 * * *
|
||||
** Synopsis: r[P2]=P1
|
||||
**
|
||||
** Mark the beginning of a subroutine by loading the integer value P1
|
||||
** into register r[P2]. The P2 register is used to store the return
|
||||
** address of the subroutine call.
|
||||
**
|
||||
** This opcode is identical to OP_Integer. It has a different name
|
||||
** only to make the byte code easier to read and verify.
|
||||
*/
|
||||
/* Opcode: Integer P1 P2 * * *
|
||||
** Synopsis: r[P2]=P1
|
||||
**
|
||||
** The 32-bit integer value P1 is written into register P2.
|
||||
*/
|
||||
case OP_BeginSubrtn:
|
||||
case OP_Integer: { /* out2 */
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = pOp->p1;
|
||||
@@ -1315,6 +1314,28 @@ case OP_String: { /* out2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: BeginSubrtn * P2 * * *
|
||||
** Synopsis: r[P2]=NULL
|
||||
**
|
||||
** Mark the beginning of a subroutine that can be entered in-line
|
||||
** or that can be called using OP_Gosub. The subroutine should
|
||||
** be terminated by an OP_Return instruction that has a P1 operand that
|
||||
** is the same as the P2 operand to this opcode and that has P3 set to 1.
|
||||
** If the subroutine is entered in-line, then the OP_Return will simply
|
||||
** fall through. But if the subroutine is entered using OP_Gosub, then
|
||||
** the OP_Return will jump back to the first instruction after the OP_Gosub.
|
||||
**
|
||||
** This routine works by loading a NULL into the P2 register. When the
|
||||
** return address register contains a NULL, the OP_Return instruction is
|
||||
** a no-op that simply falls through to the next instruction (assuming that
|
||||
** the OP_Return opcode has a P3 value of 1). Thus if the subroutine is
|
||||
** entered in-line, then the OP_Return will cause in-line execution to
|
||||
** continue. But if the subroutine is entered via OP_Gosub, then the
|
||||
** OP_Return will cause a return to the address following the OP_Gosub.
|
||||
**
|
||||
** This opcode is identical to OP_Null. It has a different name
|
||||
** only to make the byte code easier to read and verify.
|
||||
*/
|
||||
/* Opcode: Null P1 P2 P3 * *
|
||||
** Synopsis: r[P2..P3]=NULL
|
||||
**
|
||||
@@ -1327,6 +1348,7 @@ case OP_String: { /* out2 */
|
||||
** NULL values will not compare equal even if SQLITE_NULLEQ is set on
|
||||
** OP_Ne or OP_Eq.
|
||||
*/
|
||||
case OP_BeginSubrtn:
|
||||
case OP_Null: { /* out2 */
|
||||
int cnt;
|
||||
u16 nullFlag;
|
||||
@@ -2659,7 +2681,7 @@ case OP_Offset: { /* out3 */
|
||||
#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
|
||||
|
||||
/* Opcode: Column P1 P2 P3 P4 P5
|
||||
** Synopsis: r[P3]=PX
|
||||
** Synopsis: r[P3]=PX cursor P1 column P2
|
||||
**
|
||||
** Interpret the data that cursor P1 points to as a structure built using
|
||||
** the MakeRecord instruction. (See the MakeRecord opcode for additional
|
||||
@@ -2701,7 +2723,8 @@ case OP_Column: {
|
||||
|
||||
op_column_restart:
|
||||
assert( pC!=0 );
|
||||
assert( p2<(u32)pC->nField );
|
||||
assert( p2<(u32)pC->nField
|
||||
|| (pC->eCurType==CURTYPE_PSEUDO && pC->seekResult==0) );
|
||||
aOffset = pC->aOffset;
|
||||
assert( aOffset==pC->aType+pC->nField );
|
||||
assert( pC->eCurType!=CURTYPE_VTAB );
|
||||
@@ -2710,10 +2733,9 @@ op_column_restart:
|
||||
|
||||
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
if( pC->nullRow ){
|
||||
if( pC->eCurType==CURTYPE_PSEUDO ){
|
||||
if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult>0 ){
|
||||
/* For the special case of as pseudo-cursor, the seekResult field
|
||||
** identifies the register that holds the record */
|
||||
assert( pC->seekResult>0 );
|
||||
pReg = &aMem[pC->seekResult];
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
@@ -4990,15 +5012,14 @@ case OP_Found: { /* jump, in3 */
|
||||
#ifdef SQLITE_DEBUG
|
||||
pC->seekOp = pOp->opcode;
|
||||
#endif
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
r.aMem = &aMem[pOp->p3];
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable==0 );
|
||||
if( pOp->p4.i>0 ){
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
if( r.nField>0 ){
|
||||
/* Key values in an array of registers */
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.aMem = pIn3;
|
||||
r.default_rc = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(ii=0; ii<r.nField; ii++){
|
||||
@@ -5010,14 +5031,14 @@ case OP_Found: { /* jump, in3 */
|
||||
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &pC->seekResult);
|
||||
}else{
|
||||
/* Composite key generated by OP_MakeRecord */
|
||||
assert( pIn3->flags & MEM_Blob );
|
||||
assert( r.aMem->flags & MEM_Blob );
|
||||
assert( pOp->opcode!=OP_NoConflict );
|
||||
rc = ExpandBlob(pIn3);
|
||||
rc = ExpandBlob(r.aMem);
|
||||
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
|
||||
if( rc ) goto no_mem;
|
||||
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
|
||||
if( pIdxKey==0 ) goto no_mem;
|
||||
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
|
||||
sqlite3VdbeRecordUnpack(pC->pKeyInfo, r.aMem->n, r.aMem->z, pIdxKey);
|
||||
pIdxKey->default_rc = 0;
|
||||
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &pC->seekResult);
|
||||
sqlite3DbFreeNN(db, pIdxKey);
|
||||
@@ -5742,7 +5763,7 @@ case OP_RowData: {
|
||||
}
|
||||
|
||||
/* Opcode: Rowid P1 P2 * * *
|
||||
** Synopsis: r[P2]=rowid
|
||||
** Synopsis: r[P2]=PX rowid of P1
|
||||
**
|
||||
** Store in register P2 an integer which is the key of the table entry that
|
||||
** P1 is currently point to.
|
||||
@@ -5798,16 +5819,23 @@ case OP_Rowid: { /* out2 */
|
||||
** that occur while the cursor is on the null row will always
|
||||
** write a NULL.
|
||||
**
|
||||
** Or, if P1 is a Pseudo-Cursor (a cursor opened using OP_OpenPseudo)
|
||||
** just reset the cache for that cursor. This causes the row of
|
||||
** content held by the pseudo-cursor to be reparsed.
|
||||
** If cursor P1 is not previously opened, open it now to a special
|
||||
** pseudo-cursor that always returns NULL for every column.
|
||||
*/
|
||||
case OP_NullRow: {
|
||||
VdbeCursor *pC;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
if( pC==0 ){
|
||||
/* If the cursor is not already open, create a special kind of
|
||||
** pseudo-cursor that always gives null rows. */
|
||||
pC = allocateCursor(p, pOp->p1, 1, CURTYPE_PSEUDO);
|
||||
if( pC==0 ) goto no_mem;
|
||||
pC->seekResult = 0;
|
||||
pC->isTable = 1;
|
||||
pC->uc.pCursor = sqlite3BtreeFakeValidCursor();
|
||||
}
|
||||
pC->nullRow = 1;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( pC->eCurType==CURTYPE_BTREE ){
|
||||
@@ -6254,9 +6282,9 @@ case OP_IdxRowid: { /* out2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->eCurType==CURTYPE_BTREE || IsNullCursor(pC) );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( pC->isTable==0 );
|
||||
assert( pC->isTable==0 || IsNullCursor(pC) );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
|
||||
|
||||
|
||||
@@ -198,8 +198,10 @@ void sqlite3VdbeEndCoroutine(Vdbe*,int);
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG)
|
||||
void sqlite3VdbeVerifyAbortable(Vdbe *p, int);
|
||||
void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int);
|
||||
#else
|
||||
# define sqlite3VdbeVerifyAbortable(A,B)
|
||||
# define sqlite3VdbeNoJumpsOutsideSubrtn(A,B,C,D)
|
||||
#endif
|
||||
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
|
||||
@@ -134,6 +134,11 @@ struct VdbeCursor {
|
||||
u32 aType[1]; /* Type values record decode. MUST BE LAST */
|
||||
};
|
||||
|
||||
/* Return true if P is a null-only cursor
|
||||
*/
|
||||
#define IsNullCursor(P) \
|
||||
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
|
||||
|
||||
|
||||
/*
|
||||
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
|
||||
|
||||
+91
-2
@@ -880,6 +880,90 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Check to see if a subroutine contains a jump to a location outside of
|
||||
** the subroutine. If a jump outside the subroutine is detected, add code
|
||||
** that will cause the program to halt with an error message.
|
||||
**
|
||||
** The subroutine consists of opcodes between iFirst and iLast. Jumps to
|
||||
** locations within the subroutine are acceptable. iRetReg is a register
|
||||
** that contains the return address. Jumps to outside the range of iFirst
|
||||
** through iLast are also acceptable as long as the jump destination is
|
||||
** an OP_Return to iReturnAddr.
|
||||
**
|
||||
** A jump to an unresolved label means that the jump destination will be
|
||||
** beyond the current address. That is normally a jump to an early
|
||||
** termination and is consider acceptable.
|
||||
**
|
||||
** This routine only runs during debug builds. The purpose is (of course)
|
||||
** to detect invalid escapes out of a subroutine. The OP_Halt opcode
|
||||
** is generated rather than an assert() or other error, so that ".eqp full"
|
||||
** will still work to show the original bytecode, to aid in debugging.
|
||||
*/
|
||||
void sqlite3VdbeNoJumpsOutsideSubrtn(
|
||||
Vdbe *v, /* The byte-code program under construction */
|
||||
int iFirst, /* First opcode of the subroutine */
|
||||
int iLast, /* Last opcode of the subroutine */
|
||||
int iRetReg /* Subroutine return address register */
|
||||
){
|
||||
VdbeOp *pOp;
|
||||
Parse *pParse;
|
||||
int i;
|
||||
sqlite3_str *pErr = 0;
|
||||
assert( v!=0 );
|
||||
pParse = v->pParse;
|
||||
assert( pParse!=0 );
|
||||
if( pParse->nErr ) return;
|
||||
assert( iLast>=iFirst );
|
||||
assert( iLast<v->nOp );
|
||||
pOp = &v->aOp[iFirst];
|
||||
for(i=iFirst; i<=iLast; i++, pOp++){
|
||||
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ){
|
||||
int iDest = pOp->p2; /* Jump destination */
|
||||
if( iDest==0 ) continue;
|
||||
if( pOp->opcode==OP_Gosub ) continue;
|
||||
if( iDest<0 ){
|
||||
int j = ADDR(iDest);
|
||||
assert( j>=0 );
|
||||
if( j>=-pParse->nLabel || pParse->aLabel[j]<0 ){
|
||||
continue;
|
||||
}
|
||||
iDest = pParse->aLabel[j];
|
||||
}
|
||||
if( iDest<iFirst || iDest>iLast ){
|
||||
int j = iDest;
|
||||
for(; j<v->nOp; j++){
|
||||
VdbeOp *pX = &v->aOp[j];
|
||||
if( pX->opcode==OP_Return ){
|
||||
if( pX->p1==iRetReg ) break;
|
||||
continue;
|
||||
}
|
||||
if( pX->opcode==OP_Noop ) continue;
|
||||
if( pX->opcode==OP_Explain ) continue;
|
||||
if( pErr==0 ){
|
||||
pErr = sqlite3_str_new(0);
|
||||
}else{
|
||||
sqlite3_str_appendchar(pErr, 1, '\n');
|
||||
}
|
||||
sqlite3_str_appendf(pErr,
|
||||
"Opcode at %d jumps to %d which is outside the "
|
||||
"subroutine at %d..%d",
|
||||
i, iDest, iFirst, iLast);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pErr ){
|
||||
char *zErr = sqlite3_str_finish(pErr);
|
||||
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_INTERNAL, OE_Abort, 0, zErr, 0);
|
||||
sqlite3_free(zErr);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Return the address of the next instruction to be inserted.
|
||||
*/
|
||||
@@ -1490,8 +1574,13 @@ char *sqlite3VdbeDisplayComment(
|
||||
if( c=='4' ){
|
||||
sqlite3_str_appendall(&x, zP4);
|
||||
}else if( c=='X' ){
|
||||
sqlite3_str_appendall(&x, pOp->zComment);
|
||||
if( pOp->zComment && pOp->zComment[0] ){
|
||||
sqlite3_str_appendall(&x, pOp->zComment);
|
||||
}else{
|
||||
sqlite3_str_appendall(&x, zSynopsis+1);
|
||||
}
|
||||
seenCom = 1;
|
||||
break;
|
||||
}else{
|
||||
int v1 = translateP(c, pOp);
|
||||
int v2;
|
||||
@@ -3549,7 +3638,7 @@ int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p){
|
||||
** if need be. Return any I/O error from the restore operation.
|
||||
*/
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
assert( p->eCurType==CURTYPE_BTREE );
|
||||
assert( p->eCurType==CURTYPE_BTREE || IsNullCursor(p) );
|
||||
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
||||
return sqlite3VdbeHandleMovedCursor(p);
|
||||
}
|
||||
|
||||
+143
-68
@@ -102,7 +102,7 @@ int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
|
||||
}
|
||||
pInner = &pWInfo->a[pWInfo->nLevel-1];
|
||||
assert( pInner->addrNxt!=0 );
|
||||
return pInner->addrNxt;
|
||||
return pInner->pRJ ? pWInfo->iContinue : pInner->addrNxt;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -253,6 +253,30 @@ Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate memory that is automatically freed when pWInfo is freed.
|
||||
*/
|
||||
void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte){
|
||||
WhereMemBlock *pBlock;
|
||||
pBlock = sqlite3DbMallocRawNN(pWInfo->pParse->db, nByte+sizeof(*pBlock));
|
||||
if( pBlock ){
|
||||
pBlock->pNext = pWInfo->pMemToFree;
|
||||
pBlock->sz = nByte;
|
||||
pWInfo->pMemToFree = pBlock;
|
||||
pBlock++;
|
||||
}
|
||||
return (void*)pBlock;
|
||||
}
|
||||
void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte){
|
||||
void *pNew = sqlite3WhereMalloc(pWInfo, nByte);
|
||||
if( pNew && pOld ){
|
||||
WhereMemBlock *pOldBlk = (WhereMemBlock*)pOld;
|
||||
pOldBlk--;
|
||||
assert( pOldBlk->sz<nByte );
|
||||
memcpy(pNew, pOld, pOldBlk->sz);
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new mask for cursor iCursor.
|
||||
**
|
||||
@@ -732,13 +756,13 @@ static int termCanDriveIndex(
|
||||
char aff;
|
||||
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
|
||||
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
|
||||
if( (pSrc->fg.jointype & JT_LEFT)
|
||||
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
&& (pTerm->eOperator & WO_IS)
|
||||
){
|
||||
/* Cannot use an IS term from the WHERE clause as an index driver for
|
||||
** the RHS of a LEFT JOIN. Such a term can only be used if it is from
|
||||
** the ON clause. */
|
||||
** the RHS of a LEFT JOIN or for the LHS of a RIGHT JOIN. Such a term
|
||||
** can only be used if it is from the ON clause. */
|
||||
return 0;
|
||||
}
|
||||
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
|
||||
@@ -808,8 +832,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
** WHERE clause (or the ON clause of a LEFT join) that constrain which
|
||||
** rows of the target table (pSrc) that can be used. */
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
|
||||
&& ((pSrc->fg.jointype&JT_LEFT)==0 || ExprHasProperty(pExpr,EP_FromJoin))
|
||||
&& sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor)
|
||||
&& sqlite3ExprIsTableConstraint(pExpr, pSrc)
|
||||
){
|
||||
pPartial = sqlite3ExprAnd(pParse, pPartial,
|
||||
sqlite3ExprDup(pParse->db, pExpr, 0));
|
||||
@@ -1048,7 +1071,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
|
||||
&& sqlite3ExprIsTableConstant(pExpr, iCur)
|
||||
&& sqlite3ExprIsTableConstraint(pExpr, pItem)
|
||||
){
|
||||
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
@@ -1081,7 +1104,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
||||
const SrcItem *pTabItem;
|
||||
pLevel = &pWInfo->a[iLevel];
|
||||
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
||||
if( pTabItem->fg.jointype & JT_LEFT ) continue;
|
||||
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
|
||||
pLoop = pLevel->pWLoop;
|
||||
if( NEVER(pLoop==0) ) continue;
|
||||
if( pLoop->prereq & notReady ) continue;
|
||||
@@ -1154,9 +1177,10 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
assert( pTerm->u.x.leftColumn<pTab->nCol );
|
||||
|
||||
/* tag-20191211-002: WHERE-clause constraints are not useful to the
|
||||
** right-hand table of a LEFT JOIN. See tag-20191211-001 for the
|
||||
** right-hand table of a LEFT JOIN nor to the left-hand table of a
|
||||
** RIGHT JOIN. See tag-20191211-001 for the
|
||||
** equivalent restriction for ordinary tables. */
|
||||
if( (pSrc->fg.jointype & JT_LEFT)!=0
|
||||
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
){
|
||||
continue;
|
||||
@@ -1182,7 +1206,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
}
|
||||
|
||||
/* Virtual tables are unable to deal with NULLS FIRST */
|
||||
if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
||||
if( pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
||||
|
||||
/* First case - a direct column references without a COLLATE operator */
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSrc->iCursor ){
|
||||
@@ -1294,7 +1318,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
|
||||
&& pExpr->iColumn==pExpr->pLeft->iColumn) );
|
||||
pIdxOrderBy[j].iColumn = pExpr->iColumn;
|
||||
pIdxOrderBy[j].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
|
||||
pIdxOrderBy[j].desc = pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC;
|
||||
j++;
|
||||
}
|
||||
pIdxInfo->nOrderBy = j;
|
||||
@@ -2216,15 +2240,7 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
|
||||
** Free a WhereInfo structure
|
||||
*/
|
||||
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
int i;
|
||||
assert( pWInfo!=0 );
|
||||
for(i=0; i<pWInfo->nLevel; i++){
|
||||
WhereLevel *pLevel = &pWInfo->a[i];
|
||||
if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE)!=0 ){
|
||||
assert( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 );
|
||||
sqlite3DbFree(db, pLevel->u.in.aInLoop);
|
||||
}
|
||||
}
|
||||
sqlite3WhereClauseClear(&pWInfo->sWC);
|
||||
while( pWInfo->pLoops ){
|
||||
WhereLoop *p = pWInfo->pLoops;
|
||||
@@ -2232,6 +2248,11 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
whereLoopDelete(db, p);
|
||||
}
|
||||
assert( pWInfo->pExprMods==0 );
|
||||
while( pWInfo->pMemToFree ){
|
||||
WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
|
||||
sqlite3DbFreeNN(db, pWInfo->pMemToFree);
|
||||
pWInfo->pMemToFree = pNext;
|
||||
}
|
||||
sqlite3DbFreeNN(db, pWInfo);
|
||||
}
|
||||
|
||||
@@ -2600,10 +2621,11 @@ static void whereLoopOutputAdjust(
|
||||
**
|
||||
** 2022-03-24: Self-culling only applies if either the extra terms
|
||||
** are straight comparison operators that are non-true with NULL
|
||||
** operand, or if the loop is not a LEFT JOIN.
|
||||
** operand, or if the loop is not an OUTER JOIN.
|
||||
*/
|
||||
if( (pTerm->eOperator & 0x3f)!=0
|
||||
|| (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0
|
||||
|| (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype
|
||||
& (JT_LEFT|JT_LTORJ))==0
|
||||
){
|
||||
pLoop->wsFlags |= WHERE_SELFCULL;
|
||||
}
|
||||
@@ -2810,9 +2832,10 @@ static int whereLoopAddBtreeIndex(
|
||||
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
|
||||
|
||||
/* tag-20191211-001: Do not allow constraints from the WHERE clause to
|
||||
** be used by the right table of a LEFT JOIN. Only constraints in the
|
||||
** be used by the right table of a LEFT JOIN nor by the left table of a
|
||||
** RIGHT JOIN. Only constraints in the
|
||||
** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */
|
||||
if( (pSrc->fg.jointype & JT_LEFT)!=0
|
||||
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
){
|
||||
continue;
|
||||
@@ -3182,7 +3205,7 @@ static int whereUsablePartialIndex(
|
||||
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
||||
Expr *pExpr;
|
||||
pExpr = pTerm->pExpr;
|
||||
if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iRightJoinTable==iTab)
|
||||
if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iJoin==iTab)
|
||||
&& (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
|
||||
&& sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
|
||||
&& (pTerm->wtFlags & TERM_VNULL)==0
|
||||
@@ -3292,13 +3315,14 @@ static int whereLoopAddBtree(
|
||||
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
||||
/* Automatic indexes */
|
||||
if( !pBuilder->pOrSet /* Not part of an OR optimization */
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
||||
&& (pWInfo->wctrlFlags & (WHERE_RIGHT_JOIN|WHERE_OR_SUBCLAUSE))==0
|
||||
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
|
||||
&& !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
|
||||
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
|
||||
&& HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
|
||||
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
|
||||
&& !pSrc->fg.isRecursive /* Not a recursive common table expression. */
|
||||
&& (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */
|
||||
){
|
||||
/* Generate auto-index WhereLoops */
|
||||
LogEst rLogSize; /* Logarithm of the number of rows in the table */
|
||||
@@ -3788,15 +3812,26 @@ int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
|
||||
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
/*
|
||||
** Cause the prepared statement that is associated with a call to
|
||||
** xBestIndex to open write transactions on all attached schemas.
|
||||
** xBestIndex to potentiall use all schemas. If the statement being
|
||||
** prepared is read-only, then just start read transactions on all
|
||||
** schemas. But if this is a write operation, start writes on all
|
||||
** schemas.
|
||||
**
|
||||
** This is used by the (built-in) sqlite_dbpage virtual table.
|
||||
*/
|
||||
void sqlite3VtabWriteAll(sqlite3_index_info *pIdxInfo){
|
||||
void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
|
||||
HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
||||
Parse *pParse = pHidden->pParse;
|
||||
int nDb = pParse->db->nDb;
|
||||
int i;
|
||||
for(i=0; i<nDb; i++) sqlite3BeginWriteOperation(pParse, 0, i);
|
||||
for(i=0; i<nDb; i++){
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
}
|
||||
if( pParse->writeMask ){
|
||||
for(i=0; i<nDb; i++){
|
||||
sqlite3BeginWriteOperation(pParse, 0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3979,6 +4014,9 @@ static int whereLoopAddOr(
|
||||
pItem = pWInfo->pTabList->a + pNew->iTab;
|
||||
iCur = pItem->iCursor;
|
||||
|
||||
/* The multi-index OR optimization does not work for RIGHT and FULL JOIN */
|
||||
if( pItem->fg.jointype & JT_RIGHT ) return SQLITE_OK;
|
||||
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
|
||||
if( (pTerm->eOperator & WO_OR)!=0
|
||||
&& (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
|
||||
@@ -4103,9 +4141,9 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
pNew->iTab = iTab;
|
||||
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
|
||||
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
|
||||
if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){
|
||||
if( (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
|
||||
/* This condition is true when pItem is the FROM clause term on the
|
||||
** right-hand-side of a LEFT or CROSS JOIN. */
|
||||
** right-hand-side of a OUTER or CROSS JOIN. */
|
||||
mPrereq = mPrior;
|
||||
}else{
|
||||
mPrereq = 0;
|
||||
@@ -4114,7 +4152,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
SrcItem *p;
|
||||
for(p=&pItem[1]; p<pEnd; p++){
|
||||
if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){
|
||||
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
|
||||
mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
|
||||
}
|
||||
}
|
||||
@@ -4419,16 +4457,18 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
/* Make sure the sort order is compatible in an ORDER BY clause.
|
||||
** Sort order is irrelevant for a GROUP BY clause. */
|
||||
if( revSet ){
|
||||
if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){
|
||||
if( (rev ^ revIdx)
|
||||
!= (pOrderBy->a[i].fg.sortFlags&KEYINFO_ORDER_DESC)
|
||||
){
|
||||
isMatch = 0;
|
||||
}
|
||||
}else{
|
||||
rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC);
|
||||
rev = revIdx ^ (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC);
|
||||
if( rev ) *pRevMask |= MASKBIT(iLoop);
|
||||
revSet = 1;
|
||||
}
|
||||
}
|
||||
if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
||||
if( isMatch && (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
||||
if( j==pLoop->u.btree.nEq ){
|
||||
pLoop->wsFlags |= WHERE_BIGNULL_SORT;
|
||||
}else{
|
||||
@@ -5177,7 +5217,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
|
||||
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
||||
if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
|| pTerm->pExpr->w.iRightJoinTable!=pItem->iCursor
|
||||
|| pTerm->pExpr->w.iJoin!=pItem->iCursor
|
||||
){
|
||||
break;
|
||||
}
|
||||
@@ -5730,8 +5770,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
/* noop */
|
||||
}else
|
||||
#endif
|
||||
if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
|
||||
if( ((pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)==0)
|
||||
|| (pTabItem->fg.jointype & (JT_LTORJ|JT_RIGHT))!=0
|
||||
){
|
||||
int op = OP_OpenRead;
|
||||
if( pWInfo->eOnePass!=ONEPASS_OFF ){
|
||||
op = OP_OpenWrite;
|
||||
@@ -5833,6 +5875,37 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
}
|
||||
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
|
||||
if( (pTabItem->fg.jointype & JT_RIGHT)!=0
|
||||
&& (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0
|
||||
){
|
||||
WhereRightJoin *pRJ = pLevel->pRJ;
|
||||
pRJ->iMatch = pParse->nTab++;
|
||||
pRJ->regBloom = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
|
||||
pRJ->regReturn = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
|
||||
assert( pTab==pTabItem->pTab );
|
||||
if( HasRowid(pTab) ){
|
||||
KeyInfo *pInfo;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
|
||||
pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0);
|
||||
if( pInfo ){
|
||||
pInfo->aColl[0] = 0;
|
||||
pInfo->aSortFlags[0] = 0;
|
||||
sqlite3VdbeAppendP4(v, pInfo, P4_KEYINFO);
|
||||
}
|
||||
}else{
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
||||
}
|
||||
pLoop->wsFlags &= ~WHERE_IDX_ONLY;
|
||||
/* The nature of RIGHT JOIN processing is such that it messes up
|
||||
** the output order. So omit any ORDER BY/GROUP BY elimination
|
||||
** optimizations. We need to do an actual sort for RIGHT JOIN. */
|
||||
pWInfo->nOBSat = 0;
|
||||
pWInfo->eDistinct = WHERE_DISTINCT_UNORDERED;
|
||||
}
|
||||
}
|
||||
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
||||
if( db->mallocFailed ) goto whereBeginError;
|
||||
@@ -5945,6 +6018,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
for(i=pWInfo->nLevel-1; i>=0; i--){
|
||||
int addr;
|
||||
pLevel = &pWInfo->a[i];
|
||||
if( pLevel->pRJ ){
|
||||
/* Terminate the subroutine that forms the interior of the loop of
|
||||
** the RIGHT JOIN table */
|
||||
WhereRightJoin *pRJ = pLevel->pRJ;
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
pLevel->addrCont = 0;
|
||||
pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
|
||||
VdbeCoverage(v);
|
||||
assert( pParse->withinRJSubrtn>0 );
|
||||
pParse->withinRJSubrtn--;
|
||||
}
|
||||
pLoop = pLevel->pWLoop;
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
||||
@@ -5972,7 +6057,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}
|
||||
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
|
||||
/* The common case: Advance to the next row */
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
||||
sqlite3VdbeChangeP5(v, pLevel->p5);
|
||||
VdbeCoverage(v);
|
||||
@@ -5987,7 +6072,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
||||
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
|
||||
#endif
|
||||
}else{
|
||||
}else if( pLevel->addrCont ){
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
}
|
||||
if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){
|
||||
@@ -6037,6 +6122,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
|
||||
if( pLevel->pRJ ){
|
||||
sqlite3VdbeAddOp3(v, OP_Return, pLevel->pRJ->regReturn, 0, 1);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
if( pLevel->addrSkip ){
|
||||
sqlite3VdbeGoto(v, pLevel->addrSkip);
|
||||
VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName));
|
||||
@@ -6080,11 +6169,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
|
||||
}
|
||||
|
||||
/* The "break" point is here, just past the end of the outer loop.
|
||||
** Set it.
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
|
||||
|
||||
assert( pWInfo->nLevel<=pTabList->nSrc );
|
||||
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
||||
int k, last;
|
||||
@@ -6095,6 +6179,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
assert( pTab!=0 );
|
||||
pLoop = pLevel->pWLoop;
|
||||
|
||||
/* Do RIGHT JOIN processing. Generate code that will output the
|
||||
** unmatched rows of the right operand of the RIGHT JOIN with
|
||||
** all of the columns of the left operand set to NULL.
|
||||
*/
|
||||
if( pLevel->pRJ ){
|
||||
sqlite3WhereRightJoinLoop(pWInfo, i, pLevel);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For a co-routine, change all OP_Column references to the table of
|
||||
** the co-routine into OP_Copy of result contained in a register.
|
||||
** OP_Rowid becomes OP_Null.
|
||||
@@ -6106,29 +6199,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE
|
||||
/* Close all of the cursors that were opened by sqlite3WhereBegin.
|
||||
** Except, do not close cursors that will be reused by the OR optimization
|
||||
** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors
|
||||
** created for the ONEPASS optimization.
|
||||
*/
|
||||
if( (pTab->tabFlags & TF_Ephemeral)==0
|
||||
&& !IsView(pTab)
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
||||
){
|
||||
int ws = pLoop->wsFlags;
|
||||
if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
|
||||
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
||||
}
|
||||
if( (ws & WHERE_INDEXED)!=0
|
||||
&& (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
|
||||
&& pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
|
||||
){
|
||||
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If this scan uses an index, make VDBE code substitutions to read data
|
||||
** from the index instead of from the table where possible. In some cases
|
||||
** this optimization prevents the table from ever being read, which can
|
||||
@@ -6229,6 +6299,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}
|
||||
}
|
||||
|
||||
/* The "break" point is here, just past the end of the outer loop.
|
||||
** Set it.
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
|
||||
|
||||
/* Final cleanup
|
||||
*/
|
||||
if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
|
||||
|
||||
@@ -32,6 +32,28 @@ typedef struct WhereLoopBuilder WhereLoopBuilder;
|
||||
typedef struct WhereScan WhereScan;
|
||||
typedef struct WhereOrCost WhereOrCost;
|
||||
typedef struct WhereOrSet WhereOrSet;
|
||||
typedef struct WhereMemBlock WhereMemBlock;
|
||||
typedef struct WhereRightJoin WhereRightJoin;
|
||||
|
||||
/*
|
||||
** This object is a header on a block of allocated memory that will be
|
||||
** automatically freed when its WInfo oject is destructed.
|
||||
*/
|
||||
struct WhereMemBlock {
|
||||
WhereMemBlock *pNext; /* Next block in the chain */
|
||||
u8 sz; /* Bytes of space */
|
||||
};
|
||||
|
||||
/*
|
||||
** Extra information attached to a WhereLevel that is a RIGHT JOIN.
|
||||
*/
|
||||
struct WhereRightJoin {
|
||||
int iMatch; /* Cursor used to determine prior matched rows */
|
||||
int regBloom; /* Bloom filter for iRJMatch */
|
||||
int regReturn; /* Return register for the interior subroutine */
|
||||
int addrSubrtn; /* Starting address for the interior subroutine */
|
||||
int endSubrtn; /* The last opcode in the interior subroutine */
|
||||
};
|
||||
|
||||
/*
|
||||
** This object contains information needed to implement a single nested
|
||||
@@ -65,6 +87,7 @@ struct WhereLevel {
|
||||
int addrLikeRep; /* LIKE range processing address */
|
||||
#endif
|
||||
int regFilter; /* Bloom filter */
|
||||
WhereRightJoin *pRJ; /* Extra information for RIGHT JOIN */
|
||||
u8 iFrom; /* Which entry in the FROM clause */
|
||||
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to end the loop */
|
||||
@@ -478,6 +501,7 @@ struct WhereInfo {
|
||||
int iEndWhere; /* End of the WHERE clause itself */
|
||||
WhereLoop *pLoops; /* List of all WhereLoop objects */
|
||||
WhereExprMod *pExprMods; /* Expression modifications */
|
||||
WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
|
||||
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
||||
WhereClause sWC; /* Decomposition of the WHERE clause */
|
||||
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
||||
@@ -503,6 +527,8 @@ WhereTerm *sqlite3WhereFindTerm(
|
||||
u32 op, /* Mask of WO_xx values describing operator */
|
||||
Index *pIdx /* Must be compatible with this index, if not NULL */
|
||||
);
|
||||
void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte);
|
||||
void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte);
|
||||
|
||||
/* wherecode.c: */
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
@@ -539,6 +565,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
WhereLevel *pLevel, /* The current level pointer */
|
||||
Bitmask notReady /* Which tables are currently available */
|
||||
);
|
||||
SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
||||
WhereInfo *pWInfo,
|
||||
int iLevel,
|
||||
WhereLevel *pLevel
|
||||
);
|
||||
|
||||
/* whereexpr.c: */
|
||||
void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
|
||||
|
||||
+180
-20
@@ -204,6 +204,9 @@ int sqlite3WhereExplainOneScan(
|
||||
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
|
||||
}
|
||||
#endif
|
||||
if( pItem->fg.jointype & JT_LEFT ){
|
||||
sqlite3_str_appendf(&str, " LEFT-JOIN");
|
||||
}
|
||||
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
|
||||
if( pLoop->nOut>=10 ){
|
||||
sqlite3_str_appendf(&str, " (~%llu rows)",
|
||||
@@ -608,16 +611,22 @@ static int codeEqualityTerm(
|
||||
if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
|
||||
}else{
|
||||
sqlite3 *db = pParse->db;
|
||||
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
||||
|
||||
if( !db->mallocFailed ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||
sqlite3 *db = pParse->db;
|
||||
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
||||
if( !db->mallocFailed ){
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
|
||||
pExpr->iTable = iTab;
|
||||
}
|
||||
sqlite3ExprDelete(db, pX);
|
||||
}else{
|
||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
||||
pTerm->pExpr->iTable = iTab;
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP|IN_INDEX_REUSE_CUR, 0, aiMap,&iTab);
|
||||
iTab = pExpr->iTable;
|
||||
}
|
||||
sqlite3ExprDelete(db, pX);
|
||||
pX = pTerm->pExpr;
|
||||
pX = pExpr;
|
||||
}
|
||||
|
||||
if( eType==IN_INDEX_INDEX_DESC ){
|
||||
@@ -640,8 +649,9 @@ static int codeEqualityTerm(
|
||||
i = pLevel->u.in.nIn;
|
||||
pLevel->u.in.nIn += nEq;
|
||||
pLevel->u.in.aInLoop =
|
||||
sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
|
||||
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
|
||||
sqlite3WhereRealloc(pTerm->pWC->pWInfo,
|
||||
pLevel->u.in.aInLoop,
|
||||
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
|
||||
pIn = pLevel->u.in.aInLoop;
|
||||
if( pIn ){
|
||||
int iMap = 0; /* Index in aiMap[] */
|
||||
@@ -1063,7 +1073,7 @@ static void codeCursorHint(
|
||||
if( pTabItem->fg.jointype & JT_LEFT ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
|| pExpr->w.iRightJoinTable!=pTabItem->iCursor
|
||||
|| pExpr->w.iJoin!=pTabItem->iCursor
|
||||
){
|
||||
sWalker.eCode = 0;
|
||||
sWalker.xExprCallback = codeCursorHintIsOrFunction;
|
||||
@@ -1149,7 +1159,7 @@ static void codeDeferredSeek(
|
||||
|
||||
pWInfo->bDeferredSeek = 1;
|
||||
sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
|
||||
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|
||||
if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
|
||||
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
|
||||
){
|
||||
int i;
|
||||
@@ -1243,12 +1253,12 @@ static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
|
||||
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
||||
IdxExprTrans *pX = p->u.pIdxTrans;
|
||||
if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
preserveExpr(pX, pExpr);
|
||||
pExpr->affExpr = sqlite3ExprAffinity(pExpr);
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->iTable = pX->iIdxCur;
|
||||
pExpr->iColumn = pX->iIdxCol;
|
||||
testcase( ExprHasProperty(pExpr, EP_Skip) );
|
||||
testcase( ExprHasProperty(pExpr, EP_Unlikely) );
|
||||
ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn);
|
||||
pExpr->y.pTab = 0;
|
||||
@@ -1402,6 +1412,8 @@ static SQLITE_NOINLINE void filterPullDown(
|
||||
/* ,--- Because sqlite3ConstructBloomFilter() has will not have set
|
||||
** vvvvv--' pLevel->regFilter if this were true. */
|
||||
if( NEVER(pLoop->prereq & notReady) ) continue;
|
||||
assert( pLevel->addrBrk==0 );
|
||||
pLevel->addrBrk = addrNxt;
|
||||
if( pLoop->wsFlags & WHERE_IPK ){
|
||||
WhereTerm *pTerm = pLoop->aLTerm[0];
|
||||
int regRowid;
|
||||
@@ -1428,6 +1440,7 @@ static SQLITE_NOINLINE void filterPullDown(
|
||||
VdbeCoverage(pParse->pVdbe);
|
||||
}
|
||||
pLevel->regFilter = 0;
|
||||
pLevel->addrBrk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1501,7 +1514,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** initialize a memory cell that records if this table matches any
|
||||
** row of the left table of the join.
|
||||
*/
|
||||
assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|
||||
assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
|
||||
|| pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0
|
||||
);
|
||||
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
|
||||
@@ -1512,7 +1525,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
/* Compute a safe address to jump to if we discover that the table for
|
||||
** this loop is empty and can never contribute content. */
|
||||
for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
|
||||
for(j=iLevel; j>0; j--){
|
||||
if( pWInfo->a[j].iLeftJoin ) break;
|
||||
if( pWInfo->a[j].pRJ ) break;
|
||||
}
|
||||
addrHalt = pWInfo->a[j].addrBrk;
|
||||
|
||||
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||
@@ -2139,7 +2155,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
/* Seek the table cursor, if required */
|
||||
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
|
||||
&& (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0;
|
||||
if( omitTable ){
|
||||
/* pIdx is a covering index. No need to access the main table. */
|
||||
}else if( HasRowid(pIdx->pTable) ){
|
||||
@@ -2173,7 +2189,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** move forward to the next index.
|
||||
** https://sqlite.org/src/info/4e8e4857d32d401f
|
||||
*/
|
||||
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
|
||||
if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ){
|
||||
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
|
||||
}
|
||||
|
||||
@@ -2192,7 +2208,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
/* The following assert() is not a requirement, merely an observation:
|
||||
** The OR-optimization doesn't work for the right hand table of
|
||||
** a LEFT JOIN: */
|
||||
assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 );
|
||||
assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 );
|
||||
}
|
||||
|
||||
/* Record the instruction used to terminate the loop. */
|
||||
@@ -2604,7 +2620,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}
|
||||
pE = pTerm->pExpr;
|
||||
assert( pE!=0 );
|
||||
if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){
|
||||
if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ))
|
||||
&& !ExprHasProperty(pE,EP_FromJoin)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2666,7 +2684,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
|
||||
if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
|
||||
if( pTerm->leftCursor!=iCur ) continue;
|
||||
if( pTabItem->fg.jointype & JT_LEFT ) continue;
|
||||
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
|
||||
pE = pTerm->pExpr;
|
||||
#ifdef WHERETRACE_ENABLED /* 0x800 */
|
||||
if( sqlite3WhereTrace & 0x800 ){
|
||||
@@ -2697,6 +2715,47 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
pAlt->wtFlags |= TERM_CODED;
|
||||
}
|
||||
|
||||
/* For a RIGHT OUTER JOIN, record the fact that the current row has
|
||||
** been matched at least once.
|
||||
*/
|
||||
if( pLevel->pRJ ){
|
||||
Table *pTab;
|
||||
int nPk;
|
||||
int r;
|
||||
int jmp1 = 0;
|
||||
WhereRightJoin *pRJ = pLevel->pRJ;
|
||||
|
||||
/* pTab is the right-hand table of the RIGHT JOIN. Generate code that
|
||||
** will record that the current row of that table has been matched at
|
||||
** least once. This is accomplished by storing the PK for the row in
|
||||
** both the iMatch index and the regBloom Bloom filter.
|
||||
*/
|
||||
pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
|
||||
if( HasRowid(pTab) ){
|
||||
r = sqlite3GetTempRange(pParse, 2);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
|
||||
nPk = 1;
|
||||
}else{
|
||||
int iPk;
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
nPk = pPk->nKeyCol;
|
||||
r = sqlite3GetTempRange(pParse, nPk+1);
|
||||
for(iPk=0; iPk<nPk; iPk++){
|
||||
int iCol = pPk->aiColumn[iPk];
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk);
|
||||
}
|
||||
}
|
||||
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk);
|
||||
VdbeCoverage(v);
|
||||
VdbeComment((v, "match against %s", pTab->zName));
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk);
|
||||
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3VdbeJumpHere(v, jmp1);
|
||||
sqlite3ReleaseTempRange(pParse, r, nPk+1);
|
||||
}
|
||||
|
||||
/* For a LEFT OUTER JOIN, generate code that will record the fact that
|
||||
** at least one row of the right table has matched the left table.
|
||||
*/
|
||||
@@ -2712,12 +2771,27 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
assert( pWInfo->untestedTerms );
|
||||
continue;
|
||||
}
|
||||
if( pTabItem->fg.jointype & JT_LTORJ ) continue;
|
||||
assert( pTerm->pExpr );
|
||||
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
}
|
||||
|
||||
if( pLevel->pRJ ){
|
||||
/* Create a subroutine used to process all interior loops and code
|
||||
** of the RIGHT JOIN. During normal operation, the subroutine will
|
||||
** be in-line with the rest of the code. But at the end, a separate
|
||||
** loop will run that invokes this subroutine for unmatched rows
|
||||
** of pTab, with all tables to left begin set to NULL.
|
||||
*/
|
||||
WhereRightJoin *pRJ = pLevel->pRJ;
|
||||
sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn);
|
||||
pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v);
|
||||
assert( pParse->withinRJSubrtn < 255 );
|
||||
pParse->withinRJSubrtn++;
|
||||
}
|
||||
|
||||
#if WHERETRACE_ENABLED /* 0x20800 */
|
||||
if( sqlite3WhereTrace & 0x20000 ){
|
||||
sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
|
||||
@@ -2731,3 +2805,89 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
#endif
|
||||
return pLevel->notReady;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate the code for the loop that finds all non-matched terms
|
||||
** for a RIGHT JOIN.
|
||||
*/
|
||||
SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
||||
WhereInfo *pWInfo,
|
||||
int iLevel,
|
||||
WhereLevel *pLevel
|
||||
){
|
||||
Parse *pParse = pWInfo->pParse;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
WhereRightJoin *pRJ = pLevel->pRJ;
|
||||
Expr *pSubWhere = 0;
|
||||
WhereClause *pWC = &pWInfo->sWC;
|
||||
WhereInfo *pSubWInfo;
|
||||
WhereLoop *pLoop = pLevel->pWLoop;
|
||||
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
||||
SrcList sFrom;
|
||||
Bitmask mAll = 0;
|
||||
int k;
|
||||
|
||||
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
|
||||
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
|
||||
pRJ->regReturn);
|
||||
for(k=0; k<iLevel; k++){
|
||||
int iIdxCur;
|
||||
mAll |= pWInfo->a[k].pWLoop->maskSelf;
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
|
||||
iIdxCur = pWInfo->a[k].iIdxCur;
|
||||
if( iIdxCur ){
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
|
||||
}
|
||||
}
|
||||
if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
|
||||
mAll |= pLoop->maskSelf;
|
||||
for(k=0; k<pWC->nTerm; k++){
|
||||
WhereTerm *pTerm = &pWC->a[k];
|
||||
if( pTerm->wtFlags & TERM_VIRTUAL ) break;
|
||||
if( pTerm->prereqAll & ~mAll ) continue;
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue;
|
||||
pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
|
||||
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
|
||||
}
|
||||
}
|
||||
sFrom.nSrc = 1;
|
||||
sFrom.nAlloc = 1;
|
||||
memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
|
||||
sFrom.a[0].fg.jointype = 0;
|
||||
assert( pParse->withinRJSubrtn < 100 );
|
||||
pParse->withinRJSubrtn++;
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
|
||||
WHERE_RIGHT_JOIN, 0);
|
||||
if( pSubWInfo ){
|
||||
int iCur = pLevel->iTabCur;
|
||||
int r = ++pParse->nMem;
|
||||
int nPk;
|
||||
int jmp;
|
||||
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
|
||||
Table *pTab = pTabItem->pTab;
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
|
||||
nPk = 1;
|
||||
}else{
|
||||
int iPk;
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
nPk = pPk->nKeyCol;
|
||||
pParse->nMem += nPk - 1;
|
||||
for(iPk=0; iPk<nPk; iPk++){
|
||||
int iCol = pPk->aiColumn[iPk];
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
|
||||
}
|
||||
}
|
||||
jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, jmp);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn);
|
||||
sqlite3WhereEnd(pSubWInfo);
|
||||
}
|
||||
sqlite3ExprDelete(pParse->db, pSubWhere);
|
||||
ExplainQueryPlanPop(pParse);
|
||||
assert( pParse->withinRJSubrtn>0 );
|
||||
pParse->withinRJSubrtn--;
|
||||
}
|
||||
|
||||
+12
-14
@@ -64,7 +64,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
||||
if( pWC->nTerm>=pWC->nSlot ){
|
||||
WhereTerm *pOld = pWC->a;
|
||||
sqlite3 *db = pWC->pWInfo->pParse->db;
|
||||
pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
|
||||
pWC->a = sqlite3WhereMalloc(pWC->pWInfo, sizeof(pWC->a[0])*pWC->nSlot*2 );
|
||||
if( pWC->a==0 ){
|
||||
if( wtFlags & TERM_DYNAMIC ){
|
||||
sqlite3ExprDelete(db, p);
|
||||
@@ -73,10 +73,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
||||
return 0;
|
||||
}
|
||||
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
|
||||
if( pOld!=pWC->aStatic ){
|
||||
sqlite3DbFree(db, pOld);
|
||||
}
|
||||
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
|
||||
pWC->nSlot = pWC->nSlot*2;
|
||||
}
|
||||
pTerm = &pWC->a[idx = pWC->nTerm++];
|
||||
if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm;
|
||||
@@ -466,7 +463,7 @@ static int isAuxiliaryVtabOperator(
|
||||
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
||||
if( pDerived ){
|
||||
pDerived->flags |= pBase->flags & EP_FromJoin;
|
||||
pDerived->w.iRightJoinTable = pBase->w.iRightJoinTable;
|
||||
pDerived->w.iJoin = pBase->w.iJoin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1113,7 +1110,7 @@ static void exprAnalyze(
|
||||
#endif
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iRightJoinTable);
|
||||
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin);
|
||||
prereqAll |= x;
|
||||
extraRight = x-1; /* ON clause terms may not be used with an index
|
||||
** on left table of a LEFT JOIN. Ticket #3015 */
|
||||
@@ -1464,7 +1461,7 @@ static void exprAnalyze(
|
||||
0, sqlite3ExprDup(db, pRight, 0));
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
|
||||
ExprSetProperty(pNewExpr, EP_FromJoin);
|
||||
pNewExpr->w.iRightJoinTable = pExpr->w.iRightJoinTable;
|
||||
pNewExpr->w.iJoin = pExpr->w.iJoin;
|
||||
}
|
||||
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew==0 );
|
||||
@@ -1619,7 +1616,7 @@ void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
||||
Expr *pExpr = pOrderBy->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLUMN ) return;
|
||||
if( pExpr->iTable!=iCsr ) return;
|
||||
if( pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_BIGNULL ) return;
|
||||
if( pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1686,9 +1683,6 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
|
||||
a++;
|
||||
}
|
||||
}
|
||||
if( pWC->a!=pWC->aStatic ){
|
||||
sqlite3DbFree(db, pWC->a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1815,6 +1809,7 @@ void sqlite3WhereTabFuncArgs(
|
||||
if( pArgs==0 ) return;
|
||||
for(j=k=0; j<pArgs->nExpr; j++){
|
||||
Expr *pRhs;
|
||||
u32 joinType;
|
||||
while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
|
||||
if( k>=pTab->nCol ){
|
||||
sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
|
||||
@@ -1831,9 +1826,12 @@ void sqlite3WhereTabFuncArgs(
|
||||
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
|
||||
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
|
||||
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
|
||||
if( pItem->fg.jointype & JT_LEFT ){
|
||||
sqlite3SetJoinExpr(pTerm, pItem->iCursor);
|
||||
if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
|
||||
joinType = EP_FromJoin;
|
||||
}else{
|
||||
joinType = EP_InnerJoin;
|
||||
}
|
||||
sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
|
||||
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -916,7 +916,7 @@ static ExprList *exprListAppendList(
|
||||
}
|
||||
}
|
||||
pList = sqlite3ExprListAppend(pParse, pList, pDup);
|
||||
if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
|
||||
if( pList ) pList->a[nInit+i].fg.sortFlags = pAppend->a[i].fg.sortFlags;
|
||||
}
|
||||
}
|
||||
return pList;
|
||||
@@ -1729,7 +1729,7 @@ static void windowAggStep(
|
||||
|
||||
for(iEnd=sqlite3VdbeCurrentAddr(v); iOp<iEnd; iOp++){
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, iOp);
|
||||
if( pOp->opcode==OP_Column && pOp->p1==pWin->iEphCsr ){
|
||||
if( pOp->opcode==OP_Column && pOp->p1==pMWin->iEphCsr ){
|
||||
pOp->p1 = csr;
|
||||
}
|
||||
}
|
||||
@@ -2117,7 +2117,7 @@ static void windowCodeRangeTest(
|
||||
|
||||
assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
|
||||
assert( pOrderBy && pOrderBy->nExpr==1 );
|
||||
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){
|
||||
if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_DESC ){
|
||||
switch( op ){
|
||||
case OP_Ge: op = OP_Le; break;
|
||||
case OP_Gt: op = OP_Lt; break;
|
||||
@@ -2150,7 +2150,7 @@ static void windowCodeRangeTest(
|
||||
** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
||||
** not taken, control jumps over the comparison operator coded below this
|
||||
** block. */
|
||||
if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){
|
||||
if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_BIGNULL ){
|
||||
/* This block runs if reg1 contains a NULL. */
|
||||
int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
|
||||
switch( op ){
|
||||
|
||||
@@ -30,11 +30,24 @@ do_execsql_test affinity3-100 {
|
||||
FROM customer c
|
||||
LEFT JOIN apr i ON i.id=c.id;
|
||||
|
||||
CREATE VIEW v1rj AS
|
||||
SELECT c.id, i.apr
|
||||
FROM apr i
|
||||
RIGHT JOIN customer c ON i.id=c.id;
|
||||
|
||||
CREATE VIEW v2 AS
|
||||
SELECT c.id, v1.apr
|
||||
FROM customer c
|
||||
LEFT JOIN v1 ON v1.id=c.id;
|
||||
|
||||
CREATE VIEW v2rj AS
|
||||
SELECT c.id, v1.apr
|
||||
FROM v1 RIGHT JOIN customer c ON v1.id=c.id;
|
||||
|
||||
CREATE VIEW v2rjrj AS
|
||||
SELECT c.id, v1rj.apr
|
||||
FROM v1rj RIGHT JOIN customer c ON v1rj.id=c.id;
|
||||
|
||||
INSERT INTO customer (id) VALUES (1);
|
||||
INSERT INTO apr (id, apr) VALUES (1, 12);
|
||||
INSERT INTO customer (id) VALUES (2);
|
||||
@@ -44,16 +57,35 @@ do_execsql_test affinity3-110 {
|
||||
PRAGMA automatic_index=ON;
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-111 {
|
||||
PRAGMA automatic_index=ON;
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1rj;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-120 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-121 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rj;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-122 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rjrj;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-130 {
|
||||
PRAGMA automatic_index=OFF;
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-131 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v1rj;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-140 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-141 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rj;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
do_execsql_test affinity3-142 {
|
||||
SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rjrj;
|
||||
} {1 0.12 real 2 0.1201 real}
|
||||
|
||||
# Ticket https://www.sqlite.org/src/info/7ffd1ca1d2ad4ecf (2017-01-16)
|
||||
# Incorrect affinity when using automatic indexes
|
||||
|
||||
@@ -137,6 +137,17 @@ do_test aggnested-3.1 {
|
||||
GROUP BY curr.id1);
|
||||
}
|
||||
} {1 1}
|
||||
do_test aggnested-3.1-rj {
|
||||
db eval {
|
||||
SELECT
|
||||
(SELECT sum(value2==xyz) FROM t2)
|
||||
FROM
|
||||
(SELECT curr.value1 as xyz
|
||||
FROM t1 AS other RIGHT JOIN t1 AS curr
|
||||
GROUP BY curr.id1);
|
||||
}
|
||||
} {1 1}
|
||||
|
||||
do_test aggnested-3.2 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
|
||||
@@ -686,4 +686,54 @@ do_execsql_test 28.2 {
|
||||
UPDATE "t2" SET (c,d)=(a,b);
|
||||
END}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 29.1 {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE TRIGGER Trigger1 DELETE ON t1
|
||||
BEGIN
|
||||
SELECT t1.*, t1.x FROM t1 ORDER BY t1.x;
|
||||
END;
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 29.2 {
|
||||
ALTER TABLE t1 RENAME x TO z;
|
||||
}
|
||||
|
||||
do_execsql_test 29.3 {
|
||||
ALTER TABLE t1 RENAME TO t2;
|
||||
}
|
||||
|
||||
do_execsql_test 29.4 {
|
||||
CREATE TRIGGER tr2 AFTER DELETE ON t2 BEGIN
|
||||
SELECT z, y FROM (
|
||||
SELECT t2.* FROM t2
|
||||
);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 29.5 {
|
||||
DELETE FROM t2
|
||||
}
|
||||
|
||||
do_execsql_test 29.6 {
|
||||
ALTER TABLE t2 RENAME TO t3;
|
||||
}
|
||||
|
||||
do_execsql_test 29.7 {
|
||||
SELECT sql FROM sqlite_schema WHERE type='trigger'
|
||||
} {
|
||||
{CREATE TRIGGER Trigger1 DELETE ON "t3"
|
||||
BEGIN
|
||||
SELECT "t3".*, "t3".z FROM "t3" ORDER BY "t3".z;
|
||||
END}
|
||||
{CREATE TRIGGER tr2 AFTER DELETE ON "t3" BEGIN
|
||||
SELECT z, y FROM (
|
||||
SELECT "t3".* FROM "t3"
|
||||
);
|
||||
END}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+19
-3
@@ -283,7 +283,7 @@ do_eqp_test autoindex1-600a {
|
||||
| `--CORRELATED SCALAR SUBQUERY xxxxxx
|
||||
| `--SEARCH later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)
|
||||
|--SCAN x USING INDEX sheep_reg_flock_index
|
||||
`--SEARCH y USING AUTOMATIC COVERING INDEX (sheep_no=?)
|
||||
`--SEARCH y USING AUTOMATIC COVERING INDEX (sheep_no=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
|
||||
@@ -542,7 +542,23 @@ do_execsql_test autoindex1-1020 {
|
||||
SELECT count(*) FROM t11 LEFT JOIN t12 WHERE t12.y IS t11.w;
|
||||
} 0
|
||||
|
||||
|
||||
|
||||
# 2022-04-25
|
||||
# https://sqlite.org/forum/forumpost/0d3200f4f3bcd3a3
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test autoindex-1100 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
CREATE TABLE t2(c INT, d INT);
|
||||
CREATE TABLE t3(e TEXT, f TEXT);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
INSERT INTO t3 VALUES('abc', 'def');
|
||||
} {}
|
||||
do_execsql_test autoindex-1110 {
|
||||
SELECT * FROM t1, t2 LEFT JOIN t3 ON (t2.d=1) WHERE t2.c = +t1.a;
|
||||
} {1 1 1 2 {} {}}
|
||||
do_execsql_test autoindex-1120 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (t2.c=+t1.a) LEFT JOIN t3 ON (t2.d IS NULL);
|
||||
} {1 1 1 2 {} {}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -32,12 +32,21 @@ do_execsql_test autoindex4-1.1 {
|
||||
do_execsql_test autoindex4-1.2 {
|
||||
SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555;
|
||||
} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |}
|
||||
do_execsql_test autoindex4-1.2-rj {
|
||||
SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 ON a=234 AND x=555;
|
||||
} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |}
|
||||
do_execsql_test autoindex4-1.3 {
|
||||
SELECT *, '|' FROM t1 LEFT JOIN t2 ON x=555 WHERE a=234;
|
||||
} {234 def {} {} | 234 ghi {} {} |}
|
||||
do_execsql_test autoindex4-1.3-rj {
|
||||
SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 ON x=555 WHERE a=234;
|
||||
} {234 def {} {} | 234 ghi {} {} |}
|
||||
do_execsql_test autoindex4-1.4 {
|
||||
SELECT *, '|' FROM t1 LEFT JOIN t2 WHERE a=234 AND x=555;
|
||||
} {}
|
||||
do_execsql_test autoindex4-1.4-rj {
|
||||
SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 WHERE a=234 AND x=555;
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test autoindex4-2.0 {
|
||||
@@ -69,6 +78,14 @@ do_execsql_test autoindex4-3.0 {
|
||||
ORDER BY Items.ItemName;
|
||||
} {Item1 Item2}
|
||||
do_execsql_test autoindex4-3.1 {
|
||||
SELECT Items.ItemName
|
||||
FROM A
|
||||
RIGHT JOIN Items ON (A.Name = Items.ItemName and Items.ItemName = 'dummy')
|
||||
LEFT JOIN B ON (B.Name = Items.ItemName)
|
||||
WHERE Items.Name = 'Parent'
|
||||
ORDER BY Items.ItemName;
|
||||
} {Item1 Item2}
|
||||
do_execsql_test autoindex4-3.10 {
|
||||
CREATE INDEX Items_x1 ON Items(ItemName,Name) WHERE ItemName = 'dummy';
|
||||
|
||||
SELECT Items.ItemName
|
||||
@@ -78,6 +95,14 @@ do_execsql_test autoindex4-3.1 {
|
||||
WHERE Items.Name = 'Parent'
|
||||
ORDER BY Items.ItemName;
|
||||
} {Item1 Item2}
|
||||
do_execsql_test autoindex4-3.11 {
|
||||
SELECT Items.ItemName
|
||||
FROM A
|
||||
RIGHT JOIN Items ON (A.Name = Items.ItemName and Items.ItemName = 'dummy')
|
||||
LEFT JOIN B ON (B.Name = Items.ItemName)
|
||||
WHERE Items.Name = 'Parent'
|
||||
ORDER BY Items.ItemName;
|
||||
} {Item1 Item2}
|
||||
|
||||
# 2021-11-30 - Enhancement to help the automatic index mechanism to
|
||||
# create a partial index more often.
|
||||
|
||||
@@ -148,6 +148,9 @@ do_execsql_test btree01-2.1 {
|
||||
INSERT INTO t2(y) VALUES(198),(187),(100);
|
||||
SELECT y, c FROM t2 LEFT JOIN t1 ON y=a ORDER BY x;
|
||||
} {198 99 187 {} 100 50}
|
||||
do_execsql_test btree01-2.2 {
|
||||
SELECT y, c FROM t1 RIGHT JOIN t2 ON y=a ORDER BY x;
|
||||
} {198 99 187 {} 100 50}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+21
-3
@@ -684,16 +684,34 @@ do_test collate2-5.3 {
|
||||
SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1;
|
||||
}
|
||||
} {aa}
|
||||
do_test collate2-5.4 {
|
||||
do_test collate2-5.4.1 {
|
||||
execsql {
|
||||
SELECT collate2t2.b FROM collate2t1 LEFT OUTER JOIN collate2t2 USING (b) order by collate2t1.oid;
|
||||
SELECT collate2t2.b FROM collate2t1 LEFT JOIN collate2t2 USING (b) order by collate2t1.oid;
|
||||
}
|
||||
} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}}
|
||||
do_test collate2-5.5 {
|
||||
do_test collate2-5.4.2 {
|
||||
execsql {
|
||||
SELECT collate2t2.b FROM collate2t2 RIGHT JOIN collate2t1 ON collate2t1.b=collate2t2.b
|
||||
ORDER BY collate2t1.oid;
|
||||
}
|
||||
} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}}
|
||||
do_test collate2-5.4.3 {
|
||||
execsql {
|
||||
SELECT collate2t2.b FROM collate2t1 LEFT JOIN collate2t2 ON collate2t2.b=collate2t1.b
|
||||
ORDER BY collate2t1.oid;
|
||||
}
|
||||
} {{} aa {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}}
|
||||
do_test collate2-5.5.1 {
|
||||
execsql {
|
||||
SELECT collate2t1.b, collate2t2.b FROM collate2t2 LEFT OUTER JOIN collate2t1 USING (b);
|
||||
}
|
||||
} {aa aa}
|
||||
do_test collate2-5.5.2 {
|
||||
execsql {
|
||||
SELECT collate2t1.b, collate2t2.b
|
||||
FROM collate2t1 RIGHT JOIN collate2t2 ON collate2t2.b=collate2t1.b
|
||||
}
|
||||
} {aa aa}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(x);
|
||||
|
||||
@@ -1429,4 +1429,63 @@ do_catchsql_test 18.1 {
|
||||
} {1 {JSON cannot hold BLOB values}}
|
||||
} ;# ifcapable json1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 19.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 20480 pagesize 4096 filename crash-f022eb0ce64d27.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 0f f8 00 04 0e d2 00 0f 08 0f d3 ................
|
||||
| 112: 0f ae 0e d2 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3792: 00 00 34 04 06 17 0f 11 01 57 69 6e 64 65 78 61 ..4......Windexa
|
||||
| 3808: 74 31 05 43 52 45 41 54 45 20 55 4e 49 51 55 45 t1.CREATE UNIQUE
|
||||
| 3824: 20 49 4e 44 45 58 20 61 20 4f 4e 20 74 31 28 61 INDEX a ON t1(a
|
||||
| 3840: 2c 20 30 20 7c 20 61 29 81 23 01 07 17 11 11 01 , 0 | a).#......
|
||||
| 3856: 82 31 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .1tablet1t1.CREA
|
||||
| 3872: 54 45 20 54 41 42 4c 45 20 74 31 28 0a 20 20 20 TE TABLE t1(.
|
||||
| 3888: 20 67 63 62 20 41 53 20 28 62 2a 31 29 2c 0a 20 gcb AS (b*1),.
|
||||
| 3904: 20 20 20 61 20 49 34 54 45 47 45 52 20 50 52 49 a I4TEGER PRI
|
||||
| 3920: 4d 41 52 59 20 4b 45 59 2c 0a 20 20 20 20 67 63 MARY KEY,. gc
|
||||
| 3936: 63 20 41 53 20 28 74 32 2b 30 29 2c 0a 20 20 20 c AS (t2+0),.
|
||||
| 3952: 20 62 20 55 4e 49 51 55 45 2c 0a 20 20 20 20 67 b UNIQUE,. g
|
||||
| 3968: 63 61 20 41 53 20 28 31 2a 61 2b 30 29 2c 0a 20 ca AS (1*a+0),.
|
||||
| 3984: 20 20 20 74 32 20 55 4e 49 51 55 45 0a 20 20 29 t2 UNIQUE. )
|
||||
| 4000: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 23 03 WITHOUT ROWID#.
|
||||
| 4016: 06 17 37 11 01 00 69 6e 64 65 78 73 71 6c 69 74 ..7...indexsqlit
|
||||
| 4032: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 33 e_autoindex_t1_3
|
||||
| 4048: 74 31 02 23 02 06 17 37 11 01 00 69 6e 64 65 78 t1.#...7...index
|
||||
| 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex
|
||||
| 4080: 5f 74 31 5f 32 74 31 02 00 00 00 08 00 00 00 00 _t1_2t1.........
|
||||
| page 2 offset 4096
|
||||
| 0: 0a 00 00 00 05 0f d8 00 0f f8 0f f8 9f e8 0f e0 ................
|
||||
| 16: 0f d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4048: 00 00 00 00 00 00 00 00 07 04 01 02 00 0f 13 88 ................
|
||||
| 4064: 07 04 01 02 00 0e 0f a0 07 04 01 02 00 0d 0b b8 ................
|
||||
| 4080: 07 04 01 02 00 0c 07 d0 07 04 01 02 00 0b 03 e8 ................
|
||||
| page 5 offset 16384
|
||||
| 0: 0a 00 00 00 05 0f e2 00 0f fa 0f f4 0f ee 0f e8 ................
|
||||
| 16: 0f e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 05 03 01 01 0f 0f 05 03 01 01 0e 0e 05 03 ................
|
||||
| 4080: 01 01 0d 0d 05 03 01 01 0c 0c 05 03 01 01 0b 0b ................
|
||||
| end crash-f022eb0ce64d27.db
|
||||
}]} {}
|
||||
|
||||
do_execsql_test 19.1 {
|
||||
PRAGMA writable_schema=ON;
|
||||
}
|
||||
|
||||
set err "UNIQUE constraint failed: index 'a'"
|
||||
ifcapable oversize_cell_check {
|
||||
set err "database disk image is malformed"
|
||||
}
|
||||
do_catchsql_test 19.2 {
|
||||
UPDATE t1 SET a=1;
|
||||
} [list 1 $err]
|
||||
|
||||
finish_test
|
||||
|
||||
+6
-6
@@ -94,9 +94,9 @@ do_eqp_test 1.7.1 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1)
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE SUBQUERY xxxxxx
|
||||
|--MATERIALIZE (subquery-xxxxxx)
|
||||
| `--SCAN CONSTANT ROW
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
|--SCAN (subquery-xxxxxx)
|
||||
`--SCAN t3
|
||||
}
|
||||
do_eqp_test 1.7.2 {
|
||||
@@ -123,13 +123,13 @@ do_eqp_test 1.8 {
|
||||
SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2)
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE SUBQUERY xxxxxx
|
||||
|--MATERIALIZE (subquery-xxxxxx)
|
||||
| `--COMPOUND QUERY
|
||||
| |--LEFT-MOST SUBQUERY
|
||||
| | `--SCAN CONSTANT ROW
|
||||
| `--UNION USING TEMP B-TREE
|
||||
| `--SCAN CONSTANT ROW
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
|--SCAN (subquery-xxxxxx)
|
||||
`--SCAN t3
|
||||
}
|
||||
do_eqp_test 1.9 {
|
||||
@@ -282,10 +282,10 @@ det 3.2.1 {
|
||||
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE SUBQUERY xxxxxx
|
||||
|--CO-ROUTINE (subquery-xxxxxx)
|
||||
| |--SCAN t1
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
|--SCAN SUBQUERY xxxxxx
|
||||
|--SCAN (subquery-xxxxxx)
|
||||
`--USE TEMP B-TREE FOR ORDER BY
|
||||
}
|
||||
det 3.2.2 {
|
||||
|
||||
@@ -228,4 +228,26 @@ do_execsql_test 5.3 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 6.1 {
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE c1(b);
|
||||
INSERT INTO c1 VALUES(123);
|
||||
}
|
||||
|
||||
do_execsql_test 6.2 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.p1(a INTEGER PRIMARY KEY);
|
||||
CREATE TABLE aux.c1(b REFERENCES p1(a) ON DELETE RESTRICT);
|
||||
|
||||
INSERT INTO aux.p1 VALUES(123);
|
||||
}
|
||||
|
||||
do_execsql_test 6.3 {
|
||||
DELETE FROM aux.p1 WHERE a=123;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ do_eqp_test 4.2 {
|
||||
|--MATERIALIZE rr
|
||||
| `--SCAN ft4 VIRTUAL TABLE INDEX 3:
|
||||
|--SCAN t4
|
||||
`--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?)
|
||||
`--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -320,7 +320,7 @@ do_eqp_test index6-8.1 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t8a
|
||||
`--SEARCH t8b USING INDEX i8c (y=?)
|
||||
`--SEARCH t8b USING INDEX i8c (y=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
do_execsql_test index6-8.2 {
|
||||
|
||||
@@ -487,4 +487,23 @@ ifcapable like_match_blobs {
|
||||
} {2.0}
|
||||
}
|
||||
|
||||
# 2022-04-30 https://sqlite.org/forum/info/7efabf4b03328e57
|
||||
# Assertion fault during a DELETE INDEXED BY.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test indexexpr-1900 {
|
||||
CREATE TABLE t1(x TEXT PRIMARY KEY, y TEXT, z INT);
|
||||
INSERT INTO t1(x,y,z) VALUES('alpha','ALPHA',1),('bravo','charlie',1);
|
||||
CREATE INDEX i1 ON t1(+y COLLATE NOCASE);
|
||||
SELECT * FROM t1;
|
||||
} {alpha ALPHA 1 bravo charlie 1}
|
||||
do_execsql_test indexexpr-1910 {
|
||||
DELETE FROM t1 INDEXED BY i1
|
||||
WHERE x IS +y COLLATE NOCASE IN (SELECT z FROM t1)
|
||||
RETURNING *;
|
||||
} {alpha ALPHA 1}
|
||||
do_execsql_test indexexpr-1920 {
|
||||
SELECT * FROM t1;
|
||||
} {bravo charlie 1}
|
||||
|
||||
finish_test
|
||||
|
||||
+22
-11
@@ -272,11 +272,13 @@ do_test join-2.2 {
|
||||
SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1;
|
||||
}
|
||||
} {1 2 3 {} 2 3 4 1 3 4 5 2}
|
||||
do_test join-2.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
|
||||
}
|
||||
} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
|
||||
|
||||
#do_test join-2.3 {
|
||||
# catchsql {
|
||||
# SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
|
||||
# }
|
||||
#} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
|
||||
|
||||
do_test join-2.4 {
|
||||
execsql {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d
|
||||
@@ -330,32 +332,32 @@ do_test join-3.7 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 INNER OUTER JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: INNER OUTER}}
|
||||
} {1 {unknown join type: INNER OUTER}}
|
||||
do_test join-3.8 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 INNER OUTER CROSS JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: INNER OUTER CROSS}}
|
||||
} {1 {unknown join type: INNER OUTER CROSS}}
|
||||
do_test join-3.9 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 OUTER NATURAL INNER JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: OUTER NATURAL INNER}}
|
||||
} {1 {unknown join type: OUTER NATURAL INNER}}
|
||||
do_test join-3.10 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 LEFT BOGUS JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: LEFT BOGUS}}
|
||||
} {1 {unknown join type: LEFT BOGUS}}
|
||||
do_test join-3.11 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 INNER BOGUS CROSS JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: INNER BOGUS CROSS}}
|
||||
} {1 {unknown join type: INNER BOGUS CROSS}}
|
||||
do_test join-3.12 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 NATURAL AWK SED JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: NATURAL AWK SED}}
|
||||
} {1 {unknown join type: NATURAL AWK SED}}
|
||||
|
||||
do_test join-4.1 {
|
||||
execsql {
|
||||
@@ -1039,5 +1041,14 @@ do_execsql_test join-25.1 {
|
||||
SELECT count(*) FROM v0 LEFT JOIN t0 ON v0.c0;
|
||||
} {1}
|
||||
|
||||
# 2022-04-21 Parser issue detected by dbsqlfuzz
|
||||
#
|
||||
reset_db
|
||||
do_catchsql_test join-26.1 {
|
||||
CREATE TABLE t4(a,b);
|
||||
CREATE TABLE t5(a,c);
|
||||
CREATE TABLE t6(a,d);
|
||||
SELECT * FROM t5 JOIN ((t4 JOIN (t5 JOIN t6)) t7);
|
||||
} {/1 {.*}/}
|
||||
|
||||
finish_test
|
||||
|
||||
+23
-8
@@ -63,6 +63,12 @@ do_test join2-1.6 {
|
||||
t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3
|
||||
}
|
||||
} {1 11 111 1111}
|
||||
do_test join2-1.6-rj {
|
||||
execsql {
|
||||
SELECT * FROM
|
||||
t2 NATURAL RIGHT OUTER JOIN t1 NATURAL JOIN t3
|
||||
}
|
||||
} {11 111 1 1111}
|
||||
ifcapable subquery {
|
||||
do_test join2-1.7 {
|
||||
execsql {
|
||||
@@ -70,6 +76,12 @@ ifcapable subquery {
|
||||
t1 NATURAL LEFT OUTER JOIN (t2 NATURAL JOIN t3)
|
||||
}
|
||||
} {1 11 111 1111 2 22 {} {} 3 33 {} {}}
|
||||
do_test join2-1.7-rj {
|
||||
execsql {
|
||||
SELECT a, b, c, d FROM
|
||||
t2 NATURAL JOIN t3 NATURAL RIGHT JOIN t1
|
||||
}
|
||||
} {1 11 111 1111 2 22 {} {} 3 33 {} {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -88,6 +100,9 @@ do_execsql_test 2.0 {
|
||||
do_catchsql_test 2.1 {
|
||||
SELECT * FROM aa LEFT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1));
|
||||
} {1 {ON clause references tables to its right}}
|
||||
do_catchsql_test 2.1b {
|
||||
SELECT * FROM aa RIGHT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1));
|
||||
} {1 {ON clause references tables to its right}}
|
||||
do_catchsql_test 2.2 {
|
||||
SELECT * FROM aa JOIN cc ON (a=b) JOIN bb ON (b=c);
|
||||
} {0 {one one one}}
|
||||
@@ -114,7 +129,7 @@ do_eqp_test 3.1 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t1
|
||||
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
do_eqp_test 3.2 {
|
||||
@@ -122,7 +137,7 @@ do_eqp_test 3.2 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t1
|
||||
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -162,15 +177,15 @@ do_eqp_test 4.1.5 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN c1
|
||||
|--SEARCH c2 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|--SEARCH c2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
}
|
||||
do_eqp_test 4.1.6 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN c1
|
||||
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
do_execsql_test 4.2.0 {
|
||||
@@ -209,15 +224,15 @@ do_eqp_test 4.2.5 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN c1
|
||||
|--SEARCH c2 USING INDEX sqlite_autoindex_c2_1 (k=?)
|
||||
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?)
|
||||
|--SEARCH c2 USING INDEX sqlite_autoindex_c2_1 (k=?) LEFT-JOIN
|
||||
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) LEFT-JOIN
|
||||
}
|
||||
do_eqp_test 4.2.6 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN c1
|
||||
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?)
|
||||
`--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
# 2017-11-23 (Thanksgiving day)
|
||||
|
||||
+35
-3
@@ -280,9 +280,9 @@ do_eqp_test 7.2 {
|
||||
|--SCAN t1
|
||||
`--MULTI-INDEX OR
|
||||
|--INDEX 1
|
||||
| `--SEARCH t2 USING INDEX t2xy (x=? AND y=?)
|
||||
| `--SEARCH t2 USING INDEX t2xy (x=? AND y=?) LEFT-JOIN
|
||||
`--INDEX 2
|
||||
`--SEARCH t2 USING INDEX t2xy (x=? AND y=?)
|
||||
`--SEARCH t2 USING INDEX t2xy (x=? AND y=?) LEFT-JOIN
|
||||
}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
@@ -303,7 +303,7 @@ do_eqp_test 7.4 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t3
|
||||
`--SEARCH t4 USING INDEX t4xz (x=?)
|
||||
`--SEARCH t4 USING INDEX t4xz (x=?) LEFT-JOIN
|
||||
}
|
||||
do_eqp_test 7.4b {
|
||||
SELECT * FROM t3 CROSS JOIN t4 ON (t4.x = t3.x) WHERE (+t4.y = ? OR t4.z = ?);
|
||||
@@ -393,6 +393,38 @@ do_execsql_test 11.4 {
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d>=300;
|
||||
} {2}
|
||||
|
||||
# 2022-05-03 https://sqlite.org/forum/forumpost/2482b32700384a0f
|
||||
# Bloom-filter pull-down does not handle NOT NULL constraints correctly.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE t1(a INT, b INT, c INT);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||
INSERT INTO t1(a,b,c) SELECT x, x*1000, x*1000000 FROM c;
|
||||
CREATE TABLE t2(b INT, x INT);
|
||||
INSERT INTO t2(b,x) SELECT b, a FROM t1 WHERE a%3==0;
|
||||
CREATE INDEX t2b ON t2(b);
|
||||
CREATE TABLE t3(c INT, y INT);
|
||||
INSERT INTO t3(c,y) SELECT c, a FROM t1 WHERE a%4==0;
|
||||
CREATE INDEX t3c ON t3(c);
|
||||
INSERT INTO t1(a,b,c) VALUES(200, 200000, NULL);
|
||||
ANALYZE;
|
||||
} {}
|
||||
do_execsql_test 12.2 {
|
||||
SELECT * FROM t1 NATURAL JOIN t2 NATURAL JOIN t3 WHERE x>0 AND y>0
|
||||
ORDER BY +a;
|
||||
} {
|
||||
12 12000 12000000 12 12
|
||||
24 24000 24000000 24 24
|
||||
36 36000 36000000 36 36
|
||||
48 48000 48000000 48 48
|
||||
60 60000 60000000 60 60
|
||||
72 72000 72000000 72 72
|
||||
84 84000 84000000 84 84
|
||||
96 96000 96000000 96 96
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
# 2022-04-09
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests for RIGHT and FULL OUTER JOINs.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
foreach {id schema} {
|
||||
1 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
CREATE TABLE t2(c INT, d INT);
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE INDEX t2c ON t2(c);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE INDEX t1ab ON t1(a,b);
|
||||
CREATE TABLE t2(c INT, d INT);
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE INDEX t2cd ON t2(c,d);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
3 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
CREATE TABLE t2(c INT, d INT PRIMARY KEY) WITHOUT ROWID;
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE INDEX t2c ON t2(c);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
4 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT);
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
5 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE TABLE t2(c INT PRIMARY KEY, d INT) WITHOUT ROWID;
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
6 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE VIEW t2(c,d) AS VALUES(3,33),(4,44),(5,55);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
7 {
|
||||
CREATE VIEW t1(a,b) AS VALUES(1,2),(1,3),(1,4);
|
||||
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT);
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
8 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE TABLE t2(c INT, d INT);
|
||||
INSERT INTO t2 VALUES(3,33),(4,44),(5,55);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
}
|
||||
9 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT);
|
||||
CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT);
|
||||
CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b;
|
||||
INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97);
|
||||
INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55);
|
||||
CREATE TABLE dual(dummy TEXT);
|
||||
INSERT INTO dual(dummy) VALUES('x');
|
||||
}
|
||||
10 {
|
||||
CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a,b)) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(1,2),(1,3),(1,4);
|
||||
CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT);
|
||||
CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT);
|
||||
CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b;
|
||||
INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97);
|
||||
INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55);
|
||||
CREATE TABLE dual(dummy TEXT);
|
||||
INSERT INTO dual(dummy) VALUES('x');
|
||||
}
|
||||
} {
|
||||
reset_db
|
||||
db nullvalue NULL
|
||||
do_execsql_test join7-$id.setup $schema {}
|
||||
|
||||
# Verified against PG-14 for case 1
|
||||
do_execsql_test join7-$id.10 {
|
||||
SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL 55
|
||||
2 NULL
|
||||
3 33
|
||||
4 44
|
||||
}
|
||||
|
||||
# Verified against PG-14 for case 1
|
||||
do_execsql_test join7-$id.20 {
|
||||
SELECT a, c FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL 5
|
||||
1 NULL
|
||||
1 3
|
||||
1 4
|
||||
}
|
||||
|
||||
do_execsql_test join7-$id.30 {
|
||||
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.31 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.40 {
|
||||
SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.50 {
|
||||
SELECT t1.*, t2.* FROM t2 LEFT OUTER JOIN t1 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.60 {
|
||||
SELECT * FROM dual JOIN t1 ON true RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL NULL 5 55
|
||||
x 1 3 3 33
|
||||
x 1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.70 {
|
||||
SELECT t1.*, t2.*
|
||||
FROM t2 LEFT JOIN (dual JOIN t1 ON true) ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.80 {
|
||||
SELECT * FROM dual CROSS JOIN t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL NULL 5 55
|
||||
x 1 3 3 33
|
||||
x 1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.81 {
|
||||
SELECT dual.*, t1.*, t2.*
|
||||
FROM t1 CROSS JOIN dual RIGHT OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
NULL NULL NULL 5 55
|
||||
x 1 3 3 33
|
||||
x 1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.90 {
|
||||
SELECT * FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b;
|
||||
} {
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.100 {
|
||||
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
do_execsql_test join7-$id.101 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c AND a=1 ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
|
||||
# Verified against PG-14 for case 1
|
||||
do_execsql_test join7-$id.110 {
|
||||
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b;
|
||||
} {
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
|
||||
do_execsql_test join7-$id.111 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c WHERE a=1 ORDER BY +b;
|
||||
} {
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
|
||||
# Verified against PG-14 for case 1
|
||||
do_execsql_test join7-$id.115 {
|
||||
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c
|
||||
WHERE a=1 OR a IS NULL ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
|
||||
do_execsql_test join7-$id.116 {
|
||||
SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c
|
||||
WHERE a=1 OR a IS NULL ORDER BY +b;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 3 33
|
||||
1 4 4 44
|
||||
}
|
||||
|
||||
# Verified against PG-14 for case 1:
|
||||
do_execsql_test join7-$id.120 {
|
||||
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d;
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
}
|
||||
|
||||
# Verified against PG-14 for case 1:
|
||||
do_execsql_test join7-$id.130 {
|
||||
SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d;
|
||||
} {
|
||||
NULL NULL 3 33
|
||||
NULL NULL 4 44
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 NULL NULL
|
||||
1 4 NULL NULL
|
||||
}
|
||||
|
||||
# Verified against PG-14 for case 1:
|
||||
do_execsql_test join7-$id.140 {
|
||||
SELECT a, b, c, d
|
||||
FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0 ORDER BY +b, +d;
|
||||
} {
|
||||
NULL NULL 3 33
|
||||
NULL NULL 4 44
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
1 3 NULL NULL
|
||||
1 4 NULL NULL
|
||||
}
|
||||
|
||||
do_execsql_test join7-$id.141 {
|
||||
SELECT a, b, c, d
|
||||
FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0
|
||||
ORDER BY +b, +d LIMIT 2 OFFSET 2
|
||||
} {
|
||||
NULL NULL 5 55
|
||||
1 2 NULL NULL
|
||||
}
|
||||
}
|
||||
finish_test
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
# 2022-04-12
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for RIGHT and FULL OUTER JOINs.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
db null NULL
|
||||
do_execsql_test join8-10 {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE TABLE t2(x,y);
|
||||
CREATE INDEX t2x ON t2(x);
|
||||
SELECT avg(DISTINCT b) FROM (SELECT * FROM t2 LEFT RIGHT JOIN t1 ON c);
|
||||
} {NULL}
|
||||
|
||||
# Pending optimization opportunity:
|
||||
# Row-value initialization subroutines must be called from with the
|
||||
# RIGHT JOIN body subroutine before the first use of any register containing
|
||||
# the results of that subroutine. This seems dodgy. Test case:
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-1000 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT,b,c,d,e,f,g,h,j,k,l,m,n,o,p,q,r,s);
|
||||
CREATE INDEX t1x1 ON t1(g+h,j,k);
|
||||
CREATE INDEX t1x2 ON t1(b);
|
||||
INSERT INTO t1 DEFAULT VALUES;
|
||||
} {}
|
||||
do_catchsql_test join8-1010 {
|
||||
SELECT a
|
||||
FROM (
|
||||
SELECT a
|
||||
FROM (
|
||||
SELECT a
|
||||
FROM (
|
||||
SELECT a FROM t1 NATURAL LEFT JOIN t1
|
||||
WHERE (b, 2 ) IS ( SELECT 2 IN(2,2),2)
|
||||
)
|
||||
NATURAL LEFT FULL JOIN t1
|
||||
WHERE ( rowid , 1 )<=(CASE 5 WHEN 619 THEN 841 ELSE 3374391096 END,0)
|
||||
ORDER BY a ASC
|
||||
)
|
||||
NATURAL LEFT JOIN t1
|
||||
WHERE (b, 2 ) IS ( SELECT 3 IN(3,3),3)
|
||||
)
|
||||
NATURAL LEFT FULL JOIN t1
|
||||
WHERE ( rowid , 1 )<=(CASE 5 WHEN 619 THEN 841 ELSE 3374391096 END,0)
|
||||
ORDER BY a ASC;
|
||||
} {0 1}
|
||||
|
||||
# Pending issue #2: (now resolved)
|
||||
# Jump to addrHalt inside the RIGHT JOIN body subroutine bypasses the
|
||||
# OP_Return, resulting in a subroutine loop. Test case:
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-2000 {
|
||||
CREATE TABLE t1(a int, b int, c int);
|
||||
INSERT INTO t1 VALUES(1,2,3),(4,5,6);
|
||||
CREATE TABLE t2(d int, e int);
|
||||
INSERT INTO t2 VALUES(3,333),(4,444);
|
||||
CREATE TABLE t3(f int, g int);
|
||||
PRAGMA automatic_index=off;
|
||||
} {}
|
||||
do_catchsql_test join8-2010 {
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON c=d JOIN t3 ON f=e;
|
||||
} {0 {}}
|
||||
|
||||
# Demonstrate that nested FULL JOINs and USING clauses work
|
||||
#
|
||||
reset_db
|
||||
load_static_extension db series
|
||||
do_execsql_test join8-3000 {
|
||||
CREATE TABLE t1(id INTEGER PRIMARY KEY, a INT);
|
||||
CREATE TABLE t2(id INTEGER PRIMARY KEY, b INT);
|
||||
CREATE TABLE t3(id INTEGER PRIMARY KEY, c INT);
|
||||
CREATE TABLE t4(id INTEGER PRIMARY KEY, d INT);
|
||||
CREATE TABLE t5(id INTEGER PRIMARY KEY, e INT);
|
||||
CREATE TABLE t6(id INTEGER PRIMARY KEY, f INT);
|
||||
CREATE TABLE t7(id INTEGER PRIMARY KEY, g INT);
|
||||
CREATE TABLE t8(id INTEGER PRIMARY KEY, h INT);
|
||||
INSERT INTO t1 SELECT value, 1 FROM generate_series(1,256) WHERE value & 1;
|
||||
INSERT INTO t2 SELECT value, 1 FROM generate_series(1,256) WHERE value & 2;
|
||||
INSERT INTO t3 SELECT value, 1 FROM generate_series(1,256) WHERE value & 4;
|
||||
INSERT INTO t4 SELECT value, 1 FROM generate_series(1,256) WHERE value & 8;
|
||||
INSERT INTO t5 SELECT value, 1 FROM generate_series(1,256) WHERE value & 16;
|
||||
INSERT INTO t6 SELECT value, 1 FROM generate_series(1,256) WHERE value & 32;
|
||||
INSERT INTO t7 SELECT value, 1 FROM generate_series(1,256) WHERE value & 64;
|
||||
INSERT INTO t8 SELECT value, 1 FROM generate_series(1,256) WHERE value & 128;
|
||||
CREATE TABLE t9 AS
|
||||
SELECT id, h, g, f, e, d, c, b, a
|
||||
FROM t1
|
||||
NATURAL FULL JOIN t2
|
||||
NATURAL FULL JOIN t3
|
||||
NATURAL FULL JOIN t4
|
||||
NATURAL FULL JOIN t5
|
||||
NATURAL FULL JOIN t6
|
||||
NATURAL FULL JOIN t7
|
||||
NATURAL FULL JOIN t8;
|
||||
} {}
|
||||
do_execsql_test join8-3010 {
|
||||
SELECT count(*) FROM t9;
|
||||
} {255}
|
||||
do_execsql_test join8-3020 {
|
||||
SELECT id, count(*) FROM t9 GROUP BY id HAVING count(*)!=1;
|
||||
} {}
|
||||
do_execsql_test join8-3030 {
|
||||
UPDATE t9 SET a=0 WHERE a IS NULL;
|
||||
UPDATE t9 SET b=0 WHERE b IS NULL;
|
||||
UPDATE t9 SET c=0 WHERE c IS NULL;
|
||||
UPDATE t9 SET d=0 WHERE d IS NULL;
|
||||
UPDATE t9 SET e=0 WHERE e IS NULL;
|
||||
UPDATE t9 SET f=0 WHERE f IS NULL;
|
||||
UPDATE t9 SET g=0 WHERE g IS NULL;
|
||||
UPDATE t9 SET h=0 WHERE h IS NULL;
|
||||
SELECT count(*) FROM t9 WHERE id=128*h+64*g+32*f+16*e+8*d+4*c+2*b+a;
|
||||
} {255}
|
||||
do_execsql_test join8-3040 {
|
||||
SELECT * FROM t9 WHERE id<>128*h+64*g+32*f+16*e+8*d+4*c+2*b+a;
|
||||
} {}
|
||||
|
||||
# 2022-04-21 dbsqlfuzz find
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-4000 {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, a, b);
|
||||
INSERT INTO t1 VALUES(1,5555,4);
|
||||
CREATE INDEX i1a ON t1(a);
|
||||
CREATE INDEX i1b ON t1(b);
|
||||
SELECT a FROM t1 NATURAL RIGHT JOIN t1 WHERE a=5555 OR (1,b)==(SELECT 2 IN (2,2),4);
|
||||
} {5555}
|
||||
|
||||
# 2022-04-23 dbsqlfuzz c7ee5500e3abddec3557016de777713b80c790d3
|
||||
# Escape from the right-join body subroutine via the ORDER BY LIMIT optimization.
|
||||
#
|
||||
reset_db
|
||||
db null -
|
||||
do_catchsql_test join8-5000 {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1(x) VALUES(NULL),(NULL);
|
||||
CREATE TABLE t2(c, d);
|
||||
INSERT INTO t2(c,d) SELECT x, x FROM t1;
|
||||
CREATE INDEX t2dc ON t2(d, c);
|
||||
SELECT (SELECT c FROM sqlite_temp_schema FULL JOIN t2 ON d IN (1,2,3) ORDER BY d) AS x FROM t1;
|
||||
} {0 {- -}}
|
||||
|
||||
# 2022-04-29 dbsqlfuzz 19f1102a70cf966ab249de56d944fc20dbebcfcf
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test join8-6000 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d REAL);
|
||||
INSERT INTO t1 VALUES(1,'A','aa',2.5);
|
||||
SELECT * FROM t1 AS t2 NATURAL RIGHT JOIN t1 AS t3
|
||||
WHERE (a,b) IN (SELECT rowid, b FROM t1);
|
||||
} {1 A aa 2.5}
|
||||
do_execsql_test join8-6010 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INT PRIMARY KEY, b TEXT, c TEXT, d INT) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(15,'xray','baker',42);
|
||||
SELECT value, t1.* FROM json_each('7') NATURAL RIGHT JOIN t1
|
||||
WHERE (a,b) IN (SELECT a, b FROM t1);
|
||||
} {7 15 xray baker 42}
|
||||
do_execsql_test join8-6020 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY,b);
|
||||
INSERT INTO t1 VALUES(0,NULL),(1,2);
|
||||
SELECT value, t1.* FROM json_each('17') NATURAL RIGHT JOIN t1
|
||||
WHERE (a,b) IN (SELECT rowid, b FROM t1);
|
||||
} {17 1 2}
|
||||
|
||||
finish_test
|
||||
+565
@@ -0,0 +1,565 @@
|
||||
# 2022-04-16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests for RIGHT and FULL OUTER JOINs.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
foreach {id schema} {
|
||||
1 {
|
||||
CREATE TABLE t3(id INTEGER PRIMARY KEY, w TEXT);
|
||||
CREATE TABLE t4(id INTEGER PRIMARY KEY, x TEXT);
|
||||
CREATE TABLE t5(id INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE t6(id INTEGER PRIMARY KEY, z INT);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
INSERT INTO t3(id,w) VALUES(2,'two'),(3,'three'),(6,'six'),(7,'seven');
|
||||
INSERT INTO t4(id,x) VALUES(2,'alice'),(4,'bob'),(6,'cindy'),(8,'dave');
|
||||
INSERT INTO t5(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow'),(4,'green'),
|
||||
(5,'blue');
|
||||
INSERT INTO t6(id,z) VALUES(3,333),(4,444),(5,555),(0,1000),(9,999);
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t3(id INT PRIMARY KEY, w TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t4(id INT PRIMARY KEY, x TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t5(id INT PRIMARY KEY, y TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t6(id INT PRIMARY KEY, z INT) WITHOUT ROWID;
|
||||
CREATE TABLE dual(dummy TEXT);
|
||||
INSERT INTO dual(dummy) VALUES('x');
|
||||
INSERT INTO t3(id,w) VALUES(2,'two'),(3,'three'),(6,'six'),(7,'seven');
|
||||
INSERT INTO t4(id,x) VALUES(2,'alice'),(4,'bob'),(6,'cindy'),(8,'dave');
|
||||
INSERT INTO t5(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow'),(4,'green'),
|
||||
(5,'blue');
|
||||
INSERT INTO t6(id,z) VALUES(3,333),(4,444),(5,555),(0,1000),(9,999);
|
||||
}
|
||||
3 {
|
||||
CREATE TABLE t3x(id INTEGER PRIMARY KEY, w TEXT);
|
||||
CREATE TABLE t4x(id INTEGER PRIMARY KEY, x TEXT);
|
||||
CREATE TABLE t5x(id INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE t6x(id INTEGER PRIMARY KEY, z INT);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
INSERT INTO t3x(id,w) VALUES(2,'two'),(3,'three'),(6,'six'),(7,'seven');
|
||||
INSERT INTO t4x(id,x) VALUES(2,'alice'),(4,'bob'),(6,'cindy'),(8,'dave');
|
||||
INSERT INTO t5x(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow'),(4,'green'),
|
||||
(5,'blue');
|
||||
INSERT INTO t6x(id,z) VALUES(3,333),(4,444),(5,555),(0,1000),(9,999);
|
||||
CREATE VIEW t3 AS SELECT * FROM t3x LIMIT 1000;
|
||||
CREATE VIEW t4 AS SELECT * FROM t4x LIMIT 1000;
|
||||
CREATE VIEW t5 AS SELECT * FROM t5x LIMIT 1000;
|
||||
CREATE VIEW t6 AS SELECT * FROM t6x LIMIT 1000;
|
||||
}
|
||||
4 {
|
||||
CREATE TABLE t3a(id INTEGER PRIMARY KEY, w TEXT);
|
||||
CREATE TABLE t3b(id INTEGER PRIMARY KEY, w TEXT);
|
||||
CREATE TABLE t4a(id INTEGER PRIMARY KEY, x TEXT);
|
||||
CREATE TABLE t4b(id INTEGER PRIMARY KEY, x TEXT);
|
||||
CREATE TABLE t5a(id INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE t5b(id INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE t6a(id INTEGER PRIMARY KEY, z INT);
|
||||
CREATE TABLE t6b(id INTEGER PRIMARY KEY, z INT);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
INSERT INTO t3a(id,w) VALUES(2,'two'),(3,'three');
|
||||
INSERT INTO t3b(id,w) VALUES(6,'six'),(7,'seven');
|
||||
INSERT INTO t4a(id,x) VALUES(2,'alice'),(4,'bob');
|
||||
INSERT INTO t4b(id,x) VALUES(6,'cindy'),(8,'dave');
|
||||
INSERT INTO t5a(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow');
|
||||
INSERT INTO t5b(id,y) VALUES(4,'green'),(5,'blue');
|
||||
INSERT INTO t6a(id,z) VALUES(3,333),(4,444);
|
||||
INSERT INTO t6b(id,z) VALUES(5,555),(0,1000),(9,999);
|
||||
CREATE VIEW t3 AS SELECT * FROM t3a UNION ALL SELECT * FROM t3b;
|
||||
CREATE VIEW t4 AS SELECT * FROM t4a UNION ALL SELECT * FROM t4b;
|
||||
CREATE VIEW t5 AS SELECT * FROM t5a UNION ALL SELECT * FROM t5b;
|
||||
CREATE VIEW t6 AS SELECT * FROM t6a UNION ALL SELECT * FROM t6b;
|
||||
}
|
||||
5 {
|
||||
CREATE TABLE t3a(id INTEGER PRIMARY KEY, w TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t3b(id INTEGER PRIMARY KEY, w TEXT);
|
||||
CREATE TABLE t4a(id INTEGER PRIMARY KEY, x TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t4b(id INTEGER PRIMARY KEY, x TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t5a(id INTEGER PRIMARY KEY, y TEXT);
|
||||
CREATE TABLE t5b(id INTEGER PRIMARY KEY, y TEXT) WITHOUT ROWID;
|
||||
CREATE TABLE t6a(id INTEGER PRIMARY KEY, z INT);
|
||||
CREATE TABLE t6b(id INTEGER PRIMARY KEY, z INT);
|
||||
CREATE VIEW dual(dummy) AS VALUES('x');
|
||||
INSERT INTO t3a(id,w) VALUES(2,'two'),(3,'three');
|
||||
INSERT INTO t3b(id,w) VALUES(6,'six'),(7,'seven');
|
||||
INSERT INTO t4a(id,x) VALUES(2,'alice'),(4,'bob');
|
||||
INSERT INTO t4b(id,x) VALUES(6,'cindy'),(8,'dave');
|
||||
INSERT INTO t5a(id,y) VALUES(1,'red'),(2,'orange'),(3,'yellow');
|
||||
INSERT INTO t5b(id,y) VALUES(4,'green'),(5,'blue');
|
||||
INSERT INTO t6a(id,z) VALUES(3,333),(4,444);
|
||||
INSERT INTO t6b(id,z) VALUES(5,555),(0,1000),(9,999);
|
||||
CREATE VIEW t3 AS SELECT * FROM t3a UNION ALL SELECT * FROM t3b;
|
||||
CREATE VIEW t4 AS SELECT * FROM t4a UNION ALL SELECT * FROM t4b LIMIT 50;
|
||||
CREATE VIEW t5 AS SELECT * FROM t5a UNION ALL SELECT * FROM t5b LIMIT 100;
|
||||
CREATE VIEW t6 AS SELECT * FROM t6a UNION ALL SELECT * FROM t6b;
|
||||
}
|
||||
} {
|
||||
reset_db
|
||||
db nullvalue -
|
||||
do_execsql_test join9-$id.setup $schema {}
|
||||
|
||||
# Verifid by PG-14 for case 1
|
||||
do_execsql_test join9-$id.100 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL LEFT JOIN t5 NATURAL LEFT JOIN t6
|
||||
ORDER BY 1;
|
||||
} {
|
||||
2 alice orange - 2 2 -
|
||||
4 bob green 444 4 4 4
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
}
|
||||
|
||||
do_execsql_test join9-$id.101 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL LEFT JOIN t5 NATURAL LEFT JOIN t6
|
||||
ORDER BY id;
|
||||
} {
|
||||
2 alice orange - 2 2 -
|
||||
4 bob green 444 4 4 4
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
}
|
||||
do_execsql_test join9-$id.102 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 LEFT JOIN t5 USING(id) LEFT JOIN t6 USING(id)
|
||||
ORDER BY id;
|
||||
} {
|
||||
2 alice orange - 2 2 -
|
||||
4 bob green 444 4 4 4
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
}
|
||||
|
||||
# Verifid by PG-14 using case 1
|
||||
do_execsql_test join9-$id.200 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t5 NATURAL RIGHT JOIN t4 NATURAL LEFT JOIN t6
|
||||
ORDER BY 1;
|
||||
} {
|
||||
2 alice orange - 2 2 -
|
||||
4 bob green 444 4 4 4
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
}
|
||||
|
||||
do_execsql_test join9-$id.201 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t5 NATURAL RIGHT JOIN t4 NATURAL LEFT JOIN t6
|
||||
ORDER BY id;
|
||||
} {
|
||||
2 alice orange - 2 2 -
|
||||
4 bob green 444 4 4 4
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
}
|
||||
|
||||
# Verified by PG-14 using case 1
|
||||
do_execsql_test join9-$id.300 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL RIGHT JOIN t5 NATURAL RIGHT JOIN t6
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
|
||||
do_execsql_test join9-$id.301 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL RIGHT JOIN t5 NATURAL RIGHT JOIN t6
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
|
||||
# Verified by PG-14 for case 1
|
||||
do_execsql_test join9-$id.400 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL FULL JOIN t5 NATURAL FULL JOIN t6
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
|
||||
do_execsql_test join9-$id.401 {
|
||||
SELECT *, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL FULL JOIN t5 NATURAL FULL JOIN t6
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
do_execsql_test join9-$id.402 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t4 NATURAL FULL JOIN t6 NATURAL FULL JOIN t5
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
do_execsql_test join9-$id.403 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t5 NATURAL FULL JOIN t4 NATURAL FULL JOIN t6
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
do_execsql_test join9-$id.404 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t5 NATURAL FULL JOIN t6 NATURAL FULL JOIN t4
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
do_execsql_test join9-$id.405 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t6 NATURAL FULL JOIN t4 NATURAL FULL JOIN t5
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
do_execsql_test join9-$id.406 {
|
||||
SELECT id, x, y, z, t4.id, t5.id, t6.id
|
||||
FROM t6 NATURAL FULL JOIN t5 NATURAL FULL JOIN t4
|
||||
ORDER BY id;
|
||||
} {
|
||||
0 - - 1000 - - 0
|
||||
1 - red - - 1 -
|
||||
2 alice orange - 2 2 -
|
||||
3 - yellow 333 - 3 3
|
||||
4 bob green 444 4 4 4
|
||||
5 - blue 555 - 5 5
|
||||
6 cindy - - 6 - -
|
||||
8 dave - - 8 - -
|
||||
9 - - 999 - - 9
|
||||
}
|
||||
|
||||
# Verified by PG-14 using case 1
|
||||
do_execsql_test join9-$id.500 {
|
||||
SELECT id, w, x, y, z
|
||||
FROM t3 FULL JOIN t4 USING(id)
|
||||
NATURAL FULL JOIN t5
|
||||
FULL JOIN t6 USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
4 - bob green 444
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
|
||||
# Verified by PG-14 using case 1
|
||||
do_execsql_test join9-$id.600 {
|
||||
SELECT id, w, x, y, z
|
||||
FROM t3 JOIN dual AS d1 ON true
|
||||
FULL JOIN t4 USING(id)
|
||||
JOIN dual AS d2 ON true
|
||||
NATURAL FULL JOIN t5
|
||||
JOIN dual AS d3 ON true
|
||||
FULL JOIN t6 USING(id)
|
||||
CROSS JOIN dual AS d4
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
4 - bob green 444
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
|
||||
# Verified by PG-14 using case 1
|
||||
do_execsql_test join9-$id.700 {
|
||||
SELECT id, w, x, y, z
|
||||
FROM t3 JOIN dual AS d1 ON true
|
||||
FULL JOIN t4 USING(id)
|
||||
JOIN dual AS d2 ON true
|
||||
NATURAL FULL JOIN t5
|
||||
JOIN dual AS d3 ON true
|
||||
FULL JOIN t6 USING(id)
|
||||
CROSS JOIN dual AS d4
|
||||
WHERE x<>'bob' OR x IS NULL
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
|
||||
# Verified by PG-14 using case 1
|
||||
do_execsql_test join9-$id.800 {
|
||||
WITH t7(id,a) AS MATERIALIZED (SELECT * FROM t4 WHERE false)
|
||||
SELECT *
|
||||
FROM t7
|
||||
JOIN t7 AS t7b USING(id)
|
||||
FULL JOIN t3 USING(id);
|
||||
} {
|
||||
2 - - two
|
||||
3 - - three
|
||||
6 - - six
|
||||
7 - - seven
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.900 {
|
||||
SELECT *
|
||||
FROM (t3 NATURAL FULL JOIN t4)
|
||||
NATURAL FULL JOIN
|
||||
(t5 NATURAL FULL JOIN t6)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
4 - bob green 444
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
do_execsql_test join9-$id.910 {
|
||||
SELECT *
|
||||
FROM t3 NATURAL FULL JOIN
|
||||
(t4 NATURAL FULL JOIN
|
||||
(t5 NATURAL FULL JOIN t6))
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
4 - bob green 444
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
do_execsql_test join9-$id.920 {
|
||||
SELECT *
|
||||
FROM t3 FULL JOIN (
|
||||
t4 FULL JOIN (
|
||||
t5 FULL JOIN t6 USING (id)
|
||||
) USING(id)
|
||||
) USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
4 - bob green 444
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
do_execsql_test join9-$id.920 {
|
||||
SELECT *
|
||||
FROM t3 FULL JOIN (
|
||||
t4 FULL JOIN (
|
||||
t5 FULL JOIN t6 USING (id)
|
||||
) USING(id)
|
||||
) USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
0 - - - 1000
|
||||
1 - - red -
|
||||
2 two alice orange -
|
||||
3 three - yellow 333
|
||||
4 - bob green 444
|
||||
5 - - blue 555
|
||||
6 six cindy - -
|
||||
7 seven - - -
|
||||
8 - dave - -
|
||||
9 - - - 999
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.930 {
|
||||
SELECT *
|
||||
FROM t3 FULL JOIN (
|
||||
t4 FULL JOIN (
|
||||
t5 FULL JOIN t6 USING(id)
|
||||
) USING(id)
|
||||
) AS j1 ON j1.id=t3.id
|
||||
ORDER BY coalesce(t3.id,j1.id);
|
||||
} {
|
||||
- - 0 - - 1000
|
||||
- - 1 - red -
|
||||
2 two 2 alice orange -
|
||||
3 three 3 - yellow 333
|
||||
- - 4 bob green 444
|
||||
- - 5 - blue 555
|
||||
6 six 6 cindy - -
|
||||
7 seven - - - -
|
||||
- - 8 dave - -
|
||||
- - 9 - - 999
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.940 {
|
||||
SELECT *
|
||||
FROM t3 FULL JOIN (
|
||||
t4 RIGHT JOIN (
|
||||
t5 FULL JOIN t6 USING(id)
|
||||
) USING(id)
|
||||
) AS j1 ON j1.id=t3.id
|
||||
ORDER BY coalesce(t3.id,j1.id);
|
||||
} {
|
||||
- - 0 - - 1000
|
||||
- - 1 - red -
|
||||
2 two 2 alice orange -
|
||||
3 three 3 - yellow 333
|
||||
- - 4 bob green 444
|
||||
- - 5 - blue 555
|
||||
6 six - - - -
|
||||
7 seven - - - -
|
||||
- - 9 - - 999
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.950 {
|
||||
SELECT *
|
||||
FROM t3 FULL JOIN (
|
||||
t4 LEFT JOIN (
|
||||
t5 FULL JOIN t6 USING(id)
|
||||
) USING(id)
|
||||
) AS j1 ON j1.id=t3.id
|
||||
ORDER BY coalesce(t3.id,j1.id);
|
||||
} {
|
||||
2 two 2 alice orange -
|
||||
3 three - - - -
|
||||
- - 4 bob green 444
|
||||
6 six 6 cindy - -
|
||||
7 seven - - - -
|
||||
- - 8 dave - -
|
||||
}
|
||||
|
||||
# Restriction (27) in the query flattener
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.1000 {
|
||||
WITH t56(id,y,z) AS (SELECT * FROM t5 FULL JOIN t6 USING(id) LIMIT 50)
|
||||
SELECT id,x,y,z FROM t4 JOIN t56 USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
2 alice orange -
|
||||
4 bob green 444
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.1010 {
|
||||
SELECT id,x,y,z
|
||||
FROM t4 INNER JOIN (t5 FULL JOIN t6 USING(id)) USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
2 alice orange -
|
||||
4 bob green 444
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.1020 {
|
||||
SELECT id,x,y,z
|
||||
FROM t4 FULL JOIN t5 USING(id) INNER JOIN t6 USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
3 - yellow 333
|
||||
4 bob green 444
|
||||
5 - blue 555
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test join9-$id.1030 {
|
||||
WITH t45(id,x,y) AS (SELECT * FROM t4 FULL JOIN t5 USING(id) LIMIT 50)
|
||||
SELECT id,x,y,z FROM t45 JOIN t6 USING(id)
|
||||
ORDER BY 1;
|
||||
} {
|
||||
3 - yellow 333
|
||||
4 bob green 444
|
||||
5 - blue 555
|
||||
}
|
||||
|
||||
}
|
||||
finish_test
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
# 2022-04-18
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests for RIGHT and FULL OUTER JOINs.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
foreach {id schema} {
|
||||
1 {
|
||||
CREATE TABLE t1(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE t2(c INT, d INT, e INT, f INT);
|
||||
CREATE TABLE t3(a INT, b INT, e INT, f INT);
|
||||
CREATE TABLE t4(a INT, c INT, d INT, f INT);
|
||||
INSERT INTO t1 VALUES(11,21,31,41),(12,22,32,42),(15,25,35,45),(18,28,38,48);
|
||||
INSERT INTO t2 VALUES(12,22,32,42),(13,23,33,43),(15,25,35,45),(17,27,37,47);
|
||||
INSERT INTO t3 VALUES(14,24,34,44),(15,25,35,45),(16,26,36,46);
|
||||
INSERT INTO t4 VALUES(11,21,31,41),(13,23,33,43),(16,26,36,46),(19,29,39,49);
|
||||
}
|
||||
2 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT, d INT);
|
||||
CREATE TABLE t2(c INT, d INTEGER PRIMARY KEY, e INT, f INT);
|
||||
CREATE TABLE t3(a INT, b INT, e INTEGER PRIMARY KEY, f INT);
|
||||
CREATE TABLE t4(a INT, c INT, d INT, f INT PRIMARY KEY) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(11,21,31,41),(12,22,32,42),(15,25,35,45),(18,28,38,48);
|
||||
INSERT INTO t2 VALUES(12,22,32,42),(13,23,33,43),(15,25,35,45),(17,27,37,47);
|
||||
INSERT INTO t3 VALUES(14,24,34,44),(15,25,35,45),(16,26,36,46);
|
||||
INSERT INTO t4 VALUES(11,21,31,41),(13,23,33,43),(16,26,36,46),(19,29,39,49);
|
||||
}
|
||||
3 {
|
||||
CREATE TABLE t1a(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE t2a(c INT, d INT, e INT, f INT);
|
||||
CREATE TABLE t3a(a INT, b INT, e INT, f INT);
|
||||
CREATE TABLE t4a(a INT, c INT, d INT, f INT);
|
||||
INSERT INTO t1a VALUES(11,21,31,41),(12,22,32,42);
|
||||
INSERT INTO t2a VALUES(12,22,32,42),(13,23,33,43);
|
||||
INSERT INTO t3a VALUES(14,24,34,44),(15,25,35,45);
|
||||
INSERT INTO t4a VALUES(11,21,31,41),(13,23,33,43);
|
||||
CREATE TABLE t1b(a INT, b INT, c INT, d INT);
|
||||
CREATE TABLE t2b(c INT, d INT, e INT, f INT);
|
||||
CREATE TABLE t3b(a INT, b INT, e INT, f INT);
|
||||
CREATE TABLE t4b(a INT, c INT, d INT, f INT);
|
||||
INSERT INTO t1b VALUES(15,25,35,45),(18,28,38,48);
|
||||
INSERT INTO t2b VALUES(15,25,35,45),(17,27,37,47);
|
||||
INSERT INTO t3b VALUES(15,25,35,45),(16,26,36,46);
|
||||
INSERT INTO t4b VALUES(16,26,36,46),(19,29,39,49);
|
||||
CREATE VIEW t1 AS SELECT * FROM t1a UNION SELECT * FROM t1b;
|
||||
CREATE VIEW t2 AS SELECT * FROM t2a UNION SELECT * FROM t2b;
|
||||
CREATE VIEW t3 AS SELECT * FROM t3a UNION SELECT * FROM t3b;
|
||||
CREATE VIEW t4 AS SELECT * FROM t4a UNION SELECT * FROM t4b;
|
||||
}
|
||||
} {
|
||||
reset_db
|
||||
db nullvalue -
|
||||
do_execsql_test joinA-$id.setup $schema {}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.100 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
INNER JOIN t2 USING(c,d)
|
||||
INNER JOIN t3 USING(a,b,f)
|
||||
INNER JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {}
|
||||
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.110 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
LEFT JOIN t2 USING(c,d)
|
||||
LEFT JOIN t3 USING(a,b,f)
|
||||
LEFT JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
11 21 31 41 - - -
|
||||
12 22 32 42 - - -
|
||||
15 25 35 45 - - -
|
||||
18 28 38 48 - - -
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.120 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
LEFT JOIN t2 USING(c,d)
|
||||
RIGHT JOIN t3 USING(a,b,f)
|
||||
LEFT JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
14 24 - - - 44 34
|
||||
15 25 - - - 45 35
|
||||
16 26 - - - 46 36
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.130 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
RIGHT JOIN t2 USING(c,d)
|
||||
LEFT JOIN t3 USING(a,b,f)
|
||||
RIGHT JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
11 - 21 31 - 41 -
|
||||
13 - 23 33 - 43 -
|
||||
16 - 26 36 - 46 -
|
||||
19 - 29 39 - 49 -
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.140 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
FULL JOIN t2 USING(c,d)
|
||||
LEFT JOIN t3 USING(a,b,f)
|
||||
RIGHT JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
11 - 21 31 - 41 -
|
||||
13 - 23 33 - 43 -
|
||||
16 - 26 36 - 46 -
|
||||
19 - 29 39 - 49 -
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.150 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
RIGHT JOIN t2 USING(c,d)
|
||||
FULL JOIN t3 USING(a,b,f)
|
||||
RIGHT JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
11 - 21 31 - 41 -
|
||||
13 - 23 33 - 43 -
|
||||
16 - 26 36 - 46 -
|
||||
19 - 29 39 - 49 -
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.160 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
RIGHT JOIN t2 USING(c,d)
|
||||
LEFT JOIN t3 USING(a,b,f)
|
||||
FULL JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
- - 12 22 32 42 -
|
||||
- - 13 23 33 43 -
|
||||
- - 15 25 35 45 -
|
||||
- - 17 27 37 47 -
|
||||
11 - 21 31 - 41 -
|
||||
13 - 23 33 - 43 -
|
||||
16 - 26 36 - 46 -
|
||||
19 - 29 39 - 49 -
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.170 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
LEFT JOIN t2 USING(c,d)
|
||||
RIGHT JOIN t3 USING(a,b,f)
|
||||
FULL JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
11 - 21 31 - 41 -
|
||||
13 - 23 33 - 43 -
|
||||
14 24 - - - 44 34
|
||||
15 25 - - - 45 35
|
||||
16 26 - - - 46 36
|
||||
16 - 26 36 - 46 -
|
||||
19 - 29 39 - 49 -
|
||||
}
|
||||
|
||||
# Verified by PG-14
|
||||
do_execsql_test joinA-$id.200 {
|
||||
SELECT a,b,c,d,t2.e,f,t3.e
|
||||
FROM t1
|
||||
FULL JOIN t2 USING(c,d)
|
||||
FULL JOIN t3 USING(a,b,f)
|
||||
FULL JOIN t4 USING(a,c,d,f)
|
||||
ORDER BY 1 nulls first, 3 nulls first;
|
||||
} {
|
||||
- - 12 22 32 42 -
|
||||
- - 13 23 33 43 -
|
||||
- - 15 25 35 45 -
|
||||
- - 17 27 37 47 -
|
||||
11 - 21 31 - 41 -
|
||||
11 21 31 41 - - -
|
||||
12 22 32 42 - - -
|
||||
13 - 23 33 - 43 -
|
||||
14 24 - - - 44 34
|
||||
15 25 - - - 45 35
|
||||
15 25 35 45 - - -
|
||||
16 26 - - - 46 36
|
||||
16 - 26 36 - 46 -
|
||||
18 28 38 48 - - -
|
||||
19 - 29 39 - 49 -
|
||||
}
|
||||
}
|
||||
finish_test
|
||||
+7252
File diff suppressed because it is too large
Load Diff
+4594
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -545,14 +545,14 @@ do_test select1-6.9.7 {
|
||||
set x [execsql2 {
|
||||
SELECT * FROM test1 a, (select 5, 6) LIMIT 1
|
||||
}]
|
||||
regsub -all {subquery_[0-9a-fA-F_]+} $x {subquery} x
|
||||
regsub -all {subquery-\d+} $x {subquery-0} x
|
||||
set x
|
||||
} {a.f1 11 a.f2 22 subquery.5 5 subquery.6 6}
|
||||
} {a.f1 11 a.f2 22 (subquery-0).5 5 (subquery-0).6 6}
|
||||
do_test select1-6.9.8 {
|
||||
set x [execsql2 {
|
||||
SELECT * FROM test1 a, (select 5 AS x, 6 AS y) AS b LIMIT 1
|
||||
}]
|
||||
regsub -all {subquery_[0-9a-fA-F]+_} $x {subquery} x
|
||||
regsub -all {subquery-\d+} $x {subquery-0} x
|
||||
set x
|
||||
} {a.f1 11 a.f2 22 b.x 5 b.y 6}
|
||||
do_test select1-6.9.9 {
|
||||
|
||||
@@ -1221,6 +1221,23 @@ do_test shell1-8.4 {
|
||||
+------------------+-----+
|
||||
| 6683623321994527 | -47 |
|
||||
+------------------+-----+}}
|
||||
do_test shell1-8.5 {
|
||||
catchcmd ":memory: --box" {
|
||||
create table t(a text, b int);
|
||||
insert into t values ('too long for one line', 1), ('shorter', NULL);
|
||||
.header on
|
||||
.width 10 10
|
||||
.nullvalue NADA
|
||||
select * from t;}
|
||||
} {0 {┌────────────┬────────────┐
|
||||
│ a │ b │
|
||||
├────────────┼────────────┤
|
||||
│ too long f │ 1 │
|
||||
│ or one lin │ │
|
||||
│ e │ │
|
||||
├────────────┼────────────┤
|
||||
│ shorter │ NADA │
|
||||
└────────────┴────────────┘}}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases shell1-9.*: Basic test that "dot" commands and SQL intermix ok.
|
||||
|
||||
@@ -540,4 +540,34 @@ Columns renamed during .import shell5.csv due to duplicates:
|
||||
"CoW" to "CoW_3",
|
||||
"cOw" to "cOw_4"}}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Tests for preserving utf-8 that is not also ASCII.
|
||||
#
|
||||
|
||||
do_test shell5-6.1 {
|
||||
set out [open shell5.csv w]
|
||||
fconfigure $out -translation lf
|
||||
puts $out {あい,うえお}
|
||||
puts $out {1,2}
|
||||
close $out
|
||||
forcedelete test.db
|
||||
catchcmd test.db {.import -csv shell5.csv t1
|
||||
.mode line
|
||||
SELECT * FROM t1;}
|
||||
} {0 { あい = 1
|
||||
うえお = 2}}
|
||||
|
||||
do_test shell5-6.2 {
|
||||
set out [open shell5.csv w]
|
||||
fconfigure $out -translation lf
|
||||
puts $out {1,2}
|
||||
puts $out {あい,うえお}
|
||||
close $out
|
||||
forcedelete test.db
|
||||
catchcmd test.db {.import -csv shell5.csv t1
|
||||
.mode line
|
||||
SELECT * FROM t1;}
|
||||
} {0 { 1 = あい
|
||||
2 = うえお}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1011,6 +1011,7 @@ proc query_plan_graph {sql} {
|
||||
append a [append_graph " " dx cx 0]
|
||||
regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a
|
||||
regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a
|
||||
regsub -all {\((join|subquery)-\d+\)} $a {(\1-xxxxxx)} a
|
||||
return $a
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -223,11 +223,11 @@ do_test vtab6-2.2 {
|
||||
SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1;
|
||||
}
|
||||
} {1 2 3 {} 2 3 4 1 3 4 5 2}
|
||||
do_test vtab6-2.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
|
||||
}
|
||||
} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
|
||||
#do_test vtab6-2.3 {
|
||||
# catchsql {
|
||||
# SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
|
||||
# }
|
||||
#} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
|
||||
do_test vtab6-2.4 {
|
||||
execsql {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d
|
||||
@@ -281,12 +281,12 @@ do_test vtab6-3.7 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 INNER OUTER JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: INNER OUTER}}
|
||||
} {1 {unknown join type: INNER OUTER}}
|
||||
do_test vtab6-3.7 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 LEFT BOGUS JOIN t2;
|
||||
}
|
||||
} {1 {unknown or unsupported join type: LEFT BOGUS}}
|
||||
} {1 {unknown join type: LEFT BOGUS}}
|
||||
|
||||
do_test vtab6-4.1 {
|
||||
execsql {
|
||||
|
||||
@@ -1348,16 +1348,25 @@ do_execsql_test where-18.1 {
|
||||
INSERT INTO t181 VALUES(1);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL;
|
||||
} {1}
|
||||
do_execsql_test where-18.1rj {
|
||||
SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY c IS NULL;
|
||||
} {1}
|
||||
do_execsql_test where-18.2 {
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
|
||||
} {1}
|
||||
do_execsql_test where-18.3 {
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c;
|
||||
} {1}
|
||||
do_execsql_test where-18.3rj {
|
||||
SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY c;
|
||||
} {1}
|
||||
do_execsql_test where-18.4 {
|
||||
INSERT INTO t181 VALUES(1),(1),(1),(1);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
|
||||
} {1}
|
||||
do_execsql_test where-18.4rj {
|
||||
SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY +c;
|
||||
} {1}
|
||||
do_execsql_test where-18.5 {
|
||||
INSERT INTO t181 VALUES(2);
|
||||
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a;
|
||||
|
||||
+2
-2
@@ -378,9 +378,9 @@ ifcapable explain {
|
||||
|--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
|
||||
`--MULTI-INDEX OR
|
||||
|--INDEX 1
|
||||
| `--SEARCH t2 USING INDEX t2d (d=?)
|
||||
| `--SEARCH t2 USING INDEX t2d (d=?) LEFT-JOIN
|
||||
`--INDEX 2
|
||||
`--SEARCH t2 USING COVERING INDEX t2f (f=?)
|
||||
`--SEARCH t2 USING COVERING INDEX t2f (f=?) LEFT-JOIN
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -365,4 +365,49 @@ do_execsql_test 9.0 {
|
||||
FROM seps;
|
||||
} {-22- -22-333- -333-4444- -4444-}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE t1(i INTEGER PRIMARY KEY, v);
|
||||
INSERT INTO t1 VALUES( 1, 'one' );
|
||||
INSERT INTO t1 VALUES( 2, 'two' );
|
||||
}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
SELECT
|
||||
json_group_array( v ) OVER w,
|
||||
json_group_array( v ) OVER w
|
||||
FROM t1
|
||||
window w as (
|
||||
range between unbounded preceding and unbounded following
|
||||
)
|
||||
} {
|
||||
{["one","two"]}
|
||||
{["one","two"]}
|
||||
{["one","two"]}
|
||||
{["one","two"]}
|
||||
}
|
||||
|
||||
do_execsql_test 10.3 {
|
||||
SELECT
|
||||
group_concat( v ) OVER w,
|
||||
json_group_array( v ) OVER w,
|
||||
json_group_array( v ) OVER w,
|
||||
group_concat( v ) OVER w
|
||||
FROM t1
|
||||
window w as (
|
||||
range between unbounded preceding and unbounded following
|
||||
)
|
||||
} {
|
||||
one,two
|
||||
{["one","two"]}
|
||||
{["one","two"]}
|
||||
one,two
|
||||
|
||||
one,two
|
||||
{["one","two"]}
|
||||
{["one","two"]}
|
||||
one,two
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+4
-4
@@ -1075,10 +1075,10 @@ do_execsql_test 21.2 {
|
||||
# Make sure crazy nexted CTE joins terminate with an error quickly.
|
||||
#
|
||||
do_catchsql_test 22.1 {
|
||||
WITH RECURSIVE c AS (
|
||||
WITH RECURSIVE c AS (
|
||||
WITH RECURSIVE c AS (
|
||||
WITH RECURSIVE c AS (
|
||||
WITH RECURSIVE c AS NOT MATERIALIZED (
|
||||
WITH RECURSIVE c AS NOT MATERIALIZED (
|
||||
WITH RECURSIVE c AS NOT MATERIALIZED (
|
||||
WITH RECURSIVE c AS NOT MATERIALIZED (
|
||||
WITH c AS (VALUES(0))
|
||||
SELECT 1 FROM c LEFT JOIN c ON ltrim(1)
|
||||
)
|
||||
|
||||
+68
-1
@@ -229,10 +229,12 @@ do_eqp_test 211 {
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE c1
|
||||
| |--MATERIALIZE c
|
||||
| |--CO-ROUTINE c
|
||||
| | `--SCAN 3 CONSTANT ROWS
|
||||
| `--SCAN c
|
||||
|--MATERIALIZE c2
|
||||
| |--CO-ROUTINE c
|
||||
| | `--SCAN 3 CONSTANT ROWS
|
||||
| `--SCAN c
|
||||
|--SCAN c1
|
||||
|--SCAN c2
|
||||
@@ -250,6 +252,71 @@ do_execsql_test 220 {
|
||||
SELECT y FROM t2 ORDER BY y;
|
||||
} {40404 40405 40406 40504 40505 40506 40604 40605 40606}
|
||||
|
||||
# 2022-04-22: Do not allow flattening of a MATERIALIZED CTE into
|
||||
# an outer query.
|
||||
#
|
||||
reset_db
|
||||
db null -
|
||||
do_execsql_test 300 {
|
||||
CREATE TABLE t2(a INT,b INT,d INT); INSERT INTO t2 VALUES(4,5,6),(7,8,9);
|
||||
CREATE TABLE t3(a INT,b INT,e INT); INSERT INTO t3 VALUES(3,3,3),(8,8,8);
|
||||
} {}
|
||||
do_execsql_test 310 {
|
||||
WITH t23 AS MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
|
||||
SELECT * FROM t23;
|
||||
} {
|
||||
4 5 6 - -
|
||||
7 8 9 8 8
|
||||
- 3 - 3 3
|
||||
}
|
||||
do_eqp_test 311 {
|
||||
WITH t23 AS MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
|
||||
SELECT * FROM t23;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--MATERIALIZE t23
|
||||
| |--SCAN t2
|
||||
| |--SCAN t3 LEFT-JOIN
|
||||
| `--RIGHT-JOIN t3
|
||||
| `--SCAN t3
|
||||
`--SCAN t23
|
||||
}
|
||||
do_execsql_test 320 {
|
||||
WITH t23 AS NOT MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
|
||||
SELECT * FROM t23;
|
||||
} {
|
||||
4 5 6 - -
|
||||
7 8 9 8 8
|
||||
- 3 - 3 3
|
||||
}
|
||||
do_eqp_test 321 {
|
||||
WITH t23 AS NOT MATERIALIZED (SELECT * FROM t2 FULL JOIN t3 USING(b))
|
||||
SELECT * FROM t23;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t2
|
||||
|--SCAN t3 LEFT-JOIN
|
||||
`--RIGHT-JOIN t3
|
||||
`--SCAN t3
|
||||
}
|
||||
do_execsql_test 330 {
|
||||
WITH t23 AS (SELECT * FROM t2 FULL JOIN t3 USING(b))
|
||||
SELECT * FROM t23;
|
||||
} {
|
||||
4 5 6 - -
|
||||
7 8 9 8 8
|
||||
- 3 - 3 3
|
||||
}
|
||||
do_eqp_test 331 {
|
||||
WITH t23 AS (SELECT * FROM t2 FULL JOIN t3 USING(b))
|
||||
SELECT * FROM t23;
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t2
|
||||
|--SCAN t3 LEFT-JOIN
|
||||
`--RIGHT-JOIN t3
|
||||
`--SCAN t3
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-11
@@ -164,11 +164,6 @@ struct Keyword {
|
||||
#else
|
||||
# define RETURNING 0x00400000
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_MERGE
|
||||
# define MERGE 0
|
||||
#else
|
||||
# define MERGE 0x00800000
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ -215,7 +210,7 @@ static Keyword aKeywordTable[] = {
|
||||
{ "DESC", "TK_DESC", ALWAYS, 3 },
|
||||
{ "DETACH", "TK_DETACH", ATTACH, 0 },
|
||||
{ "DISTINCT", "TK_DISTINCT", ALWAYS, 5 },
|
||||
{ "DO", "TK_DO", UPSERT|MERGE, 2 },
|
||||
{ "DO", "TK_DO", UPSERT, 2 },
|
||||
{ "DROP", "TK_DROP", ALWAYS, 1 },
|
||||
{ "END", "TK_END", ALWAYS, 1 },
|
||||
{ "EACH", "TK_EACH", TRIGGER, 1 },
|
||||
@@ -260,13 +255,11 @@ static Keyword aKeywordTable[] = {
|
||||
{ "LIKE", "TK_LIKE_KW", ALWAYS, 5 },
|
||||
{ "LIMIT", "TK_LIMIT", ALWAYS, 3 },
|
||||
{ "MATCH", "TK_MATCH", ALWAYS, 2 },
|
||||
{ "MATCHED", "TK_MATCHED", MERGE, 10 },
|
||||
{ "MATERIALIZED", "TK_MATERIALIZED", CTE, 12 },
|
||||
{ "MERGE", "TK_MERGE", MERGE, 10 },
|
||||
{ "NATURAL", "TK_JOIN_KW", ALWAYS, 3 },
|
||||
{ "NO", "TK_NO", FKEY|WINDOWFUNC, 2 },
|
||||
{ "NOT", "TK_NOT", ALWAYS, 10 },
|
||||
{ "NOTHING", "TK_NOTHING", UPSERT|MERGE, 1 },
|
||||
{ "NOTHING", "TK_NOTHING", UPSERT, 1 },
|
||||
{ "NOTNULL", "TK_NOTNULL", ALWAYS, 3 },
|
||||
{ "NULL", "TK_NULL", ALWAYS, 10 },
|
||||
{ "NULLS", "TK_NULLS", ALWAYS, 3 },
|
||||
@@ -302,8 +295,6 @@ static Keyword aKeywordTable[] = {
|
||||
{ "SAVEPOINT", "TK_SAVEPOINT", ALWAYS, 1 },
|
||||
{ "SELECT", "TK_SELECT", ALWAYS, 10 },
|
||||
{ "SET", "TK_SET", ALWAYS, 10 },
|
||||
{ "SOURCE", "TK_SOURCE", MERGE, 10 },
|
||||
{ "TARGET", "TK_TARGET", MERGE, 10 },
|
||||
{ "TABLE", "TK_TABLE", ALWAYS, 1 },
|
||||
{ "TEMP", "TK_TEMP", ALWAYS, 1 },
|
||||
{ "TEMPORARY", "TK_TEMP", ALWAYS, 1 },
|
||||
|
||||
Reference in New Issue
Block a user