Compare commits
223 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e464b5f51 | |||
| 5eb6e09795 | |||
| a9cdb90421 | |||
| 95fe38f2fc | |||
| 7f417569f7 | |||
| 1a6bac0d2f | |||
| ecb386b71f | |||
| 30d2aab5fd | |||
| 6c7e89b48a | |||
| b77c312956 | |||
| 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 | |||
| ce5dd9e8d6 | |||
| e603ab00ee | |||
| da4c7ccc07 | |||
| db08a6d13c | |||
| a744167956 | |||
| 4cd8296f39 | |||
| 9c949b1c46 | |||
| c381056e6d | |||
| d44f8b2385 | |||
| 200adc9e75 | |||
| c2d0df95ba | |||
| 2a7dcbfbb0 | |||
| c16a5686fe | |||
| 8f1eb6f5e4 | |||
| 5e431bead8 | |||
| f8ef2dbd7b | |||
| 7d2c1d24b0 | |||
| ec534e6a23 | |||
| 50f22d17a8 | |||
| b834e0de59 | |||
| 36d2d09023 | |||
| 0de10ac11c | |||
| b07fb4f1c2 | |||
| a81a9f78fd | |||
| 1c8486301f | |||
| 8703edd3e9 | |||
| 8bb93daca0 | |||
| 18bcfb999a | |||
| 8ee75f7c3a | |||
| c2808f39d1 | |||
| 1f416db292 | |||
| d13527daed | |||
| 2c144b0f63 | |||
| d859dc2b25 | |||
| b47b1f67dc | |||
| 759e507ce5 | |||
| 3b8b5be3b7 | |||
| 35e9e350ca | |||
| a24832b7b2 | |||
| cf6e3fd787 | |||
| 473571b083 | |||
| 2fb448f2c8 | |||
| 17c4865b83 | |||
| 00946d7953 | |||
| 659fdb4da8 | |||
| 99a218282c | |||
| 66181ce2b8 | |||
| c4c0ff8664 | |||
| 89cf958c00 | |||
| 7e62146b13 | |||
| 66f58bf38d | |||
| c55b62d4cb | |||
| 4cb32b70ed | |||
| 555db979f6 | |||
| de9484858e | |||
| fb92e07186 | |||
| bcedbb2781 | |||
| f4dd18ea36 | |||
| 60a512d923 | |||
| cea170ec96 | |||
| da3ec15f3c | |||
| f5a8386c32 | |||
| be341502db | |||
| 5705b41fb8 | |||
| 8ad3c43257 | |||
| 500d7e542c | |||
| 56d88aad29 | |||
| 6fad5776c0 | |||
| b5bb769c27 | |||
| cb0854a380 | |||
| a753a3a2be | |||
| c63e40956b | |||
| bd5fb3a888 | |||
| 67aa2318c1 | |||
| 75c493f767 | |||
| ef07f96faf | |||
| 9198f5afac | |||
| d5c35f6d69 | |||
| 389e056bfe | |||
| b45e1d674a | |||
| 494317ad57 |
@@ -1627,6 +1627,9 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
}else{
|
||||
if( pRet->nPhrase>0 ){
|
||||
Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
|
||||
assert( pParse!=0 );
|
||||
assert( pParse->apPhrase!=0 );
|
||||
assert( pParse->nPhrase>=2 );
|
||||
assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
|
||||
if( pPhrase->nTerm==0 ){
|
||||
fts5ExprPhraseFree(pPhrase);
|
||||
|
||||
@@ -1262,9 +1262,14 @@ static int zipfileFilter(
|
||||
zipfileCursorErr(pCsr, "zipfile() function requires an argument");
|
||||
return SQLITE_ERROR;
|
||||
}else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
|
||||
static const u8 aEmptyBlob = 0;
|
||||
const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
|
||||
int nBlob = sqlite3_value_bytes(argv[0]);
|
||||
assert( pTab->pFirstEntry==0 );
|
||||
if( aBlob==0 ){
|
||||
aBlob = &aEmptyBlob;
|
||||
nBlob = 0;
|
||||
}
|
||||
rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
|
||||
pCsr->pFreeEntry = pTab->pFirstEntry;
|
||||
pTab->pFirstEntry = pTab->pLastEntry = 0;
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# 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
|
||||
|
||||
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 Updates\sa\scomment\sand\san\sassert().
|
||||
D 2022-03-17T18:03:08.225
|
||||
C Do\snot\sallow\sthe\spush-down\soptimization\son\sthe\sright\stable\sof\sa\sRIGHT\sJOIN.
|
||||
D 2022-04-25T20:47:58.298
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -117,7 +117,7 @@ F ext/fts5/fts5Int.h 36fd4a05e6e6307e3bac359a589d5f090b903afe0e7ae15db84f0ff90c7
|
||||
F ext/fts5/fts5_aux.c f558e1fb9f0f86a4f7489e258c162e1f947de5ff2709087fbb465fddb7092f98
|
||||
F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5
|
||||
F ext/fts5/fts5_config.c 501e7d3566bc92766b0e11c0109a7c5a6146bc41144195459af5422f6c2078aa
|
||||
F ext/fts5/fts5_expr.c fcd0770d53028c2b53a15d0f53bf6d0e01b1bf3dd97630b9fedf0801f03aa3ec
|
||||
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_main.c 6078ae86d3b813753a4f1201054550aff21a3f660e97b30f200d2b1472874151
|
||||
@@ -339,7 +339,7 @@ F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e
|
||||
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546
|
||||
F ext/misc/zipfile.c c4e2d12b3544a380ce171a143dc2fdfe2fc76ae424ed4cf43ba4f74c6d0db444
|
||||
F ext/misc/zipfile.c 22afe121d1a5e318453b7cdbc0f5492161d2fd4fce548ff3605da05e89be7140
|
||||
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test c62904bd9526dcdc3496a21199aaf14ae191bbadbf67f076bf16be6b3f2115c2
|
||||
@@ -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 35a6ad081b374281f728b26264ef4f0b0e7888ccb5ace1843aed30ed99c2e1ca
|
||||
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,44 +486,44 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 006325f8844c65d885b3ba469b4c08d9dd0cd3e9ec481d5bcff621f224cb2302
|
||||
F src/alter.c 9395ece9850ad57c6fbb453aeb5185be4bae3b159c4b37611425c565124ee849
|
||||
F src/analyze.c 3a119baeb03053c154029877454d41bb8fd79d4d1eb583392f2289b3554a75bc
|
||||
F src/attach.c f26d400f3ffe2cdca01406bca70e5f58c5488bf165b4fc37c228136dfcf1b583
|
||||
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 ddc3cec12a39675e10066c008aac7925b26c74f78c46b849b2416ca45701a313
|
||||
F src/btree.c df695e953c2ce78ce4878ee5016751df9bc9a921dc0500a0f53ab3bb3196e505
|
||||
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
|
||||
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
|
||||
F src/build.c a0cc68fe8172c0a31b54576f9c6c0fe6f7c82b1b5e1387afdd6a5a13132bc131
|
||||
F src/build.c e8e776b52bc145cbf4e9fb88b99830083880fc2b174c2f96518fff15cbc72396
|
||||
F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1
|
||||
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 b5f1716b4d723db48254ee0f896e362cd029e865e05414139ea7f539f3884e1d
|
||||
F src/expr.c 3cdb00b6c15f815c94836e7b4474b675155d1279e64804f6ab5816188a9b05b6
|
||||
F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce
|
||||
F src/expr.c 5d4178f8462ca55a38cefcfcdf9635030607e3532649c96de471afafeca732c4
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 06e4ac33031b02dde7130c12e79cddf4dc5cfa72b23d8e63a3c26878fc9c1d3c
|
||||
F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e
|
||||
F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761
|
||||
F src/global.c 75deb064a71e1db60c8972a660a84f4e6d805c8f0463299a18e30ea527f4a650
|
||||
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 d9fd15b2bd030cb9bd3119b301dbdb2912f16fff76c6e3797296cfd1500faaf4
|
||||
F src/json.c 24fcd7f5f9080b04b89722c343010d390f85e55b2ab560046cb567c9dd640f62
|
||||
F src/insert.c 173845e5a6bac96ae937409e4f876b631f26b31dabb9df8fd0eb3b130b2bb3a7
|
||||
F src/json.c 7749b98c62f691697c7ee536b570c744c0583cab4a89200fdd0fc2aa8cc8cbd6
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c aa919a6a7884f8b34d7b791841b24d14b1b0ab43f45b3940f4851043b2855c0c
|
||||
F src/main.c 89dfd569b4fbcab65281b3c6d636b887b2cb23cbaa16f8c6b67062862144c927
|
||||
F src/malloc.c fec841aa0a0400a6f7d20706178a5d8e8219a6bf562b6fe712c17f6c26813266
|
||||
F src/loadext.c 2ecb1441f9b1c22e9e022ee0776e67d259facf34b56ba892b206f0a294ee6f8c
|
||||
F src/main.c 135858d2ede0b83d779e71b07ede9c1d6b6eaab7b77bc2a85729584152769faf
|
||||
F src/malloc.c a9127efdcef92d6934c6339ea9813075b90edc0ce2e5c723556381a3828fb720
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
|
||||
F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/mem5.c 5a3dbd8ac8a6501152a4fc1fcae9b0900c2d7eb0589c4ec7456fdde15725a26c
|
||||
F src/memdb.c c2dc88f97c410eb68a24468344b65526685e18354ddfd15906750c1eaf9dc2dd
|
||||
F src/memjournal.c 8bd50ae6d9c6d34b3a96cc3b4f567f9935dc358444d872ab48901a8c11ad82a6
|
||||
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
|
||||
@@ -536,33 +537,33 @@ F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab
|
||||
F src/os.h 26890f540b475598cd9881dcc68931377b8d429d3ea3e2eeb64470cde64199f8
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c f0dc85d439ece53120c4071c98876758ec24e6f713b67af3711af033c897091e
|
||||
F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
|
||||
F src/os_unix.c 1f71ec8c87621f75c9c5ea973f5e8ce2f1d23fe760c01ed2814fe4b98b639825
|
||||
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 0f02b27cdaa334441463153fff3ceb780fea006ab53ffd6ef566d4468f93e924
|
||||
F src/pcache.c 0aab73936341fad83d107cf62c6a7bc2d2d5fb9aaec8c3ce61e19fc18e4560fc
|
||||
F src/parse.y b86d56b446afb9c203d8354dc6c422818a62b4bbab52b76ab3da06d7b1d07e44
|
||||
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
|
||||
F src/pragma.c 9047ffb003d9434810ee81d7b1722d0093821622eb3217c962c3407bad949ce2
|
||||
F src/pragma.c d1aead03e8418ff586c7cfca344c50a914b8eb06abd841e8e91a982d823671da
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c a187dade741c1f09ae118fcbbf0302511807bfc0355880927d7152eb75b8260d
|
||||
F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32
|
||||
F src/prepare.c fd940149c691684e7c1073c3787a7170e44852b02d1275d2e30a5b58e89cfcaf
|
||||
F src/printf.c 512574910a45341c8ad244bd3d4939968ebdfde215645b676fff01cc46e90757
|
||||
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
|
||||
F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
|
||||
F src/resolve.c f72bb13359dd5a74d440df25f320dc2c1baff5cde4fc9f0d1bc3feba90b8932a
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c c366c05e48e836ea04f8ecefb9c1225745dc250c3f01bdb39e9cbb0dc25e3610
|
||||
F src/shell.c.in ec4b952f7d9c02919e8e8394be16bcbff55c105fd080895602d10fc8fa5328b8
|
||||
F src/select.c cc1a7581403fc074eee85283ba8d81de50a831ae175cb65a5751be00f621c0d5
|
||||
F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35
|
||||
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h a95cb9ed106e3d39e2118e4dcc15a14faec3fa50d0093425083d340d9dfd96e6
|
||||
F src/sqliteInt.h 2ce7d868630ccd70ffd4b15d46b59ccf7daf89198993b62ed6e4a165d3511280
|
||||
F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
|
||||
F src/sqliteInt.h 11cd60560cd14bb6eecd04d244faf4c1895417b97d89e2f50833f83c4611588d
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 1f6673991147bc2cecc08a40d22f9803b84c805b24b499fe727f392256f73474
|
||||
F src/test1.c 87fda59eea3ac1eba1baef37c1967565cb1b8d6d264649f2e57f252ca5989914
|
||||
F src/test1.c 1356984e97bff07e4a8cc3863e892f05b3348678a74783bb6f350b76316736f1
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159
|
||||
@@ -616,21 +617,21 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
|
||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 6661a9fa660ecbd3ac0df1acd2ec788b3a8122b4316022bcdaf476ea6754a8de
|
||||
F src/treeview.c 3fac35b0835998f34bc940cb07282c5c485caa1645135435fca07ba828c48463
|
||||
F src/trigger.c 5fc3cde35cc4de510be68bb2db4dcff0ce0e1625f43e28a0920be9a6f010cd3f
|
||||
F src/update.c f875b0d59da5c3055a0b2ac20560e1650229c6787e78de5e9836267b5cbb8359
|
||||
F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98
|
||||
F src/treeview.c 396c21e21c853ebc1830c194fa13f1161dbc76adad0b0a605172ddb78b3b4cdb
|
||||
F src/trigger.c 372ada38f667c6823a3db15749eb668338e65c793394e55a37e56a489f2d1b55
|
||||
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 b1830c6daf744473a732257652b6431ac18032f508a3e30ff3a1466fe5978559
|
||||
F src/vdbe.h a1d0e3b934e835e73edd146f2e7c4eadb711b5c9875c18159a57483fd78e550e
|
||||
F src/vdbeInt.h 8dd91427155a38ec06e9ecbde07e33f21bc02e101625191e7613f883e379a363
|
||||
F src/vdbeapi.c bc3812dff7c9e6497c87ae86962818a51f66f8d7a873e7ec02a22aa115b84799
|
||||
F src/vdbeaux.c 33c61dc3dbe920f262371ad2ba3e10277d27d8e35ee86075e2aef74113eae251
|
||||
F src/vdbe.c 9527ab7f71c5b0291e5ed7727f213f4d7f6e0a82af019da5b365fd5a0f56bb96
|
||||
F src/vdbe.h 07641758ca8b4f4c6d81ea667ea167c541e6ece21f5574da11e3d21ec37e2662
|
||||
F src/vdbeInt.h ef43f7fdc5fde29fc3fd29c506c12830f366178fdb4edbbf0cbc3dfbd1278b5f
|
||||
F src/vdbeapi.c 354c893f1500cf524cc45c32879b9c68893a28b77e3442c24668d6afe4236217
|
||||
F src/vdbeaux.c f406d8d8b461f260aeaa69d265c5d175ff0a9f84d6153c87975cdfbf9d681922
|
||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||
F src/vdbemem.c 57fceb4ed6aac960e9517c963dc0668189e8b7c8e6216d257030a2f5e9a583df
|
||||
F src/vdbemem.c 7189090b72baa025f945a1ac8c61ee420c645254476e8a191d555db76dfea5d4
|
||||
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
|
||||
@@ -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 bea45cd6ad295044fd2682ebc9c415acc9d83771809926cb0fa20f39df3376a4
|
||||
F src/whereInt.h 15d2975c3b4c193c78c26674400a840da8647fe1777ae3b026e2d15937b38a03
|
||||
F src/wherecode.c 555f598a9ddad81761f084710fdb4f8733fe31bc14cd6b19f8ca4274a7eaa04c
|
||||
F src/whereexpr.c 2a71f5491798460c9590317329234d332d9eb1717cba4f3403122189a75c465e
|
||||
F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f
|
||||
F src/where.c 43085b3a4ce2e56315fabb0b240a56e76667d9e03c79f287695bcae7b76152d5
|
||||
F src/whereInt.h 4db5a877a9d1f38b5c928c1c84297c07f30b9a3bc1f5f66214cf1a8ef90a0556
|
||||
F src/wherecode.c 55a33d9db1759970c30220904bcc628ba66a1ccb63b5437ef4642f7ea6267b03
|
||||
F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5
|
||||
F src/window.c 924e04fd6e0e113d4dba18b78d43fcb8e42b8ebffc8fc728da52cf3ab014cf3c
|
||||
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 21a951d1eb09120f3c1561af5bac30ed49be2d9dfcad039f71759c5d9e28a349
|
||||
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
|
||||
F test/corruptN.test 60b5a62944b4f0029ba07edaa5fd8e670539d6b0a8d99db26c068d435675cbfe
|
||||
F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576
|
||||
@@ -878,7 +879,7 @@ F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5e
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
|
||||
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
||||
F test/e_select.test c5425a423da06d0494119db8361ebfc6de302929f7546ca596d56224137e0360
|
||||
F test/e_select.test 9b7ca08975c5444844b35ee60e09f973787a9f3317719715e8e6669abdf6aba2
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4
|
||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||
@@ -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,7 +1111,7 @@ 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
|
||||
@@ -1140,19 +1141,24 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
|
||||
F test/join.test 25cf0ac11c3b81fedfd166f9062166bdb39dea92f5a7c16cacbf6dc1f7f67020
|
||||
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 3d51c4ae5f1f373a03164ca3c88d438f64bed7a2c01cf69810e2ca3d0e9071c8
|
||||
F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3
|
||||
F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c
|
||||
F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0
|
||||
F test/join8.test 8b1cc9592aa8f623fc2878353b16c81257591908de06d2a4916f7cbe3ca75ecd
|
||||
F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05
|
||||
F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a
|
||||
F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded
|
||||
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
|
||||
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
||||
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
|
||||
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
|
||||
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/json101.test d7c84854acafaf80f883e183ac4248ea2742615086c94a61a46ad7d7382ce123
|
||||
F test/json101.test 9d46b8e254c4e23306da175dd226d5c4f164db6b294bcea98e5dcd891ba48c91
|
||||
F test/json102.test 327e77275f338c028faefa2da5164daf6b142a165e3015ff2a6e4251ddc6a0ac
|
||||
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
|
||||
F test/json104.test a502dc01853aada95d721b3b275afbe2dc18fffdac1fea6e96fb20c13586bbb5
|
||||
@@ -1357,7 +1363,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 +1395,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 +1480,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
|
||||
@@ -1628,7 +1634,7 @@ F test/tkt3911.test 74cd324f3ba653040cc6d94cc4857b290d12d633
|
||||
F test/tkt3918.test ea78bf164e4d55cbde0d83c671ef6fbe930a0032
|
||||
F test/tkt3922.test f26be40ab4fe6c00795629bd2006d96e270d9b1a
|
||||
F test/tkt3929.test cdf67acf5aa936ec4ffead81db87f8a71fe40e59
|
||||
F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767
|
||||
F test/tkt3935.test 1ffcfffc148df51c8a01d1b3efae2d6c44cbeb0af1e0c5b88f4afe9a86d4ddb6
|
||||
F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08
|
||||
@@ -1681,7 +1687,7 @@ F test/update.test eb7f4eb172ce270e51bb67d7867521f33a63635bb671e261bbafccaef3bd6
|
||||
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
|
||||
F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041
|
||||
F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1
|
||||
F test/upfrom2.test 88d39cb755db5789541e645d4e2764abc697a56958f28a3f8451a0e9342bbd6b
|
||||
F test/upfrom2.test 66f3ebf721b3cebd922faee5c386bf244f816d416b57c000753ff51af62328a1
|
||||
F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0
|
||||
F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6
|
||||
F test/upsert1.test b0ae2f58680c5205b4bc1cdeed3c3d444057c506f6c44494fa3eac60731d68a2
|
||||
@@ -1711,7 +1717,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 82d5bb8fd3c0643102c1209e9ea353b168b7eb9c8db4406ab2ee2cbbdaead62c
|
||||
F test/vtab6.test fa609a4af96da30beceefa3cb624abe9be38c4747ab373d98179b24027d6b798
|
||||
F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c
|
||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||
@@ -1769,7 +1775,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 +1783,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 +1820,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
|
||||
@@ -1863,7 +1869,7 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c 1c5a14f6044193e42864c36de48359026fa2cdcf205a43cc1a31116101e27258
|
||||
F tool/lemon.c ea5c8589c7749e9bd32ba10432aeeed3c16e215de72a12ada2bc707884837149
|
||||
F tool/lempar.c 57478ea48420da05faa873c6d1616321caa5464644588c97fbe8e0ea04450748
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
@@ -1872,7 +1878,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl 3147e9dfc4ad774e94f80084789ebaada9da9b6e66ddab16438cfc07999b6047 x
|
||||
F tool/mkctimec.tcl ac96a74f5e6d9dac672d5229f79c583d3357a50e7d098e473e6b2ce2f8ae1704 x
|
||||
F tool/mkkeywordhash.c 35bfc41adacc4aa6ef6fca7fd0c63e0ec0534b78daf4d0cfdebe398216bbffc3
|
||||
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
|
||||
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
|
||||
@@ -1883,7 +1889,7 @@ F tool/mkshellc.tcl df5d249617f9cc94d5c48eb0401673eb3f31f383ecbc54e8a13ca3dd97e8
|
||||
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
|
||||
F tool/mksqlite3c.tcl 6f9e05facb51e906a1a7ef9f95274ef2ec91bf88b96732a9aed40647c605f419
|
||||
F tool/mksqlite3c.tcl eee7e9d9c58abb1045f6ed74ad95ad26e8d22be29fdc431deea5267fb3fa049c
|
||||
F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||
@@ -1945,8 +1951,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 0a922d141749cf3ef672f56449001e03f1a7e31822b66dcaf8550bb6e1b88cd3
|
||||
R 4575407b1b9d18654c677ea1217fbbaa
|
||||
P 10bf0e613809f71cc1a47ad40b517e2a66671212a6464e179c9d377e8b70d499
|
||||
R 8764866988e0da227134244ae6ff31d7
|
||||
U drh
|
||||
Z deec1c56a09d8f545a4f4b9f8cb9eb99
|
||||
Z bf16933ceb0da28b71dd4050f0adc6a6
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0c5be14aac07222b9cd2404ae485b6587f8cb2899e776bc45f1f1117bdd7e9b7
|
||||
05917bfa02a7b6678c147d10fb53f55532ab15fd5d82d925ae921ae3759f0115
|
||||
+9
-7
@@ -858,11 +858,10 @@ static void unmapColumnIdlistNames(
|
||||
Parse *pParse,
|
||||
const IdList *pIdList
|
||||
){
|
||||
if( pIdList ){
|
||||
int ii;
|
||||
for(ii=0; ii<pIdList->nId; ii++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
|
||||
}
|
||||
int ii;
|
||||
assert( pIdList!=0 );
|
||||
for(ii=0; ii<pIdList->nId; ii++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -890,8 +889,11 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
SrcList *pSrc = p->pSrc;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
|
||||
sqlite3WalkExpr(pWalker, pSrc->a[i].pOn);
|
||||
unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
|
||||
if( pSrc->a[i].fg.isUsing==0 ){
|
||||
sqlite3WalkExpr(pWalker, pSrc->a[i].u3.pOn);
|
||||
}else{
|
||||
unmapColumnIdlistNames(pParse, pSrc->a[i].u3.pUsing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -480,7 +480,11 @@ static int fixSelectCb(Walker *p, Select *pSelect){
|
||||
pItem->fg.fromDDL = 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort;
|
||||
if( pList->a[i].fg.isUsing==0
|
||||
&& sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
|
||||
){
|
||||
return WRC_Abort;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( pSelect->pWith ){
|
||||
|
||||
+60
-33
@@ -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;
|
||||
@@ -8742,7 +8744,6 @@ static int anotherValidCursor(BtCursor *pCur){
|
||||
*/
|
||||
static int balance(BtCursor *pCur){
|
||||
int rc = SQLITE_OK;
|
||||
const int nMin = pCur->pBt->usableSize * 2 / 3;
|
||||
u8 aBalanceQuickSpace[13];
|
||||
u8 *pFree = 0;
|
||||
|
||||
@@ -8754,7 +8755,11 @@ static int balance(BtCursor *pCur){
|
||||
MemPage *pPage = pCur->pPage;
|
||||
|
||||
if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
|
||||
if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
|
||||
if( pPage->nOverflow==0 && pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){
|
||||
/* No rebalance required as long as:
|
||||
** (1) There are no overflow cells
|
||||
** (2) The amount of free space on the page is less than 2/3rds of
|
||||
** the total usable space on the page. */
|
||||
break;
|
||||
}else if( (iPage = pCur->iPage)==0 ){
|
||||
if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
|
||||
@@ -9007,24 +9012,6 @@ int sqlite3BtreeInsert(
|
||||
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags );
|
||||
assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 );
|
||||
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
return pCur->skipNext;
|
||||
}
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
|
||||
&& pBt->inTransaction==TRANS_WRITE
|
||||
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
|
||||
/* Assert that the caller has been consistent. If this cursor was opened
|
||||
** expecting an index b-tree, then the caller should be inserting blob
|
||||
** keys with no associated data. If the cursor was opened expecting an
|
||||
** intkey table, the caller should be inserting integer keys with a
|
||||
** blob of associated data. */
|
||||
assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
||||
|
||||
/* Save the positions of any other cursors open on this table.
|
||||
**
|
||||
** In some cases, the call to btreeMoveto() below is a no-op. For
|
||||
@@ -9049,6 +9036,29 @@ int sqlite3BtreeInsert(
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that the cursor is not in the CURSOR_FAULT state and that it
|
||||
** points to a valid cell.
|
||||
*/
|
||||
if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
||||
testcase( pCur->eState==CURSOR_REQUIRESEEK );
|
||||
testcase( pCur->eState==CURSOR_FAULT );
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc && rc!=SQLITE_EMPTY ) return rc;
|
||||
}
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
|
||||
&& pBt->inTransaction==TRANS_WRITE
|
||||
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
|
||||
/* Assert that the caller has been consistent. If this cursor was opened
|
||||
** expecting an index b-tree, then the caller should be inserting blob
|
||||
** keys with no associated data. If the cursor was opened expecting an
|
||||
** intkey table, the caller should be inserting integer keys with a
|
||||
** blob of associated data. */
|
||||
assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
||||
|
||||
if( pCur->pKeyInfo==0 ){
|
||||
assert( pX->pKey==0 );
|
||||
/* If this is an insert into a table b-tree, invalidate any incrblob
|
||||
@@ -9137,14 +9147,14 @@ int sqlite3BtreeInsert(
|
||||
}
|
||||
}
|
||||
assert( pCur->eState==CURSOR_VALID
|
||||
|| (pCur->eState==CURSOR_INVALID && loc)
|
||||
|| CORRUPT_DB );
|
||||
|| (pCur->eState==CURSOR_INVALID && loc) );
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
|
||||
assert( pPage->leaf || !pPage->intKey );
|
||||
if( pPage->nFree<0 ){
|
||||
if( pCur->eState>CURSOR_INVALID ){
|
||||
if( NEVER(pCur->eState>CURSOR_INVALID) ){
|
||||
/* ^^^^^--- due to the moveToRoot() call above */
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = btreeComputeFreeSpace(pPage);
|
||||
@@ -9306,7 +9316,11 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
u32 nRem; /* Bytes of data still to copy */
|
||||
|
||||
getCellInfo(pSrc);
|
||||
aOut += putVarint32(aOut, pSrc->info.nPayload);
|
||||
if( pSrc->info.nPayload<0x80 ){
|
||||
*(aOut++) = pSrc->info.nPayload;
|
||||
}else{
|
||||
aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
|
||||
}
|
||||
if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
|
||||
nIn = pSrc->info.nLocal;
|
||||
aIn = pSrc->info.pPayload;
|
||||
@@ -9425,12 +9439,16 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
|
||||
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
|
||||
if( pCur->eState==CURSOR_REQUIRESEEK ){
|
||||
rc = btreeRestoreCursorPosition(pCur);
|
||||
assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
|
||||
if( rc || pCur->eState!=CURSOR_VALID ) return rc;
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
||||
rc = btreeRestoreCursorPosition(pCur);
|
||||
assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
|
||||
if( rc || pCur->eState!=CURSOR_VALID ) return rc;
|
||||
}else{
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
assert( CORRUPT_DB || pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
|
||||
iCellDepth = pCur->iPage;
|
||||
iCellIdx = pCur->ix;
|
||||
@@ -9462,7 +9480,8 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
bPreserve = (flags & BTREE_SAVEPOSITION)!=0;
|
||||
if( bPreserve ){
|
||||
if( !pPage->leaf
|
||||
|| (pPage->nFree+pPage->xCellSize(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|
||||
|| (pPage->nFree+pPage->xCellSize(pPage,pCell)+2) >
|
||||
(int)(pBt->usableSize*2/3)
|
||||
|| pPage->nCell==1 /* See dbfuzz001.test for a test case */
|
||||
){
|
||||
/* A b-tree rebalance will be required after deleting this entry.
|
||||
@@ -9558,7 +9577,15 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
** been corrected, so be it. Otherwise, after balancing the leaf node,
|
||||
** walk the cursor up the tree to the internal node and balance it as
|
||||
** well. */
|
||||
rc = balance(pCur);
|
||||
assert( pCur->pPage->nOverflow==0 );
|
||||
assert( pCur->pPage->nFree>=0 );
|
||||
if( pCur->pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){
|
||||
/* Optimization: If the free space is less than 2/3rds of the page,
|
||||
** then balance() will always be a no-op. No need to invoke it. */
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = balance(pCur);
|
||||
}
|
||||
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
|
||||
releasePageNotNull(pCur->pPage);
|
||||
pCur->iPage--;
|
||||
|
||||
+74
-41
@@ -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);
|
||||
@@ -214,7 +212,9 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
int iDb, i;
|
||||
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
||||
sqlite3VdbeJumpHere(v, 0);
|
||||
for(iDb=0; iDb<db->nDb; iDb++){
|
||||
assert( db->nDb>0 );
|
||||
iDb = 0;
|
||||
do{
|
||||
Schema *pSchema;
|
||||
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
@@ -229,7 +229,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
||||
VdbeComment((v,
|
||||
"usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
|
||||
}
|
||||
}while( ++iDb<db->nDb );
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
for(i=0; i<pParse->nVtabLock; i++){
|
||||
char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
||||
@@ -268,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);
|
||||
}
|
||||
}
|
||||
@@ -3057,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;
|
||||
@@ -3115,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;
|
||||
@@ -3128,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++;
|
||||
@@ -4670,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);
|
||||
@@ -4695,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);
|
||||
}
|
||||
|
||||
@@ -4708,7 +4706,7 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
||||
*/
|
||||
int sqlite3IdListIndex(IdList *pList, const char *zName){
|
||||
int i;
|
||||
if( pList==0 ) return -1;
|
||||
assert( pList!=0 );
|
||||
for(i=0; i<pList->nId; i++){
|
||||
if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
|
||||
}
|
||||
@@ -4911,8 +4909,11 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
|
||||
sqlite3DeleteTable(db, pItem->pTab);
|
||||
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
|
||||
if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn);
|
||||
if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing);
|
||||
if( pItem->fg.isUsing ){
|
||||
sqlite3IdListDelete(db, pItem->u3.pUsing);
|
||||
}else if( pItem->u3.pOn ){
|
||||
sqlite3ExprDelete(db, pItem->u3.pOn);
|
||||
}
|
||||
}
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
@@ -4940,14 +4941,13 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
Token *pDatabase, /* Name of the database containing pTable */
|
||||
Token *pAlias, /* The right-hand side of the AS subexpression */
|
||||
Select *pSubquery, /* A subquery used in place of a table name */
|
||||
Expr *pOn, /* The ON clause of a join */
|
||||
IdList *pUsing /* The USING clause of a join */
|
||||
OnOrUsing *pOnUsing /* Either the ON clause or the USING clause */
|
||||
){
|
||||
SrcItem *pItem;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( !p && (pOn || pUsing) ){
|
||||
if( !p && pOnUsing!=0 && (pOnUsing->pOn || pOnUsing->pUsing) ){
|
||||
sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
|
||||
(pOn ? "ON" : "USING")
|
||||
(pOnUsing->pOn ? "ON" : "USING")
|
||||
);
|
||||
goto append_from_error;
|
||||
}
|
||||
@@ -4967,15 +4967,27 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
if( pAlias->n ){
|
||||
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
||||
}
|
||||
pItem->pSelect = pSubquery;
|
||||
pItem->pOn = pOn;
|
||||
pItem->pUsing = pUsing;
|
||||
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 ){
|
||||
pItem->u3.pOn = 0;
|
||||
}else if( pOnUsing->pUsing ){
|
||||
pItem->fg.isUsing = 1;
|
||||
pItem->u3.pUsing = pOnUsing->pUsing;
|
||||
}else{
|
||||
pItem->u3.pOn = pOnUsing->pOn;
|
||||
}
|
||||
return p;
|
||||
|
||||
append_from_error:
|
||||
assert( p==0 );
|
||||
sqlite3ExprDelete(db, pOn);
|
||||
sqlite3IdListDelete(db, pUsing);
|
||||
sqlite3ClearOnOrUsing(db, pOnUsing);
|
||||
sqlite3SelectDelete(db, pSubquery);
|
||||
return 0;
|
||||
}
|
||||
@@ -5020,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;
|
||||
@@ -5056,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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -307,9 +307,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#ifdef SQLITE_ENABLE_RTREE
|
||||
"ENABLE_RTREE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SELECTTRACE
|
||||
"ENABLE_SELECTTRACE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SESSION
|
||||
"ENABLE_SESSION",
|
||||
#endif
|
||||
@@ -331,6 +328,9 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
"ENABLE_STMT_SCANSTATUS",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_TREETRACE
|
||||
"ENABLE_TREETRACE",
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
"ENABLE_UNKNOWN_SQL_FUNCTION",
|
||||
#endif
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -128,8 +128,8 @@ void sqlite3MaterializeView(
|
||||
assert( pFrom->nSrc==1 );
|
||||
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
||||
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
assert( pFrom->a[0].pOn==0 );
|
||||
assert( pFrom->a[0].pUsing==0 );
|
||||
assert( pFrom->a[0].fg.isUsing==0 );
|
||||
assert( pFrom->a[0].u3.pOn==0 );
|
||||
}
|
||||
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
|
||||
SF_IncludeHidden, pLimit);
|
||||
@@ -300,7 +300,6 @@ void sqlite3DeleteFrom(
|
||||
assert( db->mallocFailed==0 );
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
|
||||
/* Locate the table which we want to delete. This table has to be
|
||||
** put in an SrcList structure because some of the subroutines we
|
||||
** will be calling are designed to work with multiple tables and expect
|
||||
@@ -325,6 +324,14 @@ void sqlite3DeleteFrom(
|
||||
# define isView 0
|
||||
#endif
|
||||
|
||||
#if TREETRACE_ENABLED
|
||||
if( sqlite3TreeTrace & 0x10000 ){
|
||||
sqlite3TreeViewLine(0, "In sqlite3Delete() at %s:%d", __FILE__, __LINE__);
|
||||
sqlite3TreeViewDelete(pParse->pWith, pTabList, pWhere,
|
||||
pOrderBy, pLimit, pTrigger);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
if( !isView ){
|
||||
pWhere = sqlite3LimitWhere(
|
||||
|
||||
+77
-26
@@ -1249,6 +1249,18 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p ) sqlite3ExprDeleteNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear both elements of an OnOrUsing object
|
||||
*/
|
||||
void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
|
||||
if( p==0 ){
|
||||
/* Nothing to clear */
|
||||
}else if( p->pOn ){
|
||||
sqlite3ExprDeleteNN(db, p->pOn);
|
||||
}else if( p->pUsing ){
|
||||
sqlite3IdListDelete(db, p->pUsing);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Arrange to cause pExpr to be deleted when the pParse is deleted.
|
||||
@@ -1515,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1619,6 +1632,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
|
||||
pItem->eEName = pOldItem->eEName;
|
||||
pItem->done = 0;
|
||||
pItem->bNulls = pOldItem->bNulls;
|
||||
pItem->bUsed = pOldItem->bUsed;
|
||||
pItem->bSorterRef = pOldItem->bSorterRef;
|
||||
pItem->u = pOldItem->u;
|
||||
}
|
||||
@@ -1671,8 +1685,12 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
|
||||
pTab->nTabRef++;
|
||||
}
|
||||
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
|
||||
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
|
||||
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
|
||||
if( pOldItem->fg.isUsing ){
|
||||
assert( pNewItem->fg.isUsing );
|
||||
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
|
||||
}else{
|
||||
pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
|
||||
}
|
||||
pNewItem->colUsed = pOldItem->colUsed;
|
||||
}
|
||||
return pNew;
|
||||
@@ -1682,22 +1700,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;
|
||||
}
|
||||
@@ -2163,7 +2175,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;
|
||||
@@ -2284,6 +2296,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
|
||||
** double, 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().
|
||||
@@ -3165,9 +3213,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);
|
||||
}
|
||||
}
|
||||
@@ -3296,9 +3344,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;
|
||||
}
|
||||
@@ -3732,6 +3780,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;
|
||||
@@ -4484,16 +4533,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);
|
||||
@@ -5801,7 +5852,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
|
||||
|
||||
+13
-14
@@ -390,7 +390,6 @@ static void fkLookupParent(
|
||||
}else{
|
||||
int nCol = pFKey->nCol;
|
||||
int regTemp = sqlite3GetTempRange(pParse, nCol);
|
||||
int regRec = sqlite3GetTempReg(pParse);
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
@@ -429,12 +428,11 @@ static void fkLookupParent(
|
||||
}
|
||||
sqlite3VdbeGoto(v, iOk);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
|
||||
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, regTemp, nCol, 0,
|
||||
sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
|
||||
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regTemp, nCol);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
|
||||
}
|
||||
}
|
||||
@@ -536,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".
|
||||
**
|
||||
@@ -1191,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:
|
||||
@@ -1322,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
|
||||
);
|
||||
|
||||
+1
-1
@@ -347,7 +347,7 @@ int sqlite3PendingByte = 0x40000000;
|
||||
/*
|
||||
** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS.
|
||||
*/
|
||||
u32 sqlite3SelectTrace = 0;
|
||||
u32 sqlite3TreeTrace = 0;
|
||||
u32 sqlite3WhereTrace = 0;
|
||||
|
||||
#include "opcodes.h"
|
||||
|
||||
+15
-4
@@ -181,7 +181,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
||||
}
|
||||
|
||||
for(i=j=0; i<pTab->nCol; i++){
|
||||
assert( pTab->aCol[i].affinity!=0 );
|
||||
assert( pTab->aCol[i].affinity!=0 || sqlite3VdbeParser(v)->nErr>0 );
|
||||
if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
|
||||
zColAff[j++] = pTab->aCol[i].affinity;
|
||||
}
|
||||
@@ -765,6 +765,14 @@ void sqlite3Insert(
|
||||
#endif
|
||||
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
|
||||
|
||||
#if TREETRACE_ENABLED
|
||||
if( sqlite3TreeTrace & 0x10000 ){
|
||||
sqlite3TreeViewLine(0, "In sqlite3Insert() at %s:%d", __FILE__, __LINE__);
|
||||
sqlite3TreeViewInsert(pParse->pWith, pTabList, pColumn, pSelect, pList,
|
||||
onError, pUpsert, pTrigger);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If pTab is really a view, make sure it has been initialized.
|
||||
** ViewGetColumnNames() is a no-op if pTab is not a view.
|
||||
*/
|
||||
@@ -843,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 );
|
||||
@@ -1151,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 */
|
||||
|
||||
+34
-10
@@ -1119,14 +1119,15 @@ static JsonNode *jsonLookupStep(
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
testcase( nKey==0 );
|
||||
}else{
|
||||
zKey = zPath;
|
||||
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
|
||||
nKey = i;
|
||||
}
|
||||
if( nKey==0 ){
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
if( nKey==0 ){
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
j = 1;
|
||||
for(;;){
|
||||
@@ -2274,6 +2275,33 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Append an object label to the JSON Path being constructed
|
||||
** in pStr.
|
||||
*/
|
||||
static void jsonAppendObjectPathElement(
|
||||
JsonString *pStr,
|
||||
JsonNode *pNode
|
||||
){
|
||||
int jj, nn;
|
||||
const char *z;
|
||||
assert( pNode->eType==JSON_STRING );
|
||||
assert( pNode->jnFlags & JNODE_LABEL );
|
||||
assert( pNode->eU==1 );
|
||||
z = pNode->u.zJContent;
|
||||
nn = pNode->n;
|
||||
assert( nn>=2 );
|
||||
assert( z[0]=='"' );
|
||||
assert( z[nn-1]=='"' );
|
||||
if( nn>2 && sqlite3Isalpha(z[1]) ){
|
||||
for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
|
||||
if( jj==nn-1 ){
|
||||
z++;
|
||||
nn -= 2;
|
||||
}
|
||||
}
|
||||
jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
|
||||
}
|
||||
|
||||
/* Append the name of the path for element i to pStr
|
||||
*/
|
||||
static void jsonEachComputePath(
|
||||
@@ -2298,10 +2326,7 @@ static void jsonEachComputePath(
|
||||
}else{
|
||||
assert( pUp->eType==JSON_OBJECT );
|
||||
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
|
||||
assert( pNode->eType==JSON_STRING );
|
||||
assert( pNode->jnFlags & JNODE_LABEL );
|
||||
assert( pNode->eU==1 );
|
||||
jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
|
||||
jsonAppendObjectPathElement(pStr, pNode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2372,8 +2397,7 @@ static int jsonEachColumn(
|
||||
if( p->eType==JSON_ARRAY ){
|
||||
jsonPrintf(30, &x, "[%d]", p->iRowid);
|
||||
}else if( p->eType==JSON_OBJECT ){
|
||||
assert( pThis->eU==1 );
|
||||
jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
|
||||
jsonAppendObjectPathElement(&x, pThis);
|
||||
}
|
||||
}
|
||||
jsonResult(&x);
|
||||
|
||||
+9
-1
@@ -491,7 +491,15 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_vtab_distinct,
|
||||
sqlite3_vtab_in,
|
||||
sqlite3_vtab_in_first,
|
||||
sqlite3_vtab_in_next
|
||||
sqlite3_vtab_in_next,
|
||||
/* Version 3.39.0 and later */
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
sqlite3_deserialize,
|
||||
sqlite3_serialize
|
||||
#else
|
||||
0,
|
||||
0
|
||||
#endif
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
|
||||
+25
-6
@@ -4097,6 +4097,25 @@ int sqlite3_test_control(int op, ...){
|
||||
volatile int x = 0;
|
||||
assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
|
||||
rc = x;
|
||||
#if defined(SQLITE_DEBUG)
|
||||
/* Invoke these debugging routines so that the compiler does not
|
||||
** issue "defined but not used" warnings. */
|
||||
if( x==9999 ){
|
||||
sqlite3ShowExpr(0);
|
||||
sqlite3ShowExpr(0);
|
||||
sqlite3ShowExprList(0);
|
||||
sqlite3ShowIdList(0);
|
||||
sqlite3ShowSrcList(0);
|
||||
sqlite3ShowWith(0);
|
||||
sqlite3ShowUpsert(0);
|
||||
sqlite3ShowTriggerStep(0);
|
||||
sqlite3ShowTriggerStepList(0);
|
||||
sqlite3ShowTrigger(0);
|
||||
sqlite3ShowTriggerList(0);
|
||||
sqlite3ShowWindow(0);
|
||||
sqlite3ShowWinFunc(0);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4358,8 +4377,8 @@ int sqlite3_test_control(int op, ...){
|
||||
**
|
||||
** "ptr" is a pointer to a u32.
|
||||
**
|
||||
** op==0 Store the current sqlite3SelectTrace in *ptr
|
||||
** op==1 Set sqlite3SelectTrace to the value *ptr
|
||||
** op==0 Store the current sqlite3TreeTrace in *ptr
|
||||
** op==1 Set sqlite3TreeTrace to the value *ptr
|
||||
** op==3 Store the current sqlite3WhereTrace in *ptr
|
||||
** op==3 Set sqlite3WhereTrace to the value *ptr
|
||||
*/
|
||||
@@ -4367,10 +4386,10 @@ int sqlite3_test_control(int op, ...){
|
||||
int opTrace = va_arg(ap, int);
|
||||
u32 *ptr = va_arg(ap, u32*);
|
||||
switch( opTrace ){
|
||||
case 0: *ptr = sqlite3SelectTrace; break;
|
||||
case 1: sqlite3SelectTrace = *ptr; break;
|
||||
case 2: *ptr = sqlite3WhereTrace; break;
|
||||
case 3: sqlite3WhereTrace = *ptr; break;
|
||||
case 0: *ptr = sqlite3TreeTrace; break;
|
||||
case 1: sqlite3TreeTrace = *ptr; break;
|
||||
case 2: *ptr = sqlite3WhereTrace; break;
|
||||
case 3: sqlite3WhereTrace = *ptr; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+7
-2
@@ -420,8 +420,13 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
|
||||
*/
|
||||
static int memsys5Roundup(int n){
|
||||
int iFullSz;
|
||||
if( n > 0x40000000 ) return 0;
|
||||
for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
|
||||
if( n<=mem5.szAtom*2 ){
|
||||
if( n<=mem5.szAtom ) return mem5.szAtom;
|
||||
return mem5.szAtom*2;
|
||||
}
|
||||
if( n>0x40000000 ) return 0;
|
||||
for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
|
||||
if( (iFullSz/2)>=n ) return iFullSz/2;
|
||||
return iFullSz;
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -4910,11 +4910,17 @@ static int unixShmLock(
|
||||
int flags /* What to do with the lock */
|
||||
){
|
||||
unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
|
||||
unixShm *p = pDbFd->pShm; /* The shared memory being locked */
|
||||
unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
|
||||
unixShm *p; /* The shared memory being locked */
|
||||
unixShmNode *pShmNode; /* The underlying file iNode */
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
u16 mask; /* Mask of locks to take or release */
|
||||
int *aLock = pShmNode->aLock;
|
||||
int *aLock;
|
||||
|
||||
p = pDbFd->pShm;
|
||||
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
||||
pShmNode = p->pShmNode;
|
||||
if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
|
||||
aLock = pShmNode->aLock;
|
||||
|
||||
assert( pShmNode==pDbFd->pInode->pShmNode );
|
||||
assert( pShmNode->pInode==pDbFd->pInode );
|
||||
|
||||
+5
-1
@@ -4070,10 +4070,14 @@ static int winShmLock(
|
||||
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
|
||||
winShm *p = pDbFd->pShm; /* The shared memory being locked */
|
||||
winShm *pX; /* For looping over all siblings */
|
||||
winShmNode *pShmNode = p->pShmNode;
|
||||
winShmNode *pShmNode;
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
u16 mask; /* Mask of locks to take or release */
|
||||
|
||||
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
||||
pShmNode = p->pShmNode;
|
||||
if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
|
||||
|
||||
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
|
||||
assert( n>=1 );
|
||||
assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
|
||||
|
||||
+30
-31
@@ -570,7 +570,7 @@ selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). {
|
||||
Token x;
|
||||
x.n = 0;
|
||||
parserDoubleLinkSelect(pParse, pRhs);
|
||||
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
|
||||
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0);
|
||||
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
|
||||
}
|
||||
if( pRhs ){
|
||||
@@ -685,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
|
||||
@@ -695,33 +695,35 @@ stl_prefix(A) ::= seltablist(A) joinop(Y). {
|
||||
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y;
|
||||
}
|
||||
stl_prefix(A) ::= . {A = 0;}
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_opt(I)
|
||||
on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
|
||||
}
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_by(I) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
|
||||
sqlite3SrcListIndexedBy(pParse, A, &I);
|
||||
}
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
|
||||
on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
|
||||
sqlite3SrcListFuncArgs(pParse, A, E);
|
||||
}
|
||||
%ifndef SQLITE_OMIT_SUBQUERY
|
||||
seltablist(A) ::= stl_prefix(A) LP select(S) RP
|
||||
as(Z) on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) LP select(S) RP as(Z) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&N);
|
||||
}
|
||||
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP
|
||||
as(Z) on_opt(N) using_opt(U). {
|
||||
if( A==0 && Z.n==0 && N==0 && U==0 ){
|
||||
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). {
|
||||
if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){
|
||||
A = F;
|
||||
}else if( F->nSrc==1 ){
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N);
|
||||
if( A ){
|
||||
SrcItem *pNew = &A->a[A->nSrc-1];
|
||||
SrcItem *pOld = F->a;
|
||||
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;
|
||||
@@ -734,9 +736,9 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
|
||||
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,U);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N);
|
||||
}
|
||||
}
|
||||
%endif SQLITE_OMIT_SUBQUERY
|
||||
@@ -794,13 +796,14 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
|
||||
//
|
||||
// INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ...
|
||||
//
|
||||
// The [AND] and [OR] precedence marks in the rules for on_opt cause the
|
||||
// The [AND] and [OR] precedence marks in the rules for on_using cause the
|
||||
// ON in this context to always be interpreted as belonging to the JOIN.
|
||||
//
|
||||
%type on_opt {Expr*}
|
||||
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
|
||||
on_opt(N) ::= ON expr(E). {N = E;}
|
||||
on_opt(N) ::= . [OR] {N = 0;}
|
||||
%type on_using {OnOrUsing}
|
||||
//%destructor on_using {sqlite3ClearOnOrUsing(pParse->db, &$$);}
|
||||
on_using(N) ::= ON expr(E). {N.pOn = E; N.pUsing = 0;}
|
||||
on_using(N) ::= USING LP idlist(L) RP. {N.pOn = 0; N.pUsing = L;}
|
||||
on_using(N) ::= . [OR] {N.pOn = 0; N.pUsing = 0;}
|
||||
|
||||
// Note that this block abuses the Token type just a little. If there is
|
||||
// no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If
|
||||
@@ -813,15 +816,11 @@ on_opt(N) ::= . [OR] {N = 0;}
|
||||
// recognizes and interprets this as a special case.
|
||||
//
|
||||
%type indexed_opt {Token}
|
||||
%type indexed_by {Token}
|
||||
indexed_opt(A) ::= . {A.z=0; A.n=0;}
|
||||
indexed_opt(A) ::= INDEXED BY nm(X). {A = X;}
|
||||
indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;}
|
||||
|
||||
%type using_opt {IdList*}
|
||||
%destructor using_opt {sqlite3IdListDelete(pParse->db, $$);}
|
||||
using_opt(U) ::= USING LP idlist(L) RP. {U = L;}
|
||||
using_opt(U) ::= . {U = 0;}
|
||||
|
||||
indexed_opt(A) ::= indexed_by(A).
|
||||
indexed_by(A) ::= INDEXED BY nm(X). {A = X;}
|
||||
indexed_by(A) ::= NOT INDEXED. {A.z=0; A.n=1;}
|
||||
|
||||
%type orderby_opt {ExprList*}
|
||||
%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
@@ -1034,7 +1033,7 @@ idlist(A) ::= nm(Y).
|
||||
p->affExpr = 0;
|
||||
p->flags = EP_Leaf;
|
||||
ExprClearVVAProperties(p);
|
||||
p->iAgg = -1;
|
||||
/* p->iAgg = -1; // Not required */
|
||||
p->pLeft = p->pRight = 0;
|
||||
p->pAggInfo = 0;
|
||||
memset(&p->x, 0, sizeof(p->x));
|
||||
|
||||
+1
-2
@@ -551,8 +551,7 @@ void sqlite3PcacheDrop(PgHdr *p){
|
||||
** make it so.
|
||||
*/
|
||||
void sqlite3PcacheMakeDirty(PgHdr *p){
|
||||
assert( p->nRef>0 || p->pCache->bPurgeable==0 );
|
||||
testcase( p->nRef==0 );
|
||||
assert( p->nRef>0 );
|
||||
assert( sqlite3PcachePageSanity(p) );
|
||||
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
p->flags &= ~PGHDR_DONT_WRITE;
|
||||
|
||||
+3
-5
@@ -808,7 +808,7 @@ void sqlite3Pragma(
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
case PragTyp_INCREMENTAL_VACUUM: {
|
||||
int iLimit, addr;
|
||||
int iLimit = 0, addr;
|
||||
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
|
||||
iLimit = 0x7fffffff;
|
||||
}
|
||||
@@ -1496,7 +1496,6 @@ void sqlite3Pragma(
|
||||
HashElem *k; /* Loop counter: Next table in schema */
|
||||
int x; /* result variable */
|
||||
int regResult; /* 3 registers to hold a result row */
|
||||
int regKey; /* Register to hold key for checking the FK */
|
||||
int regRow; /* Registers to hold a row from pTab */
|
||||
int addrTop; /* Top of a loop checking foreign keys */
|
||||
int addrOk; /* Jump here if the key is OK */
|
||||
@@ -1504,7 +1503,6 @@ void sqlite3Pragma(
|
||||
|
||||
regResult = pParse->nMem+1;
|
||||
pParse->nMem += 4;
|
||||
regKey = ++pParse->nMem;
|
||||
regRow = ++pParse->nMem;
|
||||
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
|
||||
while( k ){
|
||||
@@ -1571,9 +1569,9 @@ void sqlite3Pragma(
|
||||
/* Generate code to query the parent index for a matching parent
|
||||
** key. If a match is found, jump to addrOk. */
|
||||
if( pIdx ){
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, regRow, pFK->nCol, 0,
|
||||
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regRow, pFK->nCol);
|
||||
VdbeCoverage(v);
|
||||
}else if( pParent ){
|
||||
int jmp = sqlite3VdbeCurrentAddr(v)+2;
|
||||
|
||||
+1
-1
@@ -389,7 +389,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
pDb = &db->aDb[iDb];
|
||||
}else
|
||||
if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
|
||||
if( rc==SQLITE_OK || ((db->flags&SQLITE_NoSchemaError) && rc!=SQLITE_NOMEM)){
|
||||
/* Hack: If the SQLITE_NoSchemaError flag is set, then consider
|
||||
** the schema loaded, even if errors (other than OOM) occurred. In
|
||||
** this situation the current sqlite3_prepare() operation will fail,
|
||||
|
||||
+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;
|
||||
|
||||
+141
-51
@@ -115,23 +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){
|
||||
if( pUsing ){
|
||||
int k;
|
||||
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".
|
||||
@@ -208,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
|
||||
@@ -253,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 */
|
||||
@@ -306,26 +314,64 @@ 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].bUsed = 1;
|
||||
hit = 1;
|
||||
}
|
||||
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;
|
||||
@@ -340,18 +386,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( nameInUsingClause(pItem->pUsing, zCol) ) 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++;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -364,9 +429,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;
|
||||
@@ -607,11 +670,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);
|
||||
@@ -624,6 +713,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
|
||||
@@ -643,16 +742,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 );
|
||||
|
||||
+431
-238
File diff suppressed because it is too large
Load Diff
+42
-20
@@ -2944,6 +2944,9 @@ static int str_in_array(const char *zStr, const char **azArray){
|
||||
** all opcodes that occur between the p2 jump destination and the opcode
|
||||
** itself by 2 spaces.
|
||||
**
|
||||
** * Do the previous for "Return" instructions for when P2 is positive.
|
||||
** See tag-20220407a in wherecode.c and vdbe.c.
|
||||
**
|
||||
** * For each "Goto", if the jump destination is earlier in the program
|
||||
** and ends on one of:
|
||||
** Yield SeekGt SeekLt RowSetRead Rewind
|
||||
@@ -2958,7 +2961,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp; /* Index of operation in p->aiIndent[] */
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
|
||||
"Return", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
|
||||
"Rewind", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
@@ -3016,7 +3020,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
p->aiIndent[iOp] = 0;
|
||||
p->nIndent = iOp+1;
|
||||
|
||||
if( str_in_array(zOp, azNext) ){
|
||||
if( str_in_array(zOp, azNext) && p2op>0 ){
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent
|
||||
@@ -3042,7 +3046,7 @@ static void explain_data_delete(ShellState *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Disable and restore .wheretrace and .selecttrace settings.
|
||||
** Disable and restore .wheretrace and .treetrace/.selecttrace settings.
|
||||
*/
|
||||
static unsigned int savedSelectTrace;
|
||||
static unsigned int savedWhereTrace;
|
||||
@@ -3346,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;
|
||||
@@ -3407,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);
|
||||
@@ -3426,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;
|
||||
@@ -3530,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);
|
||||
@@ -4997,8 +5008,10 @@ static void open_db(ShellState *p, int openFlags){
|
||||
sqlite3_dbdata_init(p->db, 0, 0);
|
||||
#endif
|
||||
#ifdef SQLITE_HAVE_ZLIB
|
||||
sqlite3_zipfile_init(p->db, 0, 0);
|
||||
sqlite3_sqlar_init(p->db, 0, 0);
|
||||
if( !p->bSafeModePersist ){
|
||||
sqlite3_zipfile_init(p->db, 0, 0);
|
||||
sqlite3_sqlar_init(p->db, 0, 0);
|
||||
}
|
||||
#endif
|
||||
sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
|
||||
shellAddSchemaName, 0, 0);
|
||||
@@ -7827,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
|
||||
@@ -7910,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
|
||||
@@ -7956,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"
|
||||
;
|
||||
@@ -7995,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);
|
||||
@@ -9589,9 +9605,10 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int bTxtMode = 0;
|
||||
int i;
|
||||
int eMode = 0;
|
||||
int bBOM = 0;
|
||||
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
|
||||
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
|
||||
unsigned char zBOM[4]; /* Byte-order mark to using if --bom is present */
|
||||
|
||||
zBOM[0] = 0;
|
||||
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
|
||||
if( c=='e' ){
|
||||
eMode = 'x';
|
||||
@@ -9604,7 +9621,10 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( z[0]=='-' ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-bom")==0 ){
|
||||
bBOM = 1;
|
||||
zBOM[0] = 0xef;
|
||||
zBOM[1] = 0xbb;
|
||||
zBOM[2] = 0xbf;
|
||||
zBOM[3] = 0;
|
||||
}else if( c!='e' && strcmp(z,"-x")==0 ){
|
||||
eMode = 'x'; /* spreadsheet */
|
||||
}else if( c!='e' && strcmp(z,"-e")==0 ){
|
||||
@@ -9673,7 +9693,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->out = stdout;
|
||||
rc = 1;
|
||||
}else{
|
||||
if( bBOM ) fprintf(p->out,"\357\273\277");
|
||||
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
|
||||
}
|
||||
#endif
|
||||
@@ -9686,7 +9706,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->out = stdout;
|
||||
rc = 1;
|
||||
} else {
|
||||
if( bBOM ) fprintf(p->out,"\357\273\277");
|
||||
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
|
||||
}
|
||||
}
|
||||
@@ -10107,7 +10127,9 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
|
||||
if( (c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0)
|
||||
|| (c=='t' && n==9 && strncmp(azArg[0], "treetrace", n)==0)
|
||||
){
|
||||
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
|
||||
}else
|
||||
|
||||
@@ -351,6 +351,11 @@ struct sqlite3_api_routines {
|
||||
int (*vtab_in)(sqlite3_index_info*,int,int);
|
||||
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
||||
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
||||
/* Version 3.39.0 and later */
|
||||
int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
||||
sqlite3_int64,sqlite3_int64,unsigned);
|
||||
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
||||
unsigned int);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -669,6 +674,10 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_vtab_in sqlite3_api->vtab_in
|
||||
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
||||
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
#define sqlite3_deserialize sqlite3_api->deserialize
|
||||
#define sqlite3_serialize sqlite3_api->serialize
|
||||
#endif
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+166
-79
@@ -939,8 +939,19 @@ typedef INT16_TYPE LogEst;
|
||||
/*
|
||||
** Round up a number to the next larger multiple of 8. This is used
|
||||
** to force 8-byte alignment on 64-bit architectures.
|
||||
**
|
||||
** ROUND8() always does the rounding, for any argument.
|
||||
**
|
||||
** ROUND8P() assumes that the argument is already an integer number of
|
||||
** pointers in size, and so it is a no-op on systems where the pointer
|
||||
** size is 8.
|
||||
*/
|
||||
#define ROUND8(x) (((x)+7)&~7)
|
||||
#if SQLITE_PTRSIZE==8
|
||||
# define ROUND8P(x) (x)
|
||||
#else
|
||||
# define ROUND8P(x) (((x)+7)&~7)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Round down to the nearest multiple of 8
|
||||
@@ -1003,22 +1014,23 @@ typedef INT16_TYPE LogEst;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
|
||||
** the Select query generator tracing logic is turned on.
|
||||
** TREETRACE_ENABLED will be either 1 or 0 depending on whether or not
|
||||
** the Abstract Syntax Tree tracing logic is turned on.
|
||||
*/
|
||||
#if !defined(SQLITE_AMALGAMATION)
|
||||
extern u32 sqlite3SelectTrace;
|
||||
extern u32 sqlite3TreeTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) \
|
||||
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE))
|
||||
# define SELECTTRACE_ENABLED 1
|
||||
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \
|
||||
|| defined(SQLITE_ENABLE_TREETRACE))
|
||||
# define TREETRACE_ENABLED 1
|
||||
# define SELECTTRACE(K,P,S,X) \
|
||||
if(sqlite3SelectTrace&(K)) \
|
||||
if(sqlite3TreeTrace&(K)) \
|
||||
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
|
||||
sqlite3DebugPrintf X
|
||||
#else
|
||||
# define SELECTTRACE(K,P,S,X)
|
||||
# define SELECTTRACE_ENABLED 0
|
||||
# define TREETRACE_ENABLED 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1179,6 +1191,7 @@ typedef struct Lookaside Lookaside;
|
||||
typedef struct LookasideSlot LookasideSlot;
|
||||
typedef struct Module Module;
|
||||
typedef struct NameContext NameContext;
|
||||
typedef struct OnOrUsing OnOrUsing;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct ParseCleanup ParseCleanup;
|
||||
typedef struct PreUpdate PreUpdate;
|
||||
@@ -1766,6 +1779,8 @@ struct sqlite3 {
|
||||
#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */
|
||||
#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 */
|
||||
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
|
||||
|
||||
/*
|
||||
@@ -2830,7 +2845,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 */
|
||||
@@ -2873,7 +2888,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 */
|
||||
@@ -2990,6 +3005,7 @@ struct ExprList {
|
||||
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 */
|
||||
union {
|
||||
struct { /* Used by any ExprList other than Parse.pConsExpr */
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
@@ -3024,13 +3040,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.
|
||||
@@ -3063,10 +3091,15 @@ struct SrcItem {
|
||||
unsigned fromDDL :1; /* Comes from sqlite_schema */
|
||||
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 */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
union {
|
||||
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
|
||||
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
|
||||
} u3;
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
|
||||
union {
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
@@ -3078,6 +3111,15 @@ struct SrcItem {
|
||||
} u2;
|
||||
};
|
||||
|
||||
/*
|
||||
** The OnOrUsing object represents either an ON clause or a USING clause.
|
||||
** It can never be both at the same time, but it can be neither.
|
||||
*/
|
||||
struct OnOrUsing {
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following structure describes the FROM clause of a SELECT statement.
|
||||
** Each table or subquery in the FROM clause is a separate element of
|
||||
@@ -3106,14 +3148,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()
|
||||
@@ -3136,7 +3179,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 */
|
||||
@@ -3332,6 +3375,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
|
||||
@@ -3543,6 +3589,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
|
||||
@@ -3715,20 +3762,20 @@ struct AuthContext {
|
||||
#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
* struct Trigger.
|
||||
*
|
||||
* Pointers to instances of struct Trigger are stored in two ways.
|
||||
* 1. In the "trigHash" hash table (part of the sqlite3* that represents the
|
||||
* database). This allows Trigger structures to be retrieved by name.
|
||||
* 2. All triggers associated with a single table form a linked list, using the
|
||||
* pNext member of struct Trigger. A pointer to the first element of the
|
||||
* linked list is stored as the "pTrigger" member of the associated
|
||||
* struct Table.
|
||||
*
|
||||
* The "step_list" member points to the first element of a linked list
|
||||
* containing the SQL statements specified as the trigger program.
|
||||
*/
|
||||
** Each trigger present in the database schema is stored as an instance of
|
||||
** struct Trigger.
|
||||
**
|
||||
** Pointers to instances of struct Trigger are stored in two ways.
|
||||
** 1. In the "trigHash" hash table (part of the sqlite3* that represents the
|
||||
** database). This allows Trigger structures to be retrieved by name.
|
||||
** 2. All triggers associated with a single table form a linked list, using the
|
||||
** pNext member of struct Trigger. A pointer to the first element of the
|
||||
** linked list is stored as the "pTrigger" member of the associated
|
||||
** struct Table.
|
||||
**
|
||||
** The "step_list" member points to the first element of a linked list
|
||||
** containing the SQL statements specified as the trigger program.
|
||||
*/
|
||||
struct Trigger {
|
||||
char *zName; /* The name of the trigger */
|
||||
char *table; /* The table or view to which the trigger applies */
|
||||
@@ -3755,43 +3802,48 @@ struct Trigger {
|
||||
#define TRIGGER_AFTER 2
|
||||
|
||||
/*
|
||||
* An instance of struct TriggerStep is used to store a single SQL statement
|
||||
* that is a part of a trigger-program.
|
||||
*
|
||||
* Instances of struct TriggerStep are stored in a singly linked list (linked
|
||||
* using the "pNext" member) referenced by the "step_list" member of the
|
||||
* associated struct Trigger instance. The first element of the linked list is
|
||||
* the first step of the trigger-program.
|
||||
*
|
||||
* The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
|
||||
* "SELECT" statement. The meanings of the other members is determined by the
|
||||
* value of "op" as follows:
|
||||
*
|
||||
* (op == TK_INSERT)
|
||||
* orconf -> stores the ON CONFLICT algorithm
|
||||
* pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
|
||||
* this stores a pointer to the SELECT statement. Otherwise NULL.
|
||||
* zTarget -> Dequoted name of the table to insert into.
|
||||
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
|
||||
* this stores values to be inserted. Otherwise NULL.
|
||||
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
||||
* statement, then this stores the column-names to be
|
||||
* inserted into.
|
||||
*
|
||||
* (op == TK_DELETE)
|
||||
* zTarget -> Dequoted name of the table to delete from.
|
||||
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
|
||||
* Otherwise NULL.
|
||||
*
|
||||
* (op == TK_UPDATE)
|
||||
* zTarget -> Dequoted name of the table to update.
|
||||
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
||||
* Otherwise NULL.
|
||||
* pExprList -> A list of the columns to update and the expressions to update
|
||||
* them to. See sqlite3Update() documentation of "pChanges"
|
||||
* argument.
|
||||
*
|
||||
*/
|
||||
** An instance of struct TriggerStep is used to store a single SQL statement
|
||||
** that is a part of a trigger-program.
|
||||
**
|
||||
** Instances of struct TriggerStep are stored in a singly linked list (linked
|
||||
** using the "pNext" member) referenced by the "step_list" member of the
|
||||
** associated struct Trigger instance. The first element of the linked list is
|
||||
** the first step of the trigger-program.
|
||||
**
|
||||
** The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
|
||||
** "SELECT" statement. The meanings of the other members is determined by the
|
||||
** value of "op" as follows:
|
||||
**
|
||||
** (op == TK_INSERT)
|
||||
** orconf -> stores the ON CONFLICT algorithm
|
||||
** pSelect -> The content to be inserted - either a SELECT statement or
|
||||
** a VALUES clause.
|
||||
** zTarget -> Dequoted name of the table to insert into.
|
||||
** pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
||||
** statement, then this stores the column-names to be
|
||||
** inserted into.
|
||||
** pUpsert -> The ON CONFLICT clauses for an Upsert
|
||||
**
|
||||
** (op == TK_DELETE)
|
||||
** zTarget -> Dequoted name of the table to delete from.
|
||||
** pWhere -> The WHERE clause of the DELETE statement if one is specified.
|
||||
** Otherwise NULL.
|
||||
**
|
||||
** (op == TK_UPDATE)
|
||||
** zTarget -> Dequoted name of the table to update.
|
||||
** pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
||||
** Otherwise NULL.
|
||||
** pExprList -> A list of the columns to update and the expressions to update
|
||||
** them to. See sqlite3Update() documentation of "pChanges"
|
||||
** argument.
|
||||
**
|
||||
** (op == TK_SELECT)
|
||||
** pSelect -> The SELECT statement
|
||||
**
|
||||
** (op == TK_RETURNING)
|
||||
** pExprList -> The list of expressions that follow the RETURNING keyword.
|
||||
**
|
||||
*/
|
||||
struct TriggerStep {
|
||||
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT,
|
||||
** or TK_RETURNING */
|
||||
@@ -4401,18 +4453,50 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_DEBUG)
|
||||
void sqlite3TreeViewLine(TreeView*, const char *zFormat, ...);
|
||||
void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
|
||||
void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
|
||||
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
|
||||
void sqlite3TreeViewBareIdList(TreeView*, const IdList*, const char*);
|
||||
void sqlite3TreeViewIdList(TreeView*, const IdList*, u8, const char*);
|
||||
void sqlite3TreeViewSrcList(TreeView*, const SrcList*);
|
||||
void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
|
||||
void sqlite3TreeViewWith(TreeView*, const With*, u8);
|
||||
void sqlite3TreeViewUpsert(TreeView*, const Upsert*, u8);
|
||||
void sqlite3TreeViewDelete(const With*, const SrcList*, const Expr*,
|
||||
const ExprList*,const Expr*, const Trigger*);
|
||||
void sqlite3TreeViewInsert(const With*, const SrcList*,
|
||||
const IdList*, const Select*, const ExprList*,
|
||||
int, const Upsert*, const Trigger*);
|
||||
void sqlite3TreeViewUpdate(const With*, const SrcList*, const ExprList*,
|
||||
const Expr*, int, const ExprList*, const Expr*,
|
||||
const Upsert*, const Trigger*);
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3TreeViewTriggerStep(TreeView*, const TriggerStep*, u8, u8);
|
||||
void sqlite3TreeViewTrigger(TreeView*, const Trigger*, u8, u8);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
|
||||
void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
|
||||
#endif
|
||||
void sqlite3ShowExpr(const Expr*);
|
||||
void sqlite3ShowExprList(const ExprList*);
|
||||
void sqlite3ShowIdList(const IdList*);
|
||||
void sqlite3ShowSrcList(const SrcList*);
|
||||
void sqlite3ShowSelect(const Select*);
|
||||
void sqlite3ShowWith(const With*);
|
||||
void sqlite3ShowUpsert(const Upsert*);
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3ShowTriggerStep(const TriggerStep*);
|
||||
void sqlite3ShowTriggerStepList(const TriggerStep*);
|
||||
void sqlite3ShowTrigger(const Trigger*);
|
||||
void sqlite3ShowTriggerList(const Trigger*);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3ShowWindow(const Window*);
|
||||
void sqlite3ShowWinFunc(const Window*);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void sqlite3SetString(char **, sqlite3*, const char*);
|
||||
void sqlite3ErrorMsg(Parse*, const char*, ...);
|
||||
@@ -4561,13 +4645,14 @@ SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
|
||||
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
|
||||
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
|
||||
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
||||
Token*, Select*, Expr*, IdList*);
|
||||
Token*, Select*, OnOrUsing*);
|
||||
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*);
|
||||
void sqlite3SrcListDelete(sqlite3*, SrcList*);
|
||||
Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
|
||||
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||
@@ -4667,6 +4752,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
|
||||
@@ -4764,7 +4850,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
|
||||
@@ -5110,7 +5197,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);
|
||||
|
||||
+1
-2
@@ -334,8 +334,7 @@ int sqlite3_db_status(
|
||||
|
||||
db->pnBytesFreed = &nByte;
|
||||
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
|
||||
sqlite3VdbeClearObject(db, pVdbe);
|
||||
sqlite3DbFree(db, pVdbe);
|
||||
sqlite3VdbeDelete(pVdbe);
|
||||
}
|
||||
db->pnBytesFreed = 0;
|
||||
|
||||
|
||||
+3
-3
@@ -8908,9 +8908,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
(char*)&sqlite3_sync_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_fullsync_count",
|
||||
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
|
||||
#if defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
Tcl_LinkVar(interp, "sqlite3_unsupported_selecttrace",
|
||||
(char*)&sqlite3SelectTrace, TCL_LINK_INT);
|
||||
#if defined(SQLITE_ENABLE_TREETRACE)
|
||||
Tcl_LinkVar(interp, "sqlite3_unsupported_treetrace",
|
||||
(char*)&sqlite3TreeTrace, TCL_LINK_INT);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
|
||||
Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
|
||||
|
||||
+1
-1
@@ -710,7 +710,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
}
|
||||
sqlite3DbFree(db, pParse->pVList);
|
||||
if( pParse->pVList ) sqlite3DbFreeNN(db, pParse->pVList);
|
||||
db->pParse = pParentParse;
|
||||
assert( nErr==0 || pParse->rc!=SQLITE_OK );
|
||||
return nErr;
|
||||
|
||||
+438
-50
@@ -24,33 +24,37 @@
|
||||
** Add a new subitem to the tree. The moreToFollow flag indicates that this
|
||||
** is not the last item in the tree.
|
||||
*/
|
||||
static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
|
||||
static void sqlite3TreeViewPush(TreeView **pp, u8 moreToFollow){
|
||||
TreeView *p = *pp;
|
||||
if( p==0 ){
|
||||
p = sqlite3_malloc64( sizeof(*p) );
|
||||
if( p==0 ) return 0;
|
||||
*pp = p = sqlite3_malloc64( sizeof(*p) );
|
||||
if( p==0 ) return;
|
||||
memset(p, 0, sizeof(*p));
|
||||
}else{
|
||||
p->iLevel++;
|
||||
}
|
||||
assert( moreToFollow==0 || moreToFollow==1 );
|
||||
if( p->iLevel<(int)sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finished with one layer of the tree
|
||||
*/
|
||||
static void sqlite3TreeViewPop(TreeView *p){
|
||||
static void sqlite3TreeViewPop(TreeView **pp){
|
||||
TreeView *p = *pp;
|
||||
if( p==0 ) return;
|
||||
p->iLevel--;
|
||||
if( p->iLevel<0 ) sqlite3_free(p);
|
||||
if( p->iLevel<0 ){
|
||||
sqlite3_free(p);
|
||||
*pp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a single line of output for the tree, with a prefix that contains
|
||||
** all the appropriate tree lines
|
||||
*/
|
||||
static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
||||
void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
int i;
|
||||
StrAccum acc;
|
||||
@@ -78,7 +82,7 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
||||
** Shorthand for starting a new tree item that consists of a single label
|
||||
*/
|
||||
static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
|
||||
p = sqlite3TreeViewPush(p, moreFollows);
|
||||
sqlite3TreeViewPush(&p, moreFollows);
|
||||
sqlite3TreeViewLine(p, "%s", zLabel);
|
||||
}
|
||||
|
||||
@@ -95,7 +99,7 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
|
||||
}
|
||||
if( pWith->nCte>0 ){
|
||||
pView = sqlite3TreeViewPush(pView, 1);
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
StrAccum x;
|
||||
char zLine[1000];
|
||||
@@ -111,6 +115,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);
|
||||
@@ -118,9 +126,9 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
|
||||
sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +137,7 @@ 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;
|
||||
@@ -140,11 +149,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");
|
||||
}
|
||||
@@ -154,12 +170,13 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
||||
if( pItem->pSelect ){
|
||||
assert( pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
||||
sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
|
||||
}
|
||||
if( pItem->fg.isTabFunc ){
|
||||
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,11 +190,11 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
sqlite3TreeViewLine(pView, "nil-SELECT");
|
||||
return;
|
||||
}
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
if( p->pWith ){
|
||||
sqlite3TreeViewWith(pView, p->pWith, 1);
|
||||
cnt = 1;
|
||||
sqlite3TreeViewPush(pView, 1);
|
||||
sqlite3TreeViewPush(&pView, 1);
|
||||
}
|
||||
do{
|
||||
if( p->selFlags & SF_WhereBegin ){
|
||||
@@ -191,7 +208,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
(int)p->nSelectRow
|
||||
);
|
||||
}
|
||||
if( cnt++ ) sqlite3TreeViewPop(pView);
|
||||
if( cnt++ ) sqlite3TreeViewPop(&pView);
|
||||
if( p->pPrior ){
|
||||
n = 1000;
|
||||
}else{
|
||||
@@ -214,24 +231,24 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWin ){
|
||||
Window *pX;
|
||||
pView = sqlite3TreeViewPush(pView, (n--)>0);
|
||||
sqlite3TreeViewPush(&pView, (n--)>0);
|
||||
sqlite3TreeViewLine(pView, "window-functions");
|
||||
for(pX=p->pWin; pX; pX=pX->pNextWin){
|
||||
sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
#endif
|
||||
if( p->pSrc && p->pSrc->nSrc ){
|
||||
pView = sqlite3TreeViewPush(pView, (n--)>0);
|
||||
sqlite3TreeViewPush(&pView, (n--)>0);
|
||||
sqlite3TreeViewLine(pView, "FROM");
|
||||
sqlite3TreeViewSrcList(pView, p->pSrc);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( p->pWhere ){
|
||||
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pWhere, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( p->pGroupBy ){
|
||||
sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
|
||||
@@ -239,7 +256,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
if( p->pHaving ){
|
||||
sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pHaving, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWinDefn ){
|
||||
@@ -248,7 +265,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
|
||||
sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
#endif
|
||||
if( p->pOrderBy ){
|
||||
@@ -260,9 +277,9 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
if( p->pLimit->pRight ){
|
||||
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( p->pPrior ){
|
||||
const char *zOp = "UNION";
|
||||
@@ -275,7 +292,7 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
}
|
||||
p = p->pPrior;
|
||||
}while( p!=0 );
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
@@ -291,24 +308,24 @@ void sqlite3TreeViewBound(
|
||||
switch( eBound ){
|
||||
case TK_UNBOUNDED: {
|
||||
sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
break;
|
||||
}
|
||||
case TK_CURRENT: {
|
||||
sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
break;
|
||||
}
|
||||
case TK_PRECEDING: {
|
||||
sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
|
||||
sqlite3TreeViewExpr(pView, pExpr, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
break;
|
||||
}
|
||||
case TK_FOLLOWING: {
|
||||
sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
|
||||
sqlite3TreeViewExpr(pView, pExpr, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -324,9 +341,9 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
if( pWin->pFilter ){
|
||||
sqlite3TreeViewItem(pView, "FILTER", 1);
|
||||
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
pView = sqlite3TreeViewPush(pView, more);
|
||||
sqlite3TreeViewPush(&pView, more);
|
||||
if( pWin->zName ){
|
||||
sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin);
|
||||
}else{
|
||||
@@ -337,9 +354,9 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
if( pWin->eFrmType ) nElement++;
|
||||
if( pWin->eExclude ) nElement++;
|
||||
if( pWin->zBase ){
|
||||
sqlite3TreeViewPush(pView, (--nElement)>0);
|
||||
sqlite3TreeViewPush(&pView, (--nElement)>0);
|
||||
sqlite3TreeViewLine(pView, "window: %s", pWin->zBase);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pWin->pPartition ){
|
||||
sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY");
|
||||
@@ -357,7 +374,7 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
sqlite3TreeViewItem(pView, zBuf, (--nElement)>0);
|
||||
sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
|
||||
sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pWin->eExclude ){
|
||||
char zBuf[30];
|
||||
@@ -372,11 +389,11 @@ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
||||
zExclude = zBuf;
|
||||
break;
|
||||
}
|
||||
sqlite3TreeViewPush(pView, 0);
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
@@ -385,11 +402,11 @@ 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){
|
||||
pView = sqlite3TreeViewPush(pView, more);
|
||||
sqlite3TreeViewPush(&pView, more);
|
||||
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
|
||||
pWin->pWFunc->zName, pWin->pWFunc->nArg);
|
||||
sqlite3TreeViewWindow(pView, pWin, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
@@ -400,10 +417,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
const char *zBinOp = 0; /* Binary operator */
|
||||
const char *zUniOp = 0; /* Unary operator */
|
||||
char zFlgs[200];
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
if( pExpr==0 ){
|
||||
sqlite3TreeViewLine(pView, "nil");
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
return;
|
||||
}
|
||||
if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
|
||||
@@ -412,7 +429,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");
|
||||
@@ -760,7 +777,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
|
||||
@@ -782,13 +799,23 @@ 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);
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
moreToFollow = 0;
|
||||
sqlite3TreeViewLine(pView, 0);
|
||||
if( zName ){
|
||||
fprintf(stdout, "AS %s ", zName);
|
||||
switch( pList->a[i].eEName ){
|
||||
default:
|
||||
fprintf(stdout, "AS %s ", zName);
|
||||
break;
|
||||
case ENAME_TAB:
|
||||
fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName);
|
||||
if( pList->a[i].bUsed==0 ) fprintf(stdout, "(unused) ");
|
||||
break;
|
||||
case ENAME_SPAN:
|
||||
fprintf(stdout, "SPAN(\"%s\") ", zName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j ){
|
||||
fprintf(stdout, "iOrderByCol=%d", j);
|
||||
@@ -798,7 +825,7 @@ void sqlite3TreeViewBareExprList(
|
||||
}
|
||||
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
|
||||
if( j || zName ){
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -809,9 +836,370 @@ void sqlite3TreeViewExprList(
|
||||
u8 moreToFollow,
|
||||
const char *zLabel
|
||||
){
|
||||
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
sqlite3TreeViewBareExprList(pView, pList, zLabel);
|
||||
sqlite3TreeViewPop(pView);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable explanation of an id-list.
|
||||
*/
|
||||
void sqlite3TreeViewBareIdList(
|
||||
TreeView *pView,
|
||||
const IdList *pList,
|
||||
const char *zLabel
|
||||
){
|
||||
if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
|
||||
if( pList==0 ){
|
||||
sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
|
||||
}else{
|
||||
int i;
|
||||
sqlite3TreeViewLine(pView, "%s", zLabel);
|
||||
for(i=0; i<pList->nId; i++){
|
||||
char *zName = pList->a[i].zName;
|
||||
int moreToFollow = i<pList->nId - 1;
|
||||
if( zName==0 ) zName = "(null)";
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
sqlite3TreeViewLine(pView, 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
void sqlite3TreeViewIdList(
|
||||
TreeView *pView,
|
||||
const IdList *pList,
|
||||
u8 moreToFollow,
|
||||
const char *zLabel
|
||||
){
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
sqlite3TreeViewBareIdList(pView, pList, zLabel);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable explanation of a list of Upsert objects
|
||||
*/
|
||||
void sqlite3TreeViewUpsert(
|
||||
TreeView *pView,
|
||||
const Upsert *pUpsert,
|
||||
u8 moreToFollow
|
||||
){
|
||||
if( pUpsert==0 ) return;
|
||||
sqlite3TreeViewPush(&pView, moreToFollow);
|
||||
while( pUpsert ){
|
||||
int n;
|
||||
sqlite3TreeViewPush(&pView, pUpsert->pNextUpsert!=0 || moreToFollow);
|
||||
sqlite3TreeViewLine(pView, "ON CONFLICT DO %s",
|
||||
pUpsert->isDoUpdate ? "UPDATE" : "NOTHING");
|
||||
n = (pUpsert->pUpsertSet!=0) + (pUpsert->pUpsertWhere!=0);
|
||||
sqlite3TreeViewExprList(pView, pUpsert->pUpsertTarget, (n--)>0, "TARGET");
|
||||
sqlite3TreeViewExprList(pView, pUpsert->pUpsertSet, (n--)>0, "SET");
|
||||
if( pUpsert->pUpsertWhere ){
|
||||
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, pUpsert->pUpsertWhere, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
pUpsert = pUpsert->pNextUpsert;
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable diagram of the data structure that go
|
||||
** into generating an DELETE statement.
|
||||
*/
|
||||
void sqlite3TreeViewDelete(
|
||||
const With *pWith,
|
||||
const SrcList *pTabList,
|
||||
const Expr *pWhere,
|
||||
const ExprList *pOrderBy,
|
||||
const Expr *pLimit,
|
||||
const Trigger *pTrigger
|
||||
){
|
||||
int n = 0;
|
||||
TreeView *pView = 0;
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
sqlite3TreeViewLine(pView, "DELETE");
|
||||
if( pWith ) n++;
|
||||
if( pTabList ) n++;
|
||||
if( pWhere ) n++;
|
||||
if( pOrderBy ) n++;
|
||||
if( pLimit ) n++;
|
||||
if( pTrigger ) n++;
|
||||
if( pWith ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewWith(pView, pWith, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pTabList ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "FROM");
|
||||
sqlite3TreeViewSrcList(pView, pTabList);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pWhere ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "WHERE");
|
||||
sqlite3TreeViewExpr(pView, pWhere, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pOrderBy ){
|
||||
sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY");
|
||||
}
|
||||
if( pLimit ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "LIMIT");
|
||||
sqlite3TreeViewExpr(pView, pLimit, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pTrigger ){
|
||||
sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable diagram of the data structure that go
|
||||
** into generating an INSERT statement.
|
||||
*/
|
||||
void sqlite3TreeViewInsert(
|
||||
const With *pWith,
|
||||
const SrcList *pTabList,
|
||||
const IdList *pColumnList,
|
||||
const Select *pSelect,
|
||||
const ExprList *pExprList,
|
||||
int onError,
|
||||
const Upsert *pUpsert,
|
||||
const Trigger *pTrigger
|
||||
){
|
||||
TreeView *pView = 0;
|
||||
int n = 0;
|
||||
const char *zLabel = "INSERT";
|
||||
switch( onError ){
|
||||
case OE_Replace: zLabel = "REPLACE"; break;
|
||||
case OE_Ignore: zLabel = "INSERT OR IGNORE"; break;
|
||||
case OE_Rollback: zLabel = "INSERT OR ROLLBACK"; break;
|
||||
case OE_Abort: zLabel = "INSERT OR ABORT"; break;
|
||||
case OE_Fail: zLabel = "INSERT OR FAIL"; break;
|
||||
}
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
sqlite3TreeViewLine(pView, zLabel);
|
||||
if( pWith ) n++;
|
||||
if( pTabList ) n++;
|
||||
if( pColumnList ) n++;
|
||||
if( pSelect ) n++;
|
||||
if( pExprList ) n++;
|
||||
if( pUpsert ) n++;
|
||||
if( pTrigger ) n++;
|
||||
if( pWith ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewWith(pView, pWith, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pTabList ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "INTO");
|
||||
sqlite3TreeViewSrcList(pView, pTabList);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pColumnList ){
|
||||
sqlite3TreeViewIdList(pView, pColumnList, (--n)>0, "COLUMNS");
|
||||
}
|
||||
if( pSelect ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "DATA-SOURCE");
|
||||
sqlite3TreeViewSelect(pView, pSelect, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pExprList ){
|
||||
sqlite3TreeViewExprList(pView, pExprList, (--n)>0, "VALUES");
|
||||
}
|
||||
if( pUpsert ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "UPSERT");
|
||||
sqlite3TreeViewUpsert(pView, pUpsert, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pTrigger ){
|
||||
sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a human-readable diagram of the data structure that go
|
||||
** into generating an UPDATE statement.
|
||||
*/
|
||||
void sqlite3TreeViewUpdate(
|
||||
const With *pWith,
|
||||
const SrcList *pTabList,
|
||||
const ExprList *pChanges,
|
||||
const Expr *pWhere,
|
||||
int onError,
|
||||
const ExprList *pOrderBy,
|
||||
const Expr *pLimit,
|
||||
const Upsert *pUpsert,
|
||||
const Trigger *pTrigger
|
||||
){
|
||||
int n = 0;
|
||||
TreeView *pView = 0;
|
||||
const char *zLabel = "UPDATE";
|
||||
switch( onError ){
|
||||
case OE_Replace: zLabel = "UPDATE OR REPLACE"; break;
|
||||
case OE_Ignore: zLabel = "UPDATE OR IGNORE"; break;
|
||||
case OE_Rollback: zLabel = "UPDATE OR ROLLBACK"; break;
|
||||
case OE_Abort: zLabel = "UPDATE OR ABORT"; break;
|
||||
case OE_Fail: zLabel = "UPDATE OR FAIL"; break;
|
||||
}
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
sqlite3TreeViewLine(pView, zLabel);
|
||||
if( pWith ) n++;
|
||||
if( pTabList ) n++;
|
||||
if( pChanges ) n++;
|
||||
if( pWhere ) n++;
|
||||
if( pOrderBy ) n++;
|
||||
if( pLimit ) n++;
|
||||
if( pUpsert ) n++;
|
||||
if( pTrigger ) n++;
|
||||
if( pWith ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewWith(pView, pWith, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pTabList ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "FROM");
|
||||
sqlite3TreeViewSrcList(pView, pTabList);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pChanges ){
|
||||
sqlite3TreeViewExprList(pView, pChanges, (--n)>0, "SET");
|
||||
}
|
||||
if( pWhere ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "WHERE");
|
||||
sqlite3TreeViewExpr(pView, pWhere, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pOrderBy ){
|
||||
sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY");
|
||||
}
|
||||
if( pLimit ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "LIMIT");
|
||||
sqlite3TreeViewExpr(pView, pLimit, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pUpsert ){
|
||||
sqlite3TreeViewPush(&pView, (--n)>0);
|
||||
sqlite3TreeViewLine(pView, "UPSERT");
|
||||
sqlite3TreeViewUpsert(pView, pUpsert, 0);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
if( pTrigger ){
|
||||
sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
|
||||
}
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/*
|
||||
** Show a human-readable graph of a TriggerStep
|
||||
*/
|
||||
void sqlite3TreeViewTriggerStep(
|
||||
TreeView *pView,
|
||||
const TriggerStep *pStep,
|
||||
u8 moreToFollow,
|
||||
u8 showFullList
|
||||
){
|
||||
int cnt = 0;
|
||||
if( pStep==0 ) return;
|
||||
sqlite3TreeViewPush(&pView,
|
||||
moreToFollow || (showFullList && pStep->pNext!=0));
|
||||
do{
|
||||
if( cnt++ && pStep->pNext==0 ){
|
||||
sqlite3TreeViewPop(&pView);
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
}
|
||||
sqlite3TreeViewLine(pView, "%s", pStep->zSpan ? pStep->zSpan : "RETURNING");
|
||||
}while( showFullList && (pStep = pStep->pNext)!=0 );
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
|
||||
/*
|
||||
** Show a human-readable graph of a Trigger
|
||||
*/
|
||||
void sqlite3TreeViewTrigger(
|
||||
TreeView *pView,
|
||||
const Trigger *pTrigger,
|
||||
u8 moreToFollow,
|
||||
u8 showFullList
|
||||
){
|
||||
int cnt = 0;
|
||||
if( pTrigger==0 ) return;
|
||||
sqlite3TreeViewPush(&pView,
|
||||
moreToFollow || (showFullList && pTrigger->pNext!=0));
|
||||
do{
|
||||
if( cnt++ && pTrigger->pNext==0 ){
|
||||
sqlite3TreeViewPop(&pView);
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
}
|
||||
sqlite3TreeViewLine(pView, "TRIGGER %s", pTrigger->zName);
|
||||
sqlite3TreeViewPush(&pView, 0);
|
||||
sqlite3TreeViewTriggerStep(pView, pTrigger->step_list, 0, 1);
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}while( showFullList && (pTrigger = pTrigger->pNext)!=0 );
|
||||
sqlite3TreeViewPop(&pView);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
|
||||
|
||||
/*
|
||||
** These simplified versions of the tree-view routines omit unnecessary
|
||||
** parameters. These variants are intended to be used from a symbolic
|
||||
** debugger, such as "gdb", during interactive debugging sessions.
|
||||
**
|
||||
** This routines are given external linkage so that they will always be
|
||||
** accessible to the debugging, and to avoid warnings about unused
|
||||
** functions. But these routines only exist in debugging builds, so they
|
||||
** do not contaminate the interface.
|
||||
*/
|
||||
void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
|
||||
void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
|
||||
void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
|
||||
void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
|
||||
void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); }
|
||||
void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); }
|
||||
void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); }
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3ShowTriggerStep(const TriggerStep *p){
|
||||
sqlite3TreeViewTriggerStep(0,p,0,0);
|
||||
}
|
||||
void sqlite3ShowTriggerStepList(const TriggerStep *p){
|
||||
sqlite3TreeViewTriggerStep(0,p,0,1);
|
||||
}
|
||||
void sqlite3ShowTrigger(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,0); }
|
||||
void sqlite3ShowTriggerList(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,1);}
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3ShowWindow(const Window *p){ sqlite3TreeViewWindow(0,p,0); }
|
||||
void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(0,p,0); }
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
+29
-7
@@ -52,9 +52,7 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
Trigger *pList; /* List of triggers to return */
|
||||
HashElem *p; /* Loop variable for TEMP triggers */
|
||||
|
||||
if( pParse->disableTriggers ){
|
||||
return 0;
|
||||
}
|
||||
assert( pParse->disableTriggers==0 );
|
||||
pTmpSchema = pParse->db->aDb[1].pSchema;
|
||||
p = sqliteHashFirst(&pTmpSchema->trigHash);
|
||||
pList = pTab->pTrigger;
|
||||
@@ -67,11 +65,10 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
){
|
||||
pTrig->pNext = pList;
|
||||
pList = pTrig;
|
||||
}else if( pTrig->op==TK_RETURNING
|
||||
}else if( pTrig->op==TK_RETURNING ){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
&& pParse->db->pVtabCtx==0
|
||||
assert( pParse->db->pVtabCtx==0 );
|
||||
#endif
|
||||
){
|
||||
assert( pParse->bReturning );
|
||||
assert( &(pParse->u1.pReturning->retTrig) == pTrig );
|
||||
pTrig->table = pTab->zName;
|
||||
@@ -730,13 +727,22 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if any TEMP triggers exist
|
||||
*/
|
||||
static int tempTriggersExist(sqlite3 *db){
|
||||
if( NEVER(db->aDb[1].pSchema==0) ) return 0;
|
||||
if( sqliteHashFirst(&db->aDb[1].pSchema->trigHash)==0 ) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a list of all triggers on table pTab if there exists at least
|
||||
** one trigger that must be fired when an operation of type 'op' is
|
||||
** performed on the table, and, if that operation is an UPDATE, if at
|
||||
** least one of the columns in pChanges is being modified.
|
||||
*/
|
||||
Trigger *sqlite3TriggersExist(
|
||||
static SQLITE_NOINLINE Trigger *triggersReallyExist(
|
||||
Parse *pParse, /* Parse context */
|
||||
Table *pTab, /* The table the contains the triggers */
|
||||
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
||||
@@ -799,6 +805,22 @@ exit_triggers_exist:
|
||||
}
|
||||
return (mask ? pList : 0);
|
||||
}
|
||||
Trigger *sqlite3TriggersExist(
|
||||
Parse *pParse, /* Parse context */
|
||||
Table *pTab, /* The table the contains the triggers */
|
||||
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
||||
ExprList *pChanges, /* Columns that change in an UPDATE statement */
|
||||
int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
|
||||
){
|
||||
assert( pTab!=0 );
|
||||
if( (pTab->pTrigger==0 && !tempTriggersExist(pParse->db))
|
||||
|| pParse->disableTriggers
|
||||
){
|
||||
if( pMask ) *pMask = 0;
|
||||
return 0;
|
||||
}
|
||||
return triggersReallyExist(pParse,pTab,op,pChanges,pMask);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the pStep->zTarget string into a SrcList and return a pointer
|
||||
|
||||
@@ -376,6 +376,14 @@ void sqlite3Update(
|
||||
# define isView 0
|
||||
#endif
|
||||
|
||||
#if TREETRACE_ENABLED
|
||||
if( sqlite3TreeTrace & 0x10000 ){
|
||||
sqlite3TreeViewLine(0, "In sqlite3Update() at %s:%d", __FILE__, __LINE__);
|
||||
sqlite3TreeViewUpdate(pParse->pWith, pTabList, pChanges, pWhere,
|
||||
onError, pOrderBy, pLimit, pUpsert, pTrigger);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there was a FROM clause, set nChangeFrom to the number of expressions
|
||||
** in the change-list. Otherwise, set it to 0. There cannot be a FROM
|
||||
** clause if this function is being called to generate code for part of
|
||||
|
||||
+212
-138
@@ -266,12 +266,12 @@ static VdbeCursor *allocateCursor(
|
||||
int nByte;
|
||||
VdbeCursor *pCx = 0;
|
||||
nByte =
|
||||
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
||||
ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
||||
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
|
||||
|
||||
assert( iCur>=0 && iCur<p->nCursor );
|
||||
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
|
||||
sqlite3VdbeFreeCursorNN(p, p->apCsr[iCur]);
|
||||
p->apCsr[iCur] = 0;
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ static VdbeCursor *allocateCursor(
|
||||
pCx->aOffset = &pCx->aType[nField];
|
||||
if( eCurType==CURTYPE_BTREE ){
|
||||
pCx->uc.pCursor = (BtCursor*)
|
||||
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
||||
&pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
||||
sqlite3BtreeCursorZero(pCx->uc.pCursor);
|
||||
}
|
||||
return pCx;
|
||||
@@ -740,7 +740,7 @@ int sqlite3VdbeExec(
|
||||
#endif
|
||||
/*** INSERT STACK UNION HERE ***/
|
||||
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
|
||||
assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */
|
||||
sqlite3VdbeEnter(p);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
@@ -983,28 +983,39 @@ 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 * P3 * *
|
||||
/* 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.
|
||||
**
|
||||
** 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.
|
||||
** 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
|
||||
** formatter in the CLI will indent all opcodes from the P2 opcode up
|
||||
** to be not including the current Return. P2 should be the first opcode
|
||||
** 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1027,7 +1038,12 @@ 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:
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1129,11 +1145,10 @@ case OP_Halt: {
|
||||
VdbeFrame *pFrame;
|
||||
int pcx;
|
||||
|
||||
pcx = (int)(pOp - aOp);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
|
||||
#endif
|
||||
if( pOp->p1==SQLITE_OK && p->pFrame ){
|
||||
if( p->pFrame && pOp->p1==SQLITE_OK ){
|
||||
/* Halt the sub-program. Return control to the parent frame. */
|
||||
pFrame = p->pFrame;
|
||||
p->pFrame = pFrame->pParent;
|
||||
@@ -1155,7 +1170,6 @@ case OP_Halt: {
|
||||
}
|
||||
p->rc = pOp->p1;
|
||||
p->errorAction = (u8)pOp->p2;
|
||||
p->pc = pcx;
|
||||
assert( pOp->p5<=4 );
|
||||
if( p->rc ){
|
||||
if( pOp->p5 ){
|
||||
@@ -1172,6 +1186,7 @@ case OP_Halt: {
|
||||
}else{
|
||||
sqlite3VdbeError(p, "%s", pOp->p4.z);
|
||||
}
|
||||
pcx = (int)(pOp - aOp);
|
||||
sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
|
||||
}
|
||||
rc = sqlite3VdbeHalt(p);
|
||||
@@ -1186,22 +1201,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;
|
||||
@@ -1308,6 +1312,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
|
||||
**
|
||||
@@ -1320,6 +1346,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;
|
||||
@@ -1549,45 +1576,32 @@ case OP_FkCheck: {
|
||||
** the result row.
|
||||
*/
|
||||
case OP_ResultRow: {
|
||||
Mem *pMem;
|
||||
int i;
|
||||
assert( p->nResColumn==pOp->p2 );
|
||||
assert( pOp->p1>0 || CORRUPT_DB );
|
||||
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
|
||||
|
||||
/* Invalidate all ephemeral cursor row caches */
|
||||
p->cacheCtr = (p->cacheCtr + 2)|1;
|
||||
|
||||
/* Make sure the results of the current row are \000 terminated
|
||||
** and have an assigned type. The results are de-ephemeralized as
|
||||
** a side effect.
|
||||
*/
|
||||
pMem = p->pResultSet = &aMem[pOp->p1];
|
||||
for(i=0; i<pOp->p2; i++){
|
||||
assert( memIsValid(&pMem[i]) );
|
||||
Deephemeralize(&pMem[i]);
|
||||
assert( (pMem[i].flags & MEM_Ephem)==0
|
||||
|| (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
|
||||
sqlite3VdbeMemNulTerminate(&pMem[i]);
|
||||
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
||||
p->pResultSet = &aMem[pOp->p1];
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* The registers in the result will not be used again when the
|
||||
** prepared statement restarts. This is because sqlite3_column()
|
||||
** APIs might have caused type conversions of made other changes to
|
||||
** the register values. Therefore, we can go ahead and break any
|
||||
** OP_SCopy dependencies. */
|
||||
pMem[i].pScopyFrom = 0;
|
||||
#endif
|
||||
{
|
||||
Mem *pMem = p->pResultSet;
|
||||
int i;
|
||||
for(i=0; i<pOp->p2; i++){
|
||||
assert( memIsValid(&pMem[i]) );
|
||||
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
||||
/* The registers in the result will not be used again when the
|
||||
** prepared statement restarts. This is because sqlite3_column()
|
||||
** APIs might have caused type conversions of made other changes to
|
||||
** the register values. Therefore, we can go ahead and break any
|
||||
** OP_SCopy dependencies. */
|
||||
pMem[i].pScopyFrom = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
|
||||
if( db->mTrace & SQLITE_TRACE_ROW ){
|
||||
db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Return SQLITE_ROW
|
||||
*/
|
||||
p->pc = (int)(pOp - aOp) + 1;
|
||||
rc = SQLITE_ROW;
|
||||
goto vdbe_return;
|
||||
@@ -2101,23 +2115,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB );
|
||||
/* Common case of comparison of two integers */
|
||||
if( pIn3->u.i > pIn1->u.i ){
|
||||
iCompare = +1;
|
||||
if( sqlite3aGTb[pOp->opcode] ){
|
||||
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
iCompare = +1;
|
||||
}else if( pIn3->u.i < pIn1->u.i ){
|
||||
iCompare = -1;
|
||||
if( sqlite3aLTb[pOp->opcode] ){
|
||||
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
iCompare = -1;
|
||||
}else{
|
||||
iCompare = 0;
|
||||
if( sqlite3aEQb[pOp->opcode] ){
|
||||
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
iCompare = 0;
|
||||
}
|
||||
VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
break;
|
||||
@@ -2144,11 +2158,11 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** then the result is always NULL.
|
||||
** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
|
||||
*/
|
||||
iCompare = 1; /* Operands are not equal */
|
||||
VdbeBranchTaken(2,3);
|
||||
if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
||||
goto jump_to_p2;
|
||||
}
|
||||
iCompare = 1; /* Operands are not equal */
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
@@ -2254,9 +2268,8 @@ case OP_ElseEq: { /* same as TK_ESCAPE, jump */
|
||||
** Set the permutation used by the OP_Compare operator in the next
|
||||
** instruction. The permutation is stored in the P4 operand.
|
||||
**
|
||||
** The permutation is only valid until the next OP_Compare that has
|
||||
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
||||
** occur immediately prior to the OP_Compare.
|
||||
** The permutation is only valid for the next opcode which must be
|
||||
** an OP_Compare that has the OPFLAG_PERMUTE bit set in P5.
|
||||
**
|
||||
** The first integer in the P4 integer array is the length of the array
|
||||
** and does not become part of the permutation.
|
||||
@@ -2288,6 +2301,8 @@ case OP_Permutation: {
|
||||
** The comparison is a sort comparison, so NULLs compare equal,
|
||||
** NULLs are less than numbers, numbers are less than strings,
|
||||
** and strings are less than blobs.
|
||||
**
|
||||
** This opcode must be immediately followed by an OP_Jump opcode.
|
||||
*/
|
||||
case OP_Compare: {
|
||||
int n;
|
||||
@@ -2346,6 +2361,7 @@ case OP_Compare: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert( pOp[1].opcode==OP_Jump );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2354,8 +2370,11 @@ case OP_Compare: {
|
||||
** Jump to the instruction at address P1, P2, or P3 depending on whether
|
||||
** in the most recent OP_Compare instruction the P1 vector was less than
|
||||
** equal to, or greater than the P2 vector, respectively.
|
||||
**
|
||||
** This opcode must immediately follow an OP_Compare opcode.
|
||||
*/
|
||||
case OP_Jump: { /* jump */
|
||||
assert( pOp>aOp && pOp[-1].opcode==OP_Compare );
|
||||
if( iCompare<0 ){
|
||||
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
|
||||
}else if( iCompare==0 ){
|
||||
@@ -2660,7 +2679,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
|
||||
@@ -2702,7 +2721,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 );
|
||||
@@ -2711,10 +2731,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) );
|
||||
@@ -2752,7 +2771,11 @@ op_column_restart:
|
||||
assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */
|
||||
}
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
|
||||
if( (aOffset[0] = pC->aRow[0])<0x80 ){
|
||||
pC->iHdrOffset = 1;
|
||||
}else{
|
||||
pC->iHdrOffset = sqlite3GetVarint32(pC->aRow, aOffset);
|
||||
}
|
||||
pC->nHdrParsed = 0;
|
||||
|
||||
if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/
|
||||
@@ -3387,18 +3410,60 @@ case OP_MakeRecord: {
|
||||
zPayload = zHdr + nHdr;
|
||||
|
||||
/* Write the record */
|
||||
zHdr += putVarint32(zHdr, nHdr);
|
||||
if( nHdr<0x80 ){
|
||||
*(zHdr++) = nHdr;
|
||||
}else{
|
||||
zHdr += sqlite3PutVarint(zHdr,nHdr);
|
||||
}
|
||||
assert( pData0<=pLast );
|
||||
pRec = pData0;
|
||||
do{
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
serial_type = pRec->uTemp;
|
||||
/* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
|
||||
** additional varints, one per column. */
|
||||
zHdr += putVarint32(zHdr, serial_type); /* serial type */
|
||||
/* EVIDENCE-OF: R-64536-51728 The values for each column in the record
|
||||
** additional varints, one per column.
|
||||
** EVIDENCE-OF: R-64536-51728 The values for each column in the record
|
||||
** immediately follow the header. */
|
||||
zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */
|
||||
}while( (++pRec)<=pLast );
|
||||
if( serial_type<=7 ){
|
||||
*(zHdr++) = serial_type;
|
||||
if( serial_type==0 ){
|
||||
/* NULL value. No change in zPayload */
|
||||
}else{
|
||||
u64 v;
|
||||
u32 i;
|
||||
if( serial_type==7 ){
|
||||
assert( sizeof(v)==sizeof(pRec->u.r) );
|
||||
memcpy(&v, &pRec->u.r, sizeof(v));
|
||||
swapMixedEndianFloat(v);
|
||||
}else{
|
||||
v = pRec->u.i;
|
||||
}
|
||||
len = i = sqlite3SmallTypeSizes[serial_type];
|
||||
assert( i>0 );
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
zPayload[--i] = (u8)(v&0xFF);
|
||||
if( i==0 ) break;
|
||||
v >>= 8;
|
||||
}
|
||||
zPayload += len;
|
||||
}
|
||||
}else if( serial_type<0x80 ){
|
||||
*(zHdr++) = serial_type;
|
||||
if( serial_type>=14 && pRec->n>0 ){
|
||||
assert( pRec->z!=0 );
|
||||
memcpy(zPayload, pRec->z, pRec->n);
|
||||
zPayload += pRec->n;
|
||||
}
|
||||
}else{
|
||||
zHdr += sqlite3PutVarint(zHdr, serial_type);
|
||||
if( pRec->n ){
|
||||
assert( pRec->z!=0 );
|
||||
memcpy(zPayload, pRec->z, pRec->n);
|
||||
zPayload += pRec->n;
|
||||
}
|
||||
}
|
||||
if( pRec==pLast ) break;
|
||||
pRec++;
|
||||
}
|
||||
assert( nHdr==(int)(zHdr - (u8*)pOut->z) );
|
||||
assert( nByte==(int)(zPayload - (u8*)pOut->z) );
|
||||
|
||||
@@ -3617,7 +3682,10 @@ case OP_Savepoint: {
|
||||
}
|
||||
}
|
||||
if( rc ) goto abort_due_to_error;
|
||||
|
||||
if( p->eVdbeState==VDBE_HALT_STATE ){
|
||||
rc = SQLITE_DONE;
|
||||
goto vdbe_return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3721,6 +3789,7 @@ case OP_AutoCommit: {
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
Btree *pBt;
|
||||
Db *pDb;
|
||||
int iMeta = 0;
|
||||
|
||||
assert( p->bIsReader );
|
||||
@@ -3740,7 +3809,8 @@ case OP_Transaction: {
|
||||
}
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
pDb = &db->aDb[pOp->p1];
|
||||
pBt = pDb->pBt;
|
||||
|
||||
if( pBt ){
|
||||
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta);
|
||||
@@ -3781,8 +3851,7 @@ case OP_Transaction: {
|
||||
assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
|
||||
if( rc==SQLITE_OK
|
||||
&& pOp->p5
|
||||
&& (iMeta!=pOp->p3
|
||||
|| db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
|
||||
&& (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i)
|
||||
){
|
||||
/*
|
||||
** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
|
||||
@@ -4925,11 +4994,8 @@ case OP_NoConflict: /* jump, in3 */
|
||||
case OP_NotFound: /* jump, in3 */
|
||||
case OP_Found: { /* jump, in3 */
|
||||
int alreadyExists;
|
||||
int takeJump;
|
||||
int ii;
|
||||
VdbeCursor *pC;
|
||||
int res;
|
||||
UnpackedRecord *pFree;
|
||||
UnpackedRecord *pIdxKey;
|
||||
UnpackedRecord r;
|
||||
|
||||
@@ -4944,14 +5010,15 @@ 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.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
r.aMem = pIn3;
|
||||
r.default_rc = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(ii=0; ii<r.nField; ii++){
|
||||
assert( memIsValid(&r.aMem[ii]) );
|
||||
@@ -4959,37 +5026,25 @@ case OP_Found: { /* jump, in3 */
|
||||
if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
|
||||
}
|
||||
#endif
|
||||
pIdxKey = &r;
|
||||
pFree = 0;
|
||||
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &pC->seekResult);
|
||||
}else{
|
||||
assert( pIn3->flags & MEM_Blob );
|
||||
rc = ExpandBlob(pIn3);
|
||||
/* Composite key generated by OP_MakeRecord */
|
||||
assert( r.aMem->flags & MEM_Blob );
|
||||
assert( pOp->opcode!=OP_NoConflict );
|
||||
rc = ExpandBlob(r.aMem);
|
||||
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
|
||||
if( rc ) goto no_mem;
|
||||
pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
|
||||
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);
|
||||
}
|
||||
pIdxKey->default_rc = 0;
|
||||
takeJump = 0;
|
||||
if( pOp->opcode==OP_NoConflict ){
|
||||
/* For the OP_NoConflict opcode, take the jump if any of the
|
||||
** input fields are NULL, since any key with a NULL will not
|
||||
** conflict */
|
||||
for(ii=0; ii<pIdxKey->nField; ii++){
|
||||
if( pIdxKey->aMem[ii].flags & MEM_Null ){
|
||||
takeJump = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res);
|
||||
if( pFree ) sqlite3DbFreeNN(db, pFree);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pC->seekResult = res;
|
||||
alreadyExists = (res==0);
|
||||
alreadyExists = (pC->seekResult==0);
|
||||
pC->nullRow = 1-alreadyExists;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
@@ -4997,9 +5052,25 @@ case OP_Found: { /* jump, in3 */
|
||||
VdbeBranchTaken(alreadyExists!=0,2);
|
||||
if( alreadyExists ) goto jump_to_p2;
|
||||
}else{
|
||||
VdbeBranchTaken(takeJump||alreadyExists==0,2);
|
||||
if( takeJump || !alreadyExists ) goto jump_to_p2;
|
||||
if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i;
|
||||
if( !alreadyExists ){
|
||||
VdbeBranchTaken(1,2);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
if( pOp->opcode==OP_NoConflict ){
|
||||
/* For the OP_NoConflict opcode, take the jump if any of the
|
||||
** input fields are NULL, since any key with a NULL will not
|
||||
** conflict */
|
||||
for(ii=0; ii<r.nField; ii++){
|
||||
if( r.aMem[ii].flags & MEM_Null ){
|
||||
VdbeBranchTaken(1,2);
|
||||
goto jump_to_p2;
|
||||
}
|
||||
}
|
||||
}
|
||||
VdbeBranchTaken(0,2);
|
||||
if( pOp->opcode==OP_IfNoHope ){
|
||||
pC->seekHit = pOp->p4.i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5690,7 +5761,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.
|
||||
@@ -5746,16 +5817,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 ){
|
||||
@@ -6202,9 +6280,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 );
|
||||
|
||||
@@ -7249,6 +7327,7 @@ case OP_AggStep: {
|
||||
pCtx->pVdbe = p;
|
||||
pCtx->skipFlag = 0;
|
||||
pCtx->isError = 0;
|
||||
pCtx->enc = encoding;
|
||||
pCtx->argc = n;
|
||||
pOp->p4type = P4_FUNCCTX;
|
||||
pOp->p4.pCtx = pCtx;
|
||||
@@ -7378,9 +7457,6 @@ case OP_AggFinal: {
|
||||
}
|
||||
sqlite3VdbeChangeEncoding(pMem, encoding);
|
||||
UPDATE_MAX_BLOBSIZE(pMem);
|
||||
if( sqlite3VdbeMemTooBig(pMem) ){
|
||||
goto too_big;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7901,6 +7977,7 @@ case OP_VColumn: {
|
||||
assert( pModule->xColumn );
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
sContext.pOut = pDest;
|
||||
sContext.enc = encoding;
|
||||
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
|
||||
if( pOp->p5 & OPFLAG_NOCHNG ){
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
@@ -7919,9 +7996,6 @@ case OP_VColumn: {
|
||||
REGISTER_TRACE(pOp->p3, pDest);
|
||||
UPDATE_MAX_BLOBSIZE(pDest);
|
||||
|
||||
if( sqlite3VdbeMemTooBig(pDest) ){
|
||||
goto too_big;
|
||||
}
|
||||
if( rc ) goto abort_due_to_error;
|
||||
break;
|
||||
}
|
||||
@@ -8188,6 +8262,7 @@ case OP_Function: { /* group */
|
||||
if( pCtx->pOut != pOut ){
|
||||
pCtx->pVdbe = p;
|
||||
pCtx->pOut = pOut;
|
||||
pCtx->enc = encoding;
|
||||
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
|
||||
}
|
||||
assert( pCtx->pVdbe==p );
|
||||
@@ -8214,11 +8289,10 @@ case OP_Function: { /* group */
|
||||
if( rc ) goto abort_due_to_error;
|
||||
}
|
||||
|
||||
/* Copy the result of the function into register P3 */
|
||||
if( pOut->flags & (MEM_Str|MEM_Blob) ){
|
||||
sqlite3VdbeChangeEncoding(pOut, encoding);
|
||||
if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
|
||||
}
|
||||
assert( (pOut->flags&MEM_Str)==0
|
||||
|| pOut->enc==encoding
|
||||
|| db->mallocFailed );
|
||||
assert( !sqlite3VdbeMemTooBig(pOut) );
|
||||
|
||||
REGISTER_TRACE(pOp->p3, pOut);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
@@ -8344,7 +8418,7 @@ case OP_Init: { /* jump */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
|
||||
&& !p->doingRerun
|
||||
&& p->minWriteFileFormat!=254 /* tag-20220401a */
|
||||
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
||||
){
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
@@ -8573,7 +8647,7 @@ abort_due_to_error:
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
||||
(int)(pOp - aOp), p->zSql, p->zErrMsg);
|
||||
sqlite3VdbeHalt(p);
|
||||
if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
|
||||
if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
|
||||
if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){
|
||||
db->flags |= SQLITE_CorruptRdOnly;
|
||||
|
||||
+2
-1
@@ -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
|
||||
@@ -244,7 +246,6 @@ int sqlite3VdbeMakeLabel(Parse*);
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe*);
|
||||
void sqlite3VdbeReusable(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
|
||||
+26
-10
@@ -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.
|
||||
@@ -369,6 +374,7 @@ struct sqlite3_context {
|
||||
Vdbe *pVdbe; /* The VM that owns this context */
|
||||
int iOp; /* Instruction number of OP_Function */
|
||||
int isError; /* Error code returned by the function. */
|
||||
u8 enc; /* Encoding to use for results */
|
||||
u8 skipFlag; /* Skip accumulator loading if true */
|
||||
u8 argc; /* Number of arguments */
|
||||
sqlite3_value *argv[1]; /* Argument set */
|
||||
@@ -417,7 +423,6 @@ struct Vdbe {
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
Parse *pParse; /* Parsing context used to create this Vdbe */
|
||||
ynVar nVar; /* Number of entries in aVar[] */
|
||||
u32 iVdbeMagic; /* Magic number defining state of the SQL statement */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
int nCursor; /* Number of slots in apCsr[] */
|
||||
u32 cacheCtr; /* VdbeCursor row cache generation counter */
|
||||
@@ -455,11 +460,10 @@ struct Vdbe {
|
||||
u8 errorAction; /* Recovery action to do in case of an error */
|
||||
u8 minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
u8 prepFlags; /* SQLITE_PREPARE_* flags */
|
||||
u8 doingRerun; /* True if rerunning after an auto-reprepare */
|
||||
u8 eVdbeState; /* On of the VDBE_*_STATE values */
|
||||
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
|
||||
bft explain:2; /* True if EXPLAIN present on SQL command */
|
||||
bft changeCntOn:1; /* True to update the change-counter */
|
||||
bft runOnlyOnce:1; /* Automatically expire on reset */
|
||||
bft usesStmtJournal:1; /* True if uses a statement journal */
|
||||
bft readOnly:1; /* True for statements that do not write */
|
||||
bft bIsReader:1; /* True for statements that read */
|
||||
@@ -486,13 +490,12 @@ struct Vdbe {
|
||||
};
|
||||
|
||||
/*
|
||||
** The following are allowed values for Vdbe.magic
|
||||
** The following are allowed values for Vdbe.eVdbeState
|
||||
*/
|
||||
#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */
|
||||
#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */
|
||||
#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */
|
||||
#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */
|
||||
#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */
|
||||
#define VDBE_INIT_STATE 0 /* Prepared statement under construction */
|
||||
#define VDBE_READY_STATE 1 /* Ready to run but not yet started */
|
||||
#define VDBE_RUN_STATE 2 /* Run in progress */
|
||||
#define VDBE_HALT_STATE 3 /* Finished. Need reset() or finalize() */
|
||||
|
||||
/*
|
||||
** Structure used to store the context required by the
|
||||
@@ -533,18 +536,31 @@ struct ValueList {
|
||||
sqlite3_value *pOut; /* Register to hold each decoded output value */
|
||||
};
|
||||
|
||||
/* Size of content associated with serial types that fit into a
|
||||
** single-byte varint.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
extern const u8 sqlite3SmallTypeSizes[];
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Function prototypes
|
||||
*/
|
||||
void sqlite3VdbeError(Vdbe*, const char *, ...);
|
||||
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
|
||||
void sqlite3VdbeFreeCursorNN(Vdbe*,VdbeCursor*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p);
|
||||
int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor*);
|
||||
u32 sqlite3VdbeSerialTypeLen(u32);
|
||||
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
|
||||
u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
|
||||
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
||||
u64 sqlite3FloatSwap(u64 in);
|
||||
# define swapMixedEndianFloat(X) X = sqlite3FloatSwap(X)
|
||||
#else
|
||||
# define swapMixedEndianFloat(X)
|
||||
#endif
|
||||
void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
|
||||
|
||||
|
||||
+102
-79
@@ -378,7 +378,8 @@ static void setResultStrOrError(
|
||||
u8 enc, /* Encoding of z. 0 for BLOBs */
|
||||
void (*xDel)(void*) /* Destructor function */
|
||||
){
|
||||
int rc = sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel);
|
||||
Mem *pOut = pCtx->pOut;
|
||||
int rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel);
|
||||
if( rc ){
|
||||
if( rc==SQLITE_TOOBIG ){
|
||||
sqlite3_result_error_toobig(pCtx);
|
||||
@@ -388,6 +389,11 @@ static void setResultStrOrError(
|
||||
assert( rc==SQLITE_NOMEM );
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
|
||||
if( sqlite3VdbeMemTooBig(pOut) ){
|
||||
sqlite3_result_error_toobig(pCtx);
|
||||
}
|
||||
}
|
||||
static int invokeValueDestructor(
|
||||
@@ -531,17 +537,22 @@ void sqlite3_result_text16le(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
|
||||
Mem *pOut = pCtx->pOut;
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
sqlite3VdbeMemCopy(pCtx->pOut, pValue);
|
||||
sqlite3VdbeMemCopy(pOut, pValue);
|
||||
sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
|
||||
if( sqlite3VdbeMemTooBig(pOut) ){
|
||||
sqlite3_result_error_toobig(pCtx);
|
||||
}
|
||||
}
|
||||
void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
|
||||
sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
|
||||
}
|
||||
int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
|
||||
Mem *pOut = pCtx->pOut;
|
||||
assert( sqlite3_mutex_held(pOut->db->mutex) );
|
||||
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
sqlite3_result_error_toobig(pCtx);
|
||||
return SQLITE_TOOBIG;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
@@ -557,8 +568,8 @@ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
|
||||
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
|
||||
#endif
|
||||
if( pCtx->pOut->flags & MEM_Null ){
|
||||
sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
|
||||
SQLITE_UTF8, SQLITE_STATIC);
|
||||
setResultStrOrError(pCtx, sqlite3ErrStr(errCode), -1, SQLITE_UTF8,
|
||||
SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,80 +643,83 @@ static int sqlite3Step(Vdbe *p){
|
||||
int rc;
|
||||
|
||||
assert(p);
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){
|
||||
/* We used to require that sqlite3_reset() be called before retrying
|
||||
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
||||
** with version 3.7.0, we changed this so that sqlite3_reset() would
|
||||
** be called automatically instead of throwing the SQLITE_MISUSE error.
|
||||
** This "automatic-reset" change is not technically an incompatibility,
|
||||
** since any application that receives an SQLITE_MISUSE is broken by
|
||||
** definition.
|
||||
**
|
||||
** Nevertheless, some published applications that were originally written
|
||||
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
|
||||
** returns, and those were broken by the automatic-reset change. As a
|
||||
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
|
||||
** legacy behavior of returning SQLITE_MISUSE for cases where the
|
||||
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
|
||||
** or SQLITE_BUSY error.
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_AUTORESET
|
||||
if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
}else{
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#else
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check that malloc() has not failed. If it has, return early. */
|
||||
db = p->db;
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
if( p->eVdbeState!=VDBE_RUN_STATE ){
|
||||
restart_step:
|
||||
if( p->eVdbeState==VDBE_READY_STATE ){
|
||||
if( p->expired ){
|
||||
p->rc = SQLITE_SCHEMA;
|
||||
rc = SQLITE_ERROR;
|
||||
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
|
||||
/* If this statement was prepared using saved SQL and an
|
||||
** error has occurred, then return the error code in p->rc to the
|
||||
** caller. Set the error code in the database handle to the same
|
||||
** value.
|
||||
*/
|
||||
rc = sqlite3VdbeTransferError(p);
|
||||
}
|
||||
goto end_of_step;
|
||||
}
|
||||
|
||||
if( p->pc<0 && p->expired ){
|
||||
p->rc = SQLITE_SCHEMA;
|
||||
rc = SQLITE_ERROR;
|
||||
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
|
||||
/* If this statement was prepared using saved SQL and an
|
||||
** error has occurred, then return the error code in p->rc to the
|
||||
** caller. Set the error code in the database handle to the same value.
|
||||
*/
|
||||
rc = sqlite3VdbeTransferError(p);
|
||||
}
|
||||
goto end_of_step;
|
||||
}
|
||||
if( p->pc<0 ){
|
||||
/* If there are no other statements currently running, then
|
||||
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
|
||||
** from interrupting a statement that has not yet started.
|
||||
*/
|
||||
if( db->nVdbeActive==0 ){
|
||||
AtomicStore(&db->u1.isInterrupted, 0);
|
||||
}
|
||||
/* If there are no other statements currently running, then
|
||||
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
|
||||
** from interrupting a statement that has not yet started.
|
||||
*/
|
||||
if( db->nVdbeActive==0 ){
|
||||
AtomicStore(&db->u1.isInterrupted, 0);
|
||||
}
|
||||
|
||||
assert( db->nVdbeWrite>0 || db->autoCommit==0
|
||||
|| (db->nDeferredCons==0 && db->nDeferredImmCons==0)
|
||||
);
|
||||
assert( db->nVdbeWrite>0 || db->autoCommit==0
|
||||
|| (db->nDeferredCons==0 && db->nDeferredImmCons==0)
|
||||
);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
|
||||
&& !db->init.busy && p->zSql ){
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
||||
}else{
|
||||
assert( p->startTime==0 );
|
||||
}
|
||||
if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
|
||||
&& !db->init.busy && p->zSql ){
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
||||
}else{
|
||||
assert( p->startTime==0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
db->nVdbeActive++;
|
||||
if( p->readOnly==0 ) db->nVdbeWrite++;
|
||||
if( p->bIsReader ) db->nVdbeRead++;
|
||||
p->pc = 0;
|
||||
db->nVdbeActive++;
|
||||
if( p->readOnly==0 ) db->nVdbeWrite++;
|
||||
if( p->bIsReader ) db->nVdbeRead++;
|
||||
p->pc = 0;
|
||||
p->eVdbeState = VDBE_RUN_STATE;
|
||||
}else
|
||||
|
||||
if( ALWAYS(p->eVdbeState==VDBE_HALT_STATE) ){
|
||||
/* We used to require that sqlite3_reset() be called before retrying
|
||||
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
||||
** with version 3.7.0, we changed this so that sqlite3_reset() would
|
||||
** be called automatically instead of throwing the SQLITE_MISUSE error.
|
||||
** This "automatic-reset" change is not technically an incompatibility,
|
||||
** since any application that receives an SQLITE_MISUSE is broken by
|
||||
** definition.
|
||||
**
|
||||
** Nevertheless, some published applications that were originally written
|
||||
** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
|
||||
** returns, and those were broken by the automatic-reset change. As a
|
||||
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
|
||||
** legacy behavior of returning SQLITE_MISUSE for cases where the
|
||||
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
|
||||
** or SQLITE_BUSY error.
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_AUTORESET
|
||||
if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
}else{
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#else
|
||||
sqlite3_reset((sqlite3_stmt*)p);
|
||||
#endif
|
||||
assert( p->eVdbeState==VDBE_READY_STATE );
|
||||
goto restart_step;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->rcApp = SQLITE_OK;
|
||||
#endif
|
||||
@@ -720,7 +734,12 @@ static int sqlite3Step(Vdbe *p){
|
||||
db->nVdbeExec--;
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_ROW ){
|
||||
if( rc==SQLITE_ROW ){
|
||||
assert( p->rc==SQLITE_OK );
|
||||
assert( db->mallocFailed==0 );
|
||||
db->errCode = SQLITE_ROW;
|
||||
return SQLITE_ROW;
|
||||
}else{
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* If the statement completed successfully, invoke the profile callback */
|
||||
checkProfileCallback(db, p);
|
||||
@@ -772,7 +791,6 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
}
|
||||
db = v->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v->doingRerun = 0;
|
||||
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
|
||||
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
|
||||
int savedPc = v->pc;
|
||||
@@ -798,7 +816,13 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
break;
|
||||
}
|
||||
sqlite3_reset(pStmt);
|
||||
if( savedPc>=0 ) v->doingRerun = 1;
|
||||
if( savedPc>=0 ){
|
||||
/* Setting minWriteFileFormat to 254 is a signal to the OP_Init and
|
||||
** OP_Trace opcodes to *not* perform SQLITE_TRACE_STMT because one
|
||||
** should output has already occurred due to SQLITE_SCHEMA.
|
||||
** tag-20220401a */
|
||||
v->minWriteFileFormat = 254;
|
||||
}
|
||||
assert( v->expired==0 );
|
||||
}
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
@@ -1412,7 +1436,7 @@ static int vdbeUnbind(Vdbe *p, int i){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(p->db->mutex);
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_RUN || p->pc>=0 ){
|
||||
if( p->eVdbeState!=VDBE_READY_STATE ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE);
|
||||
sqlite3_mutex_leave(p->db->mutex);
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
@@ -1765,7 +1789,7 @@ int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
|
||||
*/
|
||||
int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
return v!=0 && v->iVdbeMagic==VDBE_MAGIC_RUN && v->pc>=0;
|
||||
return v!=0 && v->eVdbeState==VDBE_RUN_STATE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1811,8 +1835,7 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v = 0;
|
||||
db->pnBytesFreed = (int*)&v;
|
||||
sqlite3VdbeClearObject(db, pVdbe);
|
||||
sqlite3DbFree(db, pVdbe);
|
||||
sqlite3VdbeDelete(pVdbe);
|
||||
db->pnBytesFreed = 0;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}else{
|
||||
|
||||
+190
-140
@@ -35,7 +35,7 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){
|
||||
p->pNext = db->pVdbe;
|
||||
p->pPrev = 0;
|
||||
db->pVdbe = p;
|
||||
p->iVdbeMagic = VDBE_MAGIC_INIT;
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
p->pParse = pParse;
|
||||
pParse->pVdbe = p;
|
||||
assert( pParse->aLabel==0 );
|
||||
@@ -236,7 +236,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
||||
VdbeOp *pOp;
|
||||
|
||||
i = p->nOp;
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
assert( op>=0 && op<0xff );
|
||||
if( p->nOpAlloc<=i ){
|
||||
return growOp3(p, op, p1, p2, p3);
|
||||
@@ -568,7 +568,7 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
|
||||
void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
||||
Parse *p = v->pParse;
|
||||
int j = ADDR(x);
|
||||
assert( v->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( v->eVdbeState==VDBE_INIT_STATE );
|
||||
assert( j<-p->nLabel );
|
||||
assert( j>=0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -588,14 +588,20 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
||||
** Mark the VDBE as one that can only be run one time.
|
||||
*/
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe *p){
|
||||
p->runOnlyOnce = 1;
|
||||
sqlite3VdbeAddOp2(p, OP_Expire, 1, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark the VDBE as one that can only be run multiple times.
|
||||
*/
|
||||
void sqlite3VdbeReusable(Vdbe *p){
|
||||
p->runOnlyOnce = 0;
|
||||
int i;
|
||||
for(i=1; ALWAYS(i<p->nOp); i++){
|
||||
if( ALWAYS(p->aOp[i].opcode==OP_Expire) ){
|
||||
p->aOp[1].opcode = OP_Noop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
|
||||
@@ -699,6 +705,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
int hasInitCoroutine = 0;
|
||||
Op *pOp;
|
||||
VdbeOpIter sIter;
|
||||
|
||||
if( v==0 ) return 0;
|
||||
memset(&sIter, 0, sizeof(sIter));
|
||||
sIter.v = v;
|
||||
|
||||
@@ -863,18 +871,104 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
if( pOp==p->aOp ) break;
|
||||
pOp--;
|
||||
}
|
||||
sqlite3DbFree(p->db, pParse->aLabel);
|
||||
pParse->aLabel = 0;
|
||||
if( aLabel ){
|
||||
sqlite3DbFreeNN(p->db, pParse->aLabel);
|
||||
pParse->aLabel = 0;
|
||||
}
|
||||
pParse->nLabel = 0;
|
||||
*pMaxFuncArgs = nMaxArgs;
|
||||
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.
|
||||
*/
|
||||
int sqlite3VdbeCurrentAddr(Vdbe *p){
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
return p->nOp;
|
||||
}
|
||||
|
||||
@@ -959,7 +1053,7 @@ VdbeOp *sqlite3VdbeAddOpList(
|
||||
int i;
|
||||
VdbeOp *pOut, *pFirst;
|
||||
assert( nOp>0 );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){
|
||||
return 0;
|
||||
}
|
||||
@@ -1150,13 +1244,16 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
** nOp entries.
|
||||
*/
|
||||
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
|
||||
assert( nOp>=0 );
|
||||
if( aOp ){
|
||||
Op *pOp;
|
||||
for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
|
||||
Op *pOp = &aOp[nOp-1];
|
||||
while(1){ /* Exit via break */
|
||||
if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
sqlite3DbFree(db, pOp->zComment);
|
||||
#endif
|
||||
if( pOp==aOp ) break;
|
||||
pOp--;
|
||||
}
|
||||
sqlite3DbFreeNN(db, aOp);
|
||||
}
|
||||
@@ -1218,7 +1315,7 @@ void sqlite3VdbeReleaseRegisters(
|
||||
u32 mask, /* Mask of registers to NOT release */
|
||||
int bUndefine /* If true, mark registers as undefined */
|
||||
){
|
||||
if( N==0 ) return;
|
||||
if( N==0 || OptimizationDisabled(pParse->db, SQLITE_ReleaseReg) ) return;
|
||||
assert( pParse->pVdbe );
|
||||
assert( iFirst>=1 );
|
||||
assert( iFirst+N-1<=pParse->nMem );
|
||||
@@ -1282,7 +1379,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
sqlite3 *db;
|
||||
assert( p!=0 );
|
||||
db = p->db;
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
assert( p->aOp!=0 || db->mallocFailed );
|
||||
if( db->mallocFailed ){
|
||||
if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
|
||||
@@ -1410,7 +1507,7 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||
/* C89 specifies that the constant "dummy" will be initialized to all
|
||||
** zeros, which is correct. MSVC generates a warning, nevertheless. */
|
||||
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
if( addr<0 ){
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
@@ -1477,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;
|
||||
@@ -2073,7 +2175,7 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
|
||||
VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem];
|
||||
assert( sqlite3VdbeFrameIsValid(p) );
|
||||
for(i=0; i<p->nChildCsr; i++){
|
||||
sqlite3VdbeFreeCursor(p->v, apCsr[i]);
|
||||
if( apCsr[i] ) sqlite3VdbeFreeCursorNN(p->v, apCsr[i]);
|
||||
}
|
||||
releaseMemArray(aMem, p->nChildMem);
|
||||
sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
|
||||
@@ -2112,7 +2214,7 @@ int sqlite3VdbeList(
|
||||
Op *pOp; /* Current opcode */
|
||||
|
||||
assert( p->explain );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_RUN );
|
||||
assert( p->eVdbeState==VDBE_RUN_STATE );
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
|
||||
|
||||
/* Even though this opcode does not use dynamic strings for
|
||||
@@ -2267,11 +2369,11 @@ struct ReusableSpace {
|
||||
static void *allocSpace(
|
||||
struct ReusableSpace *p, /* Bulk memory available for allocation */
|
||||
void *pBuf, /* Pointer to a prior allocation */
|
||||
sqlite3_int64 nByte /* Bytes of memory needed */
|
||||
sqlite3_int64 nByte /* Bytes of memory needed. */
|
||||
){
|
||||
assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
|
||||
if( pBuf==0 ){
|
||||
nByte = ROUND8(nByte);
|
||||
nByte = ROUND8P(nByte);
|
||||
if( nByte <= p->nFree ){
|
||||
p->nFree -= nByte;
|
||||
pBuf = &p->pSpace[p->nFree];
|
||||
@@ -2292,14 +2394,15 @@ void sqlite3VdbeRewind(Vdbe *p){
|
||||
int i;
|
||||
#endif
|
||||
assert( p!=0 );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT || p->iVdbeMagic==VDBE_MAGIC_RESET );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE
|
||||
|| p->eVdbeState==VDBE_READY_STATE
|
||||
|| p->eVdbeState==VDBE_HALT_STATE );
|
||||
|
||||
/* There should be at least one opcode.
|
||||
*/
|
||||
assert( p->nOp>0 );
|
||||
|
||||
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
|
||||
p->iVdbeMagic = VDBE_MAGIC_RUN;
|
||||
p->eVdbeState = VDBE_READY_STATE;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(i=0; i<p->nMem; i++){
|
||||
@@ -2355,7 +2458,7 @@ void sqlite3VdbeMakeReady(
|
||||
assert( p!=0 );
|
||||
assert( p->nOp>0 );
|
||||
assert( pParse!=0 );
|
||||
assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
|
||||
assert( p->eVdbeState==VDBE_INIT_STATE );
|
||||
assert( pParse==p->pParse );
|
||||
p->pVList = pParse->pVList;
|
||||
pParse->pVList = 0;
|
||||
@@ -2378,7 +2481,7 @@ void sqlite3VdbeMakeReady(
|
||||
** opcode array. This extra memory will be reallocated for other elements
|
||||
** of the prepared statement.
|
||||
*/
|
||||
n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
|
||||
n = ROUND8P(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
|
||||
x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */
|
||||
assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
|
||||
x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */
|
||||
@@ -2466,9 +2569,9 @@ void sqlite3VdbeMakeReady(
|
||||
** happens to hold.
|
||||
*/
|
||||
void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
if( pCx==0 ){
|
||||
return;
|
||||
}
|
||||
if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx);
|
||||
}
|
||||
void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
|
||||
switch( pCx->eCurType ){
|
||||
case CURTYPE_SORTER: {
|
||||
sqlite3VdbeSorterClose(p->db, pCx);
|
||||
@@ -2496,14 +2599,12 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
** Close all cursors in the current frame.
|
||||
*/
|
||||
static void closeCursorsInFrame(Vdbe *p){
|
||||
if( p->apCsr ){
|
||||
int i;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
VdbeCursor *pC = p->apCsr[i];
|
||||
if( pC ){
|
||||
sqlite3VdbeFreeCursor(p, pC);
|
||||
p->apCsr[i] = 0;
|
||||
}
|
||||
int i;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
VdbeCursor *pC = p->apCsr[i];
|
||||
if( pC ){
|
||||
sqlite3VdbeFreeCursorNN(p, pC);
|
||||
p->apCsr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2552,9 +2653,7 @@ static void closeAllCursors(Vdbe *p){
|
||||
}
|
||||
assert( p->nFrame==0 );
|
||||
closeCursorsInFrame(p);
|
||||
if( p->aMem ){
|
||||
releaseMemArray(p->aMem, p->nMem);
|
||||
}
|
||||
releaseMemArray(p->aMem, p->nMem);
|
||||
while( p->pDelFrame ){
|
||||
VdbeFrame *pDel = p->pDelFrame;
|
||||
p->pDelFrame = pDel->pParent;
|
||||
@@ -2994,6 +3093,7 @@ int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
||||
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
|
||||
p->errorAction = OE_Abort;
|
||||
sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
|
||||
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR;
|
||||
return SQLITE_CONSTRAINT_FOREIGNKEY;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -3033,9 +3133,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
** one, or the complete transaction if there is no statement transaction.
|
||||
*/
|
||||
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( p->eVdbeState==VDBE_RUN_STATE );
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
@@ -3044,7 +3142,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
|
||||
/* No commit or rollback needed if the program never started or if the
|
||||
** SQL statement does not read or write a database file. */
|
||||
if( p->pc>=0 && p->bIsReader ){
|
||||
if( p->bIsReader ){
|
||||
int mrc; /* Primary error code from p->rc */
|
||||
int eStatementOp = 0;
|
||||
int isSpecialError; /* Set to true if a 'special' error */
|
||||
@@ -3192,15 +3290,13 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
}
|
||||
|
||||
/* We have successfully halted and closed the VM. Record this fact. */
|
||||
if( p->pc>=0 ){
|
||||
db->nVdbeActive--;
|
||||
if( !p->readOnly ) db->nVdbeWrite--;
|
||||
if( p->bIsReader ) db->nVdbeRead--;
|
||||
assert( db->nVdbeActive>=db->nVdbeRead );
|
||||
assert( db->nVdbeRead>=db->nVdbeWrite );
|
||||
assert( db->nVdbeWrite>=0 );
|
||||
}
|
||||
p->iVdbeMagic = VDBE_MAGIC_HALT;
|
||||
db->nVdbeActive--;
|
||||
if( !p->readOnly ) db->nVdbeWrite--;
|
||||
if( p->bIsReader ) db->nVdbeRead--;
|
||||
assert( db->nVdbeActive>=db->nVdbeRead );
|
||||
assert( db->nVdbeRead>=db->nVdbeWrite );
|
||||
assert( db->nVdbeWrite>=0 );
|
||||
p->eVdbeState = VDBE_HALT_STATE;
|
||||
checkActiveVdbeCnt(db);
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM_BKPT;
|
||||
@@ -3282,8 +3378,8 @@ static void vdbeInvokeSqllog(Vdbe *v){
|
||||
** again.
|
||||
**
|
||||
** To look at it another way, this routine resets the state of the
|
||||
** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to
|
||||
** VDBE_MAGIC_INIT.
|
||||
** virtual machine from VDBE_RUN_STATE or VDBE_HALT_STATE back to
|
||||
** VDBE_READY_STATE.
|
||||
*/
|
||||
int sqlite3VdbeReset(Vdbe *p){
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
@@ -3297,7 +3393,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
** error, then it might not have been halted properly. So halt
|
||||
** it now.
|
||||
*/
|
||||
sqlite3VdbeHalt(p);
|
||||
if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
|
||||
|
||||
/* If the VDBE has been run even partially, then transfer the error code
|
||||
** and error message from the VDBE into the main database structure. But
|
||||
@@ -3311,13 +3407,6 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}else{
|
||||
db->errCode = p->rc;
|
||||
}
|
||||
if( p->runOnlyOnce ) p->expired = 1;
|
||||
}else if( p->rc && p->expired ){
|
||||
/* The expired flag was set on the VDBE before the first call
|
||||
** to sqlite3_step(). For consistency (since sqlite3_step() was
|
||||
** called), set the database error in this case as well.
|
||||
*/
|
||||
sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
|
||||
}
|
||||
|
||||
/* Reset register contents and reclaim error message memory.
|
||||
@@ -3374,7 +3463,6 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->iVdbeMagic = VDBE_MAGIC_RESET;
|
||||
return p->rc & db->errMask;
|
||||
}
|
||||
|
||||
@@ -3384,7 +3472,10 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
*/
|
||||
int sqlite3VdbeFinalize(Vdbe *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->iVdbeMagic==VDBE_MAGIC_RUN || p->iVdbeMagic==VDBE_MAGIC_HALT ){
|
||||
assert( VDBE_RUN_STATE>VDBE_READY_STATE );
|
||||
assert( VDBE_HALT_STATE>VDBE_READY_STATE );
|
||||
assert( VDBE_INIT_STATE<VDBE_READY_STATE );
|
||||
if( p->eVdbeState>=VDBE_READY_STATE ){
|
||||
rc = sqlite3VdbeReset(p);
|
||||
assert( (rc & p->db->errMask)==rc );
|
||||
}
|
||||
@@ -3436,22 +3527,24 @@ void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
|
||||
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
|
||||
** the database connection and frees the object itself.
|
||||
*/
|
||||
void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
||||
static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
||||
SubProgram *pSub, *pNext;
|
||||
assert( p->db==0 || p->db==db );
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
if( p->aColName ){
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
sqlite3DbFreeNN(db, p->aColName);
|
||||
}
|
||||
for(pSub=p->pProgram; pSub; pSub=pNext){
|
||||
pNext = pSub->pNext;
|
||||
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
|
||||
sqlite3DbFree(db, pSub);
|
||||
}
|
||||
if( p->iVdbeMagic!=VDBE_MAGIC_INIT ){
|
||||
if( p->eVdbeState!=VDBE_INIT_STATE ){
|
||||
releaseMemArray(p->aVar, p->nVar);
|
||||
sqlite3DbFree(db, p->pVList);
|
||||
sqlite3DbFree(db, p->pFree);
|
||||
if( p->pVList ) sqlite3DbFreeNN(db, p->pVList);
|
||||
if( p->pFree ) sqlite3DbFreeNN(db, p->pFree);
|
||||
}
|
||||
vdbeFreeOpArray(db, p->aOp, p->nOp);
|
||||
sqlite3DbFree(db, p->aColName);
|
||||
sqlite3DbFree(db, p->zSql);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
sqlite3DbFree(db, p->zNormSql);
|
||||
@@ -3484,17 +3577,17 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
db = p->db;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
sqlite3VdbeClearObject(db, p);
|
||||
if( p->pPrev ){
|
||||
p->pPrev->pNext = p->pNext;
|
||||
}else{
|
||||
assert( db->pVdbe==p );
|
||||
db->pVdbe = p->pNext;
|
||||
if( db->pnBytesFreed==0 ){
|
||||
if( p->pPrev ){
|
||||
p->pPrev->pNext = p->pNext;
|
||||
}else{
|
||||
assert( db->pVdbe==p );
|
||||
db->pVdbe = p->pNext;
|
||||
}
|
||||
if( p->pNext ){
|
||||
p->pNext->pPrev = p->pPrev;
|
||||
}
|
||||
}
|
||||
if( p->pNext ){
|
||||
p->pNext->pPrev = p->pPrev;
|
||||
}
|
||||
p->iVdbeMagic = VDBE_MAGIC_DEAD;
|
||||
p->db = 0;
|
||||
sqlite3DbFreeNN(db, p);
|
||||
}
|
||||
|
||||
@@ -3545,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);
|
||||
}
|
||||
@@ -3558,7 +3651,7 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
** sqlite3VdbeSerialType()
|
||||
** sqlite3VdbeSerialTypeLen()
|
||||
** sqlite3VdbeSerialLen()
|
||||
** sqlite3VdbeSerialPut()
|
||||
** sqlite3VdbeSerialPut() <--- in-lined into OP_MakeRecord as of 2022-04-02
|
||||
** sqlite3VdbeSerialGet()
|
||||
**
|
||||
** encapsulate the code that serializes values for storage in SQLite
|
||||
@@ -3670,7 +3763,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
|
||||
/*
|
||||
** The sizes for serial types less than 128
|
||||
*/
|
||||
static const u8 sqlite3SmallTypeSizes[] = {
|
||||
const u8 sqlite3SmallTypeSizes[128] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 */
|
||||
/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0,
|
||||
/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
||||
@@ -3739,7 +3832,7 @@ u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
|
||||
** so we trust him.
|
||||
*/
|
||||
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
||||
static u64 floatSwap(u64 in){
|
||||
u64 sqlite3FloatSwap(u64 in){
|
||||
union {
|
||||
u64 r;
|
||||
u32 i[2];
|
||||
@@ -3752,59 +3845,8 @@ static u64 floatSwap(u64 in){
|
||||
u.i[1] = t;
|
||||
return u.r;
|
||||
}
|
||||
# define swapMixedEndianFloat(X) X = floatSwap(X)
|
||||
#else
|
||||
# define swapMixedEndianFloat(X)
|
||||
#endif
|
||||
#endif /* SQLITE_MIXED_ENDIAN_64BIT_FLOAT */
|
||||
|
||||
/*
|
||||
** Write the serialized data blob for the value stored in pMem into
|
||||
** buf. It is assumed that the caller has allocated sufficient space.
|
||||
** Return the number of bytes written.
|
||||
**
|
||||
** nBuf is the amount of space left in buf[]. The caller is responsible
|
||||
** for allocating enough space to buf[] to hold the entire field, exclusive
|
||||
** of the pMem->u.nZero bytes for a MEM_Zero value.
|
||||
**
|
||||
** Return the number of bytes actually written into buf[]. The number
|
||||
** of bytes in the zero-filled tail is included in the return value only
|
||||
** if those bytes were zeroed in buf[].
|
||||
*/
|
||||
u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
||||
u32 len;
|
||||
|
||||
/* Integer and Real */
|
||||
if( serial_type<=7 && serial_type>0 ){
|
||||
u64 v;
|
||||
u32 i;
|
||||
if( serial_type==7 ){
|
||||
assert( sizeof(v)==sizeof(pMem->u.r) );
|
||||
memcpy(&v, &pMem->u.r, sizeof(v));
|
||||
swapMixedEndianFloat(v);
|
||||
}else{
|
||||
v = pMem->u.i;
|
||||
}
|
||||
len = i = sqlite3SmallTypeSizes[serial_type];
|
||||
assert( i>0 );
|
||||
do{
|
||||
buf[--i] = (u8)(v&0xFF);
|
||||
v >>= 8;
|
||||
}while( i );
|
||||
return len;
|
||||
}
|
||||
|
||||
/* String or blob */
|
||||
if( serial_type>=12 ){
|
||||
assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
|
||||
== (int)sqlite3VdbeSerialTypeLen(serial_type) );
|
||||
len = pMem->n;
|
||||
if( len>0 ) memcpy(buf, pMem->z, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* NULL or constants 0 or 1 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Input "x" is a sequence of unsigned characters that represent a
|
||||
** big-endian integer. Return the equivalent native integer
|
||||
@@ -3970,10 +4012,10 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
|
||||
){
|
||||
UnpackedRecord *p; /* Unpacked record to return */
|
||||
int nByte; /* Number of bytes required for *p */
|
||||
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
|
||||
nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
|
||||
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
||||
if( !p ) return 0;
|
||||
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
|
||||
p->aMem = (Mem*)&((char*)p)[ROUND8P(sizeof(UnpackedRecord))];
|
||||
assert( pKeyInfo->aSortFlags!=0 );
|
||||
p->pKeyInfo = pKeyInfo;
|
||||
p->nField = pKeyInfo->nKeyField + 1;
|
||||
@@ -4471,14 +4513,22 @@ int sqlite3VdbeRecordCompareWithSkip(
|
||||
** two elements in the keys are equal. Fix the various stack variables so
|
||||
** that this routine begins comparing at the second field. */
|
||||
if( bSkip ){
|
||||
u32 s1;
|
||||
idx1 = 1 + getVarint32(&aKey1[1], s1);
|
||||
u32 s1 = aKey1[1];
|
||||
if( s1<0x80 ){
|
||||
idx1 = 2;
|
||||
}else{
|
||||
idx1 = 1 + sqlite3GetVarint32(&aKey1[1], &s1);
|
||||
}
|
||||
szHdr1 = aKey1[0];
|
||||
d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1);
|
||||
i = 1;
|
||||
pRhs++;
|
||||
}else{
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
if( (szHdr1 = aKey1[0])<0x80 ){
|
||||
idx1 = 1;
|
||||
}else{
|
||||
idx1 = sqlite3GetVarint32(aKey1, &szHdr1);
|
||||
}
|
||||
d1 = szHdr1;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
+39
-22
@@ -204,7 +204,11 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
||||
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|
||||
|| desiredEnc==SQLITE_UTF16BE );
|
||||
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
|
||||
if( !(pMem->flags&MEM_Str) ){
|
||||
pMem->enc = desiredEnc;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pMem->enc==desiredEnc ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
@@ -453,9 +457,10 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
Mem t;
|
||||
assert( pFunc!=0 );
|
||||
assert( pMem!=0 );
|
||||
assert( pMem->db!=0 );
|
||||
assert( pFunc->xFinalize!=0 );
|
||||
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( sqlite3_mutex_held(pMem->db->mutex) );
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.flags = MEM_Null;
|
||||
@@ -463,6 +468,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
ctx.pOut = &t;
|
||||
ctx.pMem = pMem;
|
||||
ctx.pFunc = pFunc;
|
||||
ctx.enc = ENC(t.db);
|
||||
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
||||
@@ -484,12 +490,14 @@ int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
|
||||
assert( pFunc!=0 );
|
||||
assert( pFunc->xValue!=0 );
|
||||
assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
|
||||
assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
|
||||
assert( pAccum->db!=0 );
|
||||
assert( sqlite3_mutex_held(pAccum->db->mutex) );
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
ctx.pOut = pOut;
|
||||
ctx.pMem = pAccum;
|
||||
ctx.pFunc = pFunc;
|
||||
ctx.enc = ENC(pAccum->db);
|
||||
pFunc->xValue(&ctx);
|
||||
return ctx.isError;
|
||||
}
|
||||
@@ -1107,6 +1115,13 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
|
||||
** stored without allocating memory, then it is. If a memory allocation
|
||||
** is required to store the string, then value of pMem is unchanged. In
|
||||
** either case, SQLITE_TOOBIG is returned.
|
||||
**
|
||||
** The "enc" parameter is the text encoding for the string, or zero
|
||||
** to store a blob.
|
||||
**
|
||||
** If n is negative, then the string consists of all bytes up to but
|
||||
** excluding the first zero character. The n parameter must be
|
||||
** non-negative for blobs.
|
||||
*/
|
||||
int sqlite3VdbeMemSetStr(
|
||||
Mem *pMem, /* Memory cell to set to string value */
|
||||
@@ -1117,11 +1132,12 @@ int sqlite3VdbeMemSetStr(
|
||||
){
|
||||
i64 nByte = n; /* New value for pMem->n */
|
||||
int iLimit; /* Maximum allowed string or blob size */
|
||||
u16 flags = 0; /* New value for pMem->flags */
|
||||
u16 flags; /* New value for pMem->flags */
|
||||
|
||||
assert( pMem!=0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
||||
assert( enc!=0 || n>=0 );
|
||||
|
||||
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
|
||||
if( !z ){
|
||||
@@ -1134,7 +1150,6 @@ int sqlite3VdbeMemSetStr(
|
||||
}else{
|
||||
iLimit = SQLITE_MAX_LENGTH;
|
||||
}
|
||||
flags = (enc==0?MEM_Blob:MEM_Str);
|
||||
if( nByte<0 ){
|
||||
assert( enc!=0 );
|
||||
if( enc==SQLITE_UTF8 ){
|
||||
@@ -1142,7 +1157,23 @@ int sqlite3VdbeMemSetStr(
|
||||
}else{
|
||||
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
|
||||
}
|
||||
flags |= MEM_Term;
|
||||
flags= MEM_Str|MEM_Term;
|
||||
}else if( enc==0 ){
|
||||
flags = MEM_Blob;
|
||||
enc = SQLITE_UTF8;
|
||||
}else{
|
||||
flags = MEM_Str;
|
||||
}
|
||||
if( nByte>iLimit ){
|
||||
if( xDel && xDel!=SQLITE_TRANSIENT ){
|
||||
if( xDel==SQLITE_DYNAMIC ){
|
||||
sqlite3DbFree(pMem->db, (void*)z);
|
||||
}else{
|
||||
xDel((void*)z);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
|
||||
}
|
||||
|
||||
/* The following block sets the new values of Mem.z and Mem.xDel. It
|
||||
@@ -1154,9 +1185,6 @@ int sqlite3VdbeMemSetStr(
|
||||
if( flags&MEM_Term ){
|
||||
nAlloc += (enc==SQLITE_UTF8?1:2);
|
||||
}
|
||||
if( nByte>iLimit ){
|
||||
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
|
||||
}
|
||||
testcase( nAlloc==0 );
|
||||
testcase( nAlloc==31 );
|
||||
testcase( nAlloc==32 );
|
||||
@@ -1178,16 +1206,7 @@ int sqlite3VdbeMemSetStr(
|
||||
|
||||
pMem->n = (int)(nByte & 0x7fffffff);
|
||||
pMem->flags = flags;
|
||||
if( enc ){
|
||||
pMem->enc = enc;
|
||||
#ifdef SQLITE_ENABLE_SESSION
|
||||
}else if( pMem->db==0 ){
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
#endif
|
||||
}else{
|
||||
assert( pMem->db!=0 );
|
||||
pMem->enc = ENC(pMem->db);
|
||||
}
|
||||
pMem->enc = enc;
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
|
||||
@@ -1195,9 +1214,6 @@ int sqlite3VdbeMemSetStr(
|
||||
}
|
||||
#endif
|
||||
|
||||
if( nByte>iLimit ){
|
||||
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -1479,6 +1495,7 @@ static int valueFromFunction(
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.pOut = pVal;
|
||||
ctx.pFunc = pFunc;
|
||||
ctx.enc = ENC(db);
|
||||
pFunc->xSFunc(&ctx, nVal, apVal);
|
||||
if( ctx.isError ){
|
||||
rc = ctx.isError;
|
||||
|
||||
+185
-72
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -2596,8 +2617,18 @@ static void whereLoopOutputAdjust(
|
||||
/* If there are extra terms in the WHERE clause not used by an index
|
||||
** that depend only on the table being scanned, and that will tend to
|
||||
** cause many rows to be omitted, then mark that table as
|
||||
** "self-culling". */
|
||||
pLoop->wsFlags |= WHERE_SELFCULL;
|
||||
** "self-culling".
|
||||
**
|
||||
** 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 an OUTER JOIN.
|
||||
*/
|
||||
if( (pTerm->eOperator & 0x3f)!=0
|
||||
|| (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype
|
||||
& (JT_LEFT|JT_LTORJ))==0
|
||||
){
|
||||
pLoop->wsFlags |= WHERE_SELFCULL;
|
||||
}
|
||||
}
|
||||
if( pTerm->truthProb<=0 ){
|
||||
/* If a truth probability is specified using the likelihood() hints,
|
||||
@@ -2801,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;
|
||||
@@ -3173,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
|
||||
@@ -3283,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 */
|
||||
@@ -3779,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
|
||||
|
||||
@@ -3970,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
|
||||
@@ -4094,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;
|
||||
@@ -4105,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);
|
||||
}
|
||||
}
|
||||
@@ -5168,7 +5215,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;
|
||||
}
|
||||
@@ -5399,7 +5446,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** field (type Bitmask) it must be aligned on an 8-byte boundary on
|
||||
** some architectures. Hence the ROUND8() below.
|
||||
*/
|
||||
nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
||||
nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
||||
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
@@ -5721,8 +5768,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;
|
||||
@@ -5824,6 +5873,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;
|
||||
@@ -5896,6 +5976,26 @@ whereBeginError:
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Return true if cursor iCur is opened by instruction k of the
|
||||
** bytecode. Used inside of assert() only.
|
||||
*/
|
||||
static int cursorIsOpen(Vdbe *v, int iCur, int k){
|
||||
while( k>=0 ){
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
|
||||
if( pOp->p1!=iCur ) continue;
|
||||
if( pOp->opcode==OP_Close ) return 0;
|
||||
if( pOp->opcode==OP_OpenRead ) return 1;
|
||||
if( pOp->opcode==OP_OpenWrite ) return 1;
|
||||
if( pOp->opcode==OP_OpenDup ) return 1;
|
||||
if( pOp->opcode==OP_OpenAutoindex ) return 1;
|
||||
if( pOp->opcode==OP_OpenEphemeral ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Generate the end of the WHERE loop. See comments on
|
||||
** sqlite3WhereBegin() for additional information.
|
||||
@@ -5916,6 +6016,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
|
||||
@@ -5943,7 +6055,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);
|
||||
@@ -5958,7 +6070,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 ){
|
||||
@@ -6008,6 +6120,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));
|
||||
@@ -6051,11 +6167,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;
|
||||
@@ -6066,6 +6177,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.
|
||||
@@ -6077,29 +6197,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
|
||||
@@ -6148,14 +6245,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
){
|
||||
int x = pOp->p2;
|
||||
assert( pIdx->pTable==pTab );
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
if( pOp->opcode==OP_Offset ){
|
||||
/* Do not need to translate the column number */
|
||||
}else
|
||||
#endif
|
||||
if( !HasRowid(pTab) ){
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
x = pPk->aiColumn[x];
|
||||
assert( x>=0 );
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
}else if( pOp->opcode==OP_Offset ){
|
||||
/* Do not need to translate the column number */
|
||||
#endif
|
||||
}else{
|
||||
testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
|
||||
x = sqlite3StorageColumnToTable(pTab,x);
|
||||
@@ -6165,12 +6263,22 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
pOp->p2 = x;
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
OpcodeRewriteTrace(db, k, pOp);
|
||||
}
|
||||
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0
|
||||
}else{
|
||||
/* Unable to translate the table reference into an index
|
||||
** reference. Verify that this is harmless - that the
|
||||
** table being referenced really is open.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
|| pOp->opcode==OP_Offset
|
||||
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||
|| cursorIsOpen(v,pOp->p1,k)
|
||||
|| pOp->opcode==OP_Offset
|
||||
);
|
||||
#else
|
||||
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||
|| cursorIsOpen(v,pOp->p1,k)
|
||||
);
|
||||
#endif
|
||||
|| pWInfo->eOnePass );
|
||||
}
|
||||
}else if( pOp->opcode==OP_Rowid ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
pOp->opcode = OP_IdxRowid;
|
||||
@@ -6189,6 +6297,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*);
|
||||
|
||||
+170
-11
@@ -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)",
|
||||
@@ -640,8 +643,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 +1067,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 +1153,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;
|
||||
@@ -1501,7 +1505,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 +1516,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 +2146,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 +2180,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 +2199,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. */
|
||||
@@ -2534,6 +2541,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
sqlite3VdbeGoto(v, pLevel->addrBrk);
|
||||
sqlite3VdbeResolveLabel(v, iLoopBody);
|
||||
|
||||
/* Set the P2 operand of the OP_Return opcode that will end the current
|
||||
** loop to point to this spot, which is the top of the next containing
|
||||
** loop. The byte-code formatter will use that P2 value as a hint to
|
||||
** indent everything in between the this point and the final OP_Return.
|
||||
** See tag-20220407a in vdbe.c and shell.c */
|
||||
assert( pLevel->op==OP_Return );
|
||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); }
|
||||
if( !untestedTerms ) disableTerm(pLevel, pTerm);
|
||||
}else
|
||||
@@ -2596,7 +2611,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;
|
||||
}
|
||||
|
||||
@@ -2658,7 +2675,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 ){
|
||||
@@ -2689,6 +2706,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.
|
||||
*/
|
||||
@@ -2704,12 +2762,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",
|
||||
@@ -2723,3 +2796,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--;
|
||||
}
|
||||
|
||||
+14
-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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -951,7 +948,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
|
||||
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
|
||||
if( pSrc->a[i].fg.isUsing==0 ){
|
||||
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
|
||||
}
|
||||
if( pSrc->a[i].fg.isTabFunc ){
|
||||
mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
|
||||
}
|
||||
@@ -1111,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 */
|
||||
@@ -1462,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 );
|
||||
@@ -1684,9 +1683,6 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
|
||||
a++;
|
||||
}
|
||||
}
|
||||
if( pWC->a!=pWC->aStatic ){
|
||||
sqlite3DbFree(db, pWC->a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1813,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",
|
||||
@@ -1829,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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,59 @@ 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;
|
||||
}
|
||||
|
||||
do_catchsql_test 19.2 {
|
||||
UPDATE t1 SET a=1;
|
||||
} {1 {UNIQUE constraint failed: index 'a'}}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ do_join_test e_select-0.1.3 {
|
||||
} {9}
|
||||
do_catchsql_test e_select-0.1.4 {
|
||||
SELECT count(*) FROM t1, t2 ON (t1.a=t2.a) USING (a)
|
||||
} {1 {cannot have both ON and USING clauses in the same join}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_catchsql_test e_select-0.1.5 {
|
||||
SELECT count(*) FROM t1, t2 USING (a) ON (t1.a=t2.a)
|
||||
} {1 {near "ON": syntax error}}
|
||||
|
||||
+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 {
|
||||
|
||||
+23
-12
@@ -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
|
||||
@@ -307,7 +309,7 @@ do_test join-3.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
|
||||
}
|
||||
} {1 {cannot have both ON and USING clauses in the same join}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test join-3.4.1 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 USING(a);
|
||||
@@ -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)
|
||||
|
||||
+36
-2
@@ -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 {
|
||||
@@ -300,6 +300,13 @@ do_execsql_test 7.3 {
|
||||
|
||||
do_eqp_test 7.4 {
|
||||
SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?);
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t3
|
||||
`--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 = ?);
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--SCAN t3
|
||||
@@ -360,5 +367,32 @@ do_execsql_test 10.1 {
|
||||
SELECT x FROM v3;
|
||||
} {0}
|
||||
|
||||
# 2022-03-24 https://sqlite.org/forum/forumpost/031e262a89b6a9d2
|
||||
# Bloom-filter on a LEFT JOIN with NULL-based WHERE constraints.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT);
|
||||
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<8)
|
||||
INSERT INTO t1(a,b) SELECT x, 10*x FROM c;
|
||||
INSERT INTO t2(c,d) SELECT b*2, 100*a FROM t1;
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1;
|
||||
INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES
|
||||
('t1',NULL,150105),('t2',NULL,98747);
|
||||
ANALYZE sqlite_schema;
|
||||
} {}
|
||||
do_execsql_test 11.2 {
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d IS NULL;
|
||||
} {4}
|
||||
do_execsql_test 11.3 {
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d=100;
|
||||
} {1}
|
||||
do_execsql_test 11.4 {
|
||||
SELECT count(*) FROM t1 LEFT JOIN t2 ON c=b WHERE d>=300;
|
||||
} {2}
|
||||
|
||||
|
||||
|
||||
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
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
# 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 {- -}}
|
||||
|
||||
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
@@ -850,4 +850,21 @@ do_execsql_test json-17.1 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (SELECT b FROM json_each ORDER BY 1);
|
||||
} {}
|
||||
|
||||
# 2022-04-04 forum post https://sqlite.org/forum/forumpost/c082aeab43
|
||||
do_execsql_test json-18.1 {
|
||||
SELECT json_valid('{"":5}');
|
||||
} {1}
|
||||
do_execsql_test json-18.2 {
|
||||
SELECT json_extract('{"":5}', '$.""');
|
||||
} {5}
|
||||
do_execsql_test json-18.3 {
|
||||
SELECT json_extract('[3,{"a":4,"":[5,{"hi":6},7]},8]', '$[1].""[1].hi');
|
||||
} {6}
|
||||
do_execsql_test json-18.4 {
|
||||
SELECT json_extract('[3,{"a":4,"":[5,{"hi":6},7]},8]', '$[1].""[1]."hi"');
|
||||
} {6}
|
||||
do_catchsql_test json-18.5 {
|
||||
SELECT json_extract('{"":8}', '$.');
|
||||
} {1 {JSON path error near ''}}
|
||||
|
||||
finish_test
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -34,13 +34,13 @@ do_test tkt3935.3 {
|
||||
|
||||
do_test tkt3935.4 {
|
||||
catchsql { SELECT a FROM (t1) AS t ON b USING(a) }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test tkt3935.5 {
|
||||
catchsql { SELECT a FROM (t1) AS t ON b }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
do_test tkt3935.6 {
|
||||
catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test tkt3935.7 {
|
||||
catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
@@ -49,7 +49,7 @@ do_test tkt3935.8 {
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
do_test tkt3935.9 {
|
||||
catchsql { SELECT a FROM t1 AS t ON b USING(a) }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test tkt3935.10 {
|
||||
catchsql { SELECT a FROM t1 AS t USING(a) }
|
||||
} {1 {a JOIN clause is required before USING}}
|
||||
|
||||
@@ -382,4 +382,24 @@ do_execsql_test 6.2 {
|
||||
)
|
||||
} {}
|
||||
|
||||
# 2022-03-21
|
||||
# https://sqlite.org/forum/forumpost/929168fdd6
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1(a) VALUES(11),(22),(33),(44),(55);
|
||||
CREATE VIEW t2(b,c) AS SELECT a, COUNT(*) OVER () FROM t1;
|
||||
CREATE TABLE t3(x,y);
|
||||
CREATE TRIGGER t2r1 INSTEAD OF UPDATE ON t2 BEGIN
|
||||
INSERT INTO t3(x,y) VALUES(new.b,new.c);
|
||||
END;
|
||||
SELECT * FROM t2;
|
||||
} {11 5 22 5 33 5 44 5 55 5}
|
||||
do_execsql_test 7.1 {
|
||||
UPDATE t2 SET c=t1.a FROM t1 WHERE t2.b=t1.a;
|
||||
SELECT * FROM t3;
|
||||
} {11 11 22 22 33 33 44 44 55 55}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+8
-8
@@ -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
|
||||
@@ -263,7 +263,7 @@ do_test vtab6-3.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
|
||||
}
|
||||
} {1 {cannot have both ON and USING clauses in the same join}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test vtab6-3.4 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 USING(a);
|
||||
@@ -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
|
||||
|
||||
@@ -3015,6 +3015,7 @@ void Parse(struct lemon *gp)
|
||||
}
|
||||
if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */
|
||||
cp+=2;
|
||||
if( (*cp)=='/' ) cp++;
|
||||
while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){
|
||||
if( c=='\n' ) lineno++;
|
||||
cp++;
|
||||
|
||||
+1
-1
@@ -158,7 +158,6 @@ set boolean_defnil_options {
|
||||
SQLITE_ENABLE_QPSG
|
||||
SQLITE_ENABLE_RBU
|
||||
SQLITE_ENABLE_RTREE
|
||||
SQLITE_ENABLE_SELECTTRACE
|
||||
SQLITE_ENABLE_SESSION
|
||||
SQLITE_ENABLE_SNAPSHOT
|
||||
SQLITE_ENABLE_SORTER_REFERENCES
|
||||
@@ -166,6 +165,7 @@ set boolean_defnil_options {
|
||||
SQLITE_ENABLE_STAT4
|
||||
SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
SQLITE_ENABLE_STMTVTAB
|
||||
SQLITE_ENABLE_TREETRACE
|
||||
SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
|
||||
+2
-1
@@ -291,7 +291,8 @@ proc copy_file {filename} {
|
||||
# Add the SQLITE_PRIVATE before variable declarations or
|
||||
# definitions for internal use
|
||||
regsub {^SQLITE_API } $line {} line
|
||||
if {![regexp {^sqlite3_} $varname]} {
|
||||
if {![regexp {^sqlite3_} $varname]
|
||||
&& ![regexp {^sqlite3Show[A-Z]} $varname]} {
|
||||
regsub {^extern } $line {} line
|
||||
puts $out "SQLITE_PRIVATE $line"
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user