Compare commits
12 Commits
resfmt
...
multi-drop
| Author | SHA1 | Date | |
|---|---|---|---|
| 4760a0655f | |||
| 313aaff7cd | |||
| 4859e9c642 | |||
| 3ffea6bc31 | |||
| c5c3cde0e3 | |||
| 29962f9194 | |||
| 0809210f9d | |||
| b3e1f4cc3c | |||
| b0f9538628 | |||
| 19fb027eb5 | |||
| c3004fc223 | |||
| 6b4c974bec |
+3
-3
@@ -1053,9 +1053,9 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
int rc;
|
||||
char *zCreate = sqlite3_mprintf(
|
||||
"DROP TABLE '%q'.'%q_node';"
|
||||
"DROP TABLE '%q'.'%q_rowid';"
|
||||
"DROP TABLE '%q'.'%q_parent';",
|
||||
"DROP TABLE '%q'.'%q_node',"
|
||||
"'%q'.'%q_rowid',"
|
||||
"'%q'.'%q_parent';",
|
||||
pRtree->zDb, pRtree->zName,
|
||||
pRtree->zDb, pRtree->zName,
|
||||
pRtree->zDb, pRtree->zName
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Fix\stwo\s-Werror=lto-type-mismatch\swarnings\sreported\sin\s[forum:ef62b57bd5|forum\spost\sef62b57bd5].
|
||||
D 2024-02-29T10:55:02.008
|
||||
C The\sability\sto\sDROP\smultiple\stables\s(or\sviews\sor\sindexes\sor\striggers)\sat\sonce,\nas\simplemented\sby\sthis\sbranch,\sappears\sto\swork.\s\sHowever,\sthis\sbranch\sadds\sover\n1000\sbytes\sto\sthe\scode\sfootprint.\s\sAnd\sthe\schanges\sis\ssignificant,\sadding\srisk.\nThe\sbenefit\sof\sbeing\sable\sto\sdrop\smultiple\stables\sin\sa\ssingle\sstatement\sis\snot\nseen\sto\sbe\senough\sto\sovercome\sthose\sdownsides,\sand\sso\sthere\sare\sno\simmediate\nplans\sto\smerge\sthis\sbranch.
|
||||
D 2024-03-04T18:02:36.966
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -506,7 +506,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
|
||||
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/geopoly.c 0dd4775e896cee6067979d67aff7c998e75c2c9d9cd8d62a1a790c09cde7adca
|
||||
F ext/rtree/rtree.c 1baf9f6aa7251ddecdb019d914df4db46eb227720c00f89c485c66dbfdc7863d
|
||||
F ext/rtree/rtree.c c65a133bb697d20c0ac60ac09dc3a1cbf55500bfd6e9e730d2469aa6113480ed
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test 2b5b8c719c6a4abe377f57766f428a49af36a93061cb146cccfdc3b30000c0a4
|
||||
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
|
||||
@@ -692,7 +692,7 @@ F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
|
||||
F src/btree.c 285b493d843e7ba8ef78b6ae7d31238e904901dbc0c484f7904de4cf18fd8802
|
||||
F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0
|
||||
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
|
||||
F src/build.c 04f1bcee189f045ab086d84fee95db42cb49df82ff8e84af8136309ff3c8a75f
|
||||
F src/build.c 7ee3616b8a25577f2fb715d91eaa27f62a34e6ee6d0130cc8b9644c07875b759
|
||||
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
|
||||
@@ -702,7 +702,7 @@ F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
||||
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
||||
F src/expr.c 2803f5e7e3458ced24c0de48ec3640cd7a68ec61350d99c9f30b1bcd6640bd61
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
|
||||
F src/fkey.c 0592046ed7598625234298211cc1fe611efb3fe7870a3f1938038fd9092c82f9
|
||||
F src/func.c 4204c56196847faefef57fa14e43b8e4d65eb8d7e65318abe463472e3fd148cb
|
||||
F src/global.c 765a0656d6cbf043cb272ff0ae38f39cc46713539ffe6793258ed3eb4b188b52
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
@@ -739,7 +739,7 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
|
||||
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
||||
F src/parse.y 6209f01e8e7495379571454744fa82a5cfc2e7eeb89e46dee3f410d73ea6252d
|
||||
F src/parse.y 9a77520c83950ced6e8b981c7826ebfd8e4a5c6e4b5d9743639e357910180c94
|
||||
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
|
||||
@@ -755,7 +755,7 @@ F src/shell.c.in 2ec564ed3ff0147036be313efeb47b3dbfb8753d5eb5ea0e90636427c6b3a36
|
||||
F src/sqlite.h.in 19a2db3995a699bd7f6dfb423856242bfceb7ec849a93c91d241d19fc28d9f0f
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h 58b7295a748ca5ed9e211510205b4a66a24c68f864225b81e19d4cf6038b40a1
|
||||
F src/sqliteInt.h 532224eec9f53245c8450c662c2a9d06a1aec22cb28e5fc4cdfd0f67239e9049
|
||||
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
|
||||
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -814,7 +814,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 3f703cacdab728d7741e5a6ac242006d74fe1c2754d4f03ed889d7253259bd68
|
||||
F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee
|
||||
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
|
||||
F src/trigger.c 15ca35f491c03197c3ccd5a0b3c5b926719cbe4e185b73da0507dbeb84a52d0e
|
||||
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
|
||||
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
|
||||
F src/utf.c f23165685a67b4caf8ec08fb274cb3f319103decfb2a980b7cfd55d18dfa855e
|
||||
@@ -845,14 +845,14 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
|
||||
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
|
||||
F test/aggnested.test 610b0ce2c3e8f3daee25f9752800ee8d785db10da4aa1fbeea0ea1aabaf1d704
|
||||
F test/aggorderby.test cc3abf5de64d46ff66395ca8c2346b66c2576d5aedb7bffc5b0742508856e3bf
|
||||
F test/aggnested.test 4dfdbfab105cec5750a1eeb59284ffffc3b37a32aaaf09143df3f549e28e2081
|
||||
F test/aggorderby.test af1e07766e8f752d54dd317aa1d956e8e896671a70ddb20228e8cdf9391023b1
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||
F test/alter.test 3c00eff1e2036b9f93e9cd0f3d3e63750ac87ecb5bc71b9d7bd07cbf2ac4c494
|
||||
F test/alter2.test 7e3d26ab409df52df887b366a63902c3429b935c41cb962fd58ffc25784f2f19
|
||||
F test/alter3.test ffc4ab29ce78a3517a66afd69b2730667e3471622509c283b2bd4c46f680fba3
|
||||
F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707
|
||||
F test/alter3.test 0663df0cb3b9558ccc21abe642b792d4e2e747164156208e2a44ce88c09fe09b
|
||||
F test/alter4.test 0ef8e62259bbc17495456d19e33a97b14cc2f634ef67bfdfb6a3f826eb9cfbc1
|
||||
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
||||
F test/alterauth2.test 48967abae0494d9a300d1c92473d99fcb66edfcc23579c89322f033f49410adc
|
||||
F test/altercol.test 29fed774747777fbbaacdd865b4413ed2d0844a4c824f8af531b5c7d4a832087
|
||||
@@ -870,7 +870,7 @@ F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5
|
||||
F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16
|
||||
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
|
||||
F test/analyze.test e8ab7a3fa8b0294dd72c6d0acd822c3b69fd4ab9392789b29dd29daaa8601b4c
|
||||
F test/analyze3.test 03f4b3d794760cf15da2d85a52df9bae300e51c8fefe9c36cfae1f86dc10d23f
|
||||
F test/analyze4.test 68bd069f3ac7ac1e652ddd9f04f57d5606ddb4208450f5297005db7aa0dd707d
|
||||
F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19dddc0d
|
||||
@@ -898,7 +898,7 @@ F test/attach2.test 6d1e3a457ce260d6fc8e5945c07fba6c76dc2aa90e1c701f067b50ee88f7
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e
|
||||
F test/attachmalloc.test 67309af95c6b765c13e7d2279d7fccbef78e6eb0565d75d51cefd5dc88784549
|
||||
F test/auth.test 5b8558a40571ebc55c1581cb7cec3b2348a699542a0a51b83ef21c6a953d95e3
|
||||
F test/auth.test 8d4152a8dca10e6dbe15b0c6dfcc183d5e9a7f6f983d9ae6e05f70e947aed7c3
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
@@ -1069,6 +1069,7 @@ F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 691c9e850b0d0b56b66e7e235453198cb4cf0760e324b7403d3c5abbeab0a014
|
||||
F test/distinct2.test bb71cc7b5e58e895787f9910a788c254f679928d324732d063fe9bc202ecbe71
|
||||
F test/distinctagg.test 40d7169ae5846caaf62c6e307d2ca3c333daf9b6f7cde888956a339a97afe85f
|
||||
F test/drop-many.test 30dd091a4fd0a04b1a38e70c93f69c55749e62a3d895ac5e09277cd97caa5bbf
|
||||
F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52
|
||||
F test/e_blobclose.test 692fc02a058476c2222a63d97e3f3b2b809c1842e5525ded7f854d540ac2e075
|
||||
F test/e_blobopen.test 29f6055ee453b8e679fe9570c4d3acfedbef821622c5dad16875148c5952ef50
|
||||
@@ -1119,7 +1120,7 @@ F test/filter1.test 590f8ba9a0cd0823b80d89ac75c5ce72276189cef9225d2436adaf1ee87f
|
||||
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
|
||||
F test/filter2.test 3cc20eaea2ea1ab245197cc4a62468deb460b78f5aa9bd7d5d3353c2fe569bae
|
||||
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
|
||||
F test/fkey1.test e563bcb4cb108ce3f40363cda4f84009dc89a39e2973076e5057ba99fca35378
|
||||
F test/fkey1.test 6cf3fb520def0950799499b5bd0c6f22517cf7b6aee07523cbb52c1496aa8d00
|
||||
F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb304c
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
@@ -2176,9 +2177,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 d51c699ae413215d534f954c129691ef5d95d540dc5d4304cbba576c976d931c 29f94610dc8319709b8d3726a60e2a7a33ffbf4998c681f772da26c9701cc0b0
|
||||
R 728f9a968510fa9cb95ea7ce7eec45f1
|
||||
T +closed 29f94610dc8319709b8d3726a60e2a7a33ffbf4998c681f772da26c9701cc0b0 Closed\sby\sintegrate-merge.
|
||||
U stephan
|
||||
Z 37dee8fa6539319388e07ab4c515c697
|
||||
P 26272590691aee8569a1ea9c233f9b0e55ece63ed167696cc1ecfe3ca2548ba1
|
||||
R ffcb677589cb061417252fbc7f9600de
|
||||
U drh
|
||||
Z 148d8810a6ba162cbd3b9cd95d027cbb
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
803481f25020f3c25941f1e7d1a8071937820dea951e8798198b0b0fa3fb48ce
|
||||
1a49788afd90fa4415c6aae4b6bbad68f9306c1df1026762a9d88bcb40e4cd8f
|
||||
+292
-194
@@ -3260,84 +3260,129 @@ void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Write code to erase the table with root-page iTable from database iDb.
|
||||
** Also write code to modify the sqlite_schema table and internal schema
|
||||
** if a root-page of another table is moved by the btree-layer whilst
|
||||
** erasing iTable (this can happen with an auto-vacuum database).
|
||||
** The RootStack object holds a list (really a Heap) of btree root pages
|
||||
** and schema numbers that need to be deleted using OP_Destroy.
|
||||
**
|
||||
** OP_Destroy opcodes must be issued in order of decreasing root page
|
||||
** numbers in order to avoid having auto-vacuum disrupt subsequent
|
||||
** OP_Destroy opcodes. For that reason, all pending OP_Destroy calls
|
||||
** are accumulated in an instance of this object. Then at the end of
|
||||
** code generation, this object is used to generate the OP_Destroy opcodes
|
||||
** in decreasing order.
|
||||
**
|
||||
** The data structure is a max-heap. Each rootpage/schema-number combo
|
||||
** is stored as a 64-bit integer, with the schema-number in the upper 32
|
||||
** bits and the page number in the lower 32-bits. The root of the heap
|
||||
** (RootStack.a[0]) is the largest entry in the heap. The children of
|
||||
** heap entry i are i*2+1 and i*2+2. The heap always stays balanced by
|
||||
** ensuring that a parent entry is larger than both children.
|
||||
**
|
||||
*/
|
||||
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
|
||||
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
|
||||
sqlite3MayAbort(pParse);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
/* OP_Destroy stores an in integer r1. If this integer
|
||||
** is non-zero, then it is the root page number of a table moved to
|
||||
** location iTable. The following code modifies the sqlite_schema table to
|
||||
** reflect this.
|
||||
**
|
||||
** The "#NNN" in the SQL is a special constant that means whatever value
|
||||
** is in register NNN. See grammar rules associated with the TK_REGISTER
|
||||
** token for additional information.
|
||||
*/
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q." LEGACY_SCHEMA_TABLE
|
||||
" SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
||||
pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
|
||||
#endif
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
typedef struct RootStack RootStack;
|
||||
struct RootStack {
|
||||
u32 nAlloc; /* Slots allocated for a[] */
|
||||
u32 nUsed; /* Slots used for in a[] */
|
||||
u64 *a; /* Sorting heap. Each entry has iDb in the upper 32 bits and
|
||||
** a page number in the lower 32 bits */
|
||||
};
|
||||
|
||||
/*
|
||||
** Add a new Pgno and iDb to the RootStack in question.
|
||||
**
|
||||
** The new entry is inserted at the of the heap (most distant child)
|
||||
** and then the heap is rebalanced.
|
||||
*/
|
||||
static void rootStackPush(Parse *pParse, RootStack *p, Pgno pgno, int iDb){
|
||||
u64 iNew;
|
||||
int i, j;
|
||||
if( p->nAlloc<p->nUsed+1 ){
|
||||
p->nAlloc = p->nAlloc*2 + 12;
|
||||
p->a = sqlite3DbRealloc(pParse->db, p->a, sizeof(Pgno)*p->nAlloc);
|
||||
if( p->a==0 ){
|
||||
p->nAlloc = p->nUsed = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert( pgno>0 || CORRUPT_DB );
|
||||
assert( iDb>=0 && iDb<pParse->db->nDb );
|
||||
iNew = (((u64)iDb)<<32) | pgno;
|
||||
i = p->nUsed++;
|
||||
p->a[i] = iNew;
|
||||
while( i>=1 && p->a[j = (i-1)/2]<p->a[i] ){
|
||||
u64 tmp = p->a[i];
|
||||
p->a[i] = p->a[j];
|
||||
p->a[j] = tmp;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Write VDBE code to erase table pTab and all associated indices on disk.
|
||||
** Code to update the sqlite_schema tables and internal schema definitions
|
||||
** in case a root-page belonging to another table is moved by the btree layer
|
||||
** is also added (this can happen with an auto-vacuum database).
|
||||
** Remove the largest entry from the RootStack heap. Rebalance the
|
||||
** heap and then return that largest entry.
|
||||
*/
|
||||
static void destroyTable(Parse *pParse, Table *pTab){
|
||||
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
|
||||
** is not defined), then it is important to call OP_Destroy on the
|
||||
** table and index root-pages in order, starting with the numerically
|
||||
** largest root-page number. This guarantees that none of the root-pages
|
||||
** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
|
||||
** following were coded:
|
||||
**
|
||||
** OP_Destroy 4 0
|
||||
** ...
|
||||
** OP_Destroy 5 0
|
||||
**
|
||||
** and root page 5 happened to be the largest root-page number in the
|
||||
** database, then root page 5 would be moved to page 4 by the
|
||||
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
|
||||
** a free-list page.
|
||||
*/
|
||||
Pgno iTab = pTab->tnum;
|
||||
Pgno iDestroyed = 0;
|
||||
|
||||
while( 1 ){
|
||||
Index *pIdx;
|
||||
Pgno iLargest = 0;
|
||||
|
||||
if( iDestroyed==0 || iTab<iDestroyed ){
|
||||
iLargest = iTab;
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
Pgno iIdx = pIdx->tnum;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
|
||||
iLargest = iIdx;
|
||||
}
|
||||
}
|
||||
if( iLargest==0 ){
|
||||
return;
|
||||
}else{
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<pParse->db->nDb );
|
||||
destroyRootPage(pParse, iLargest, iDb);
|
||||
iDestroyed = iLargest;
|
||||
}
|
||||
static u64 rootStackPop(RootStack *p){
|
||||
u64 iMax;
|
||||
int i, j;
|
||||
assert( p->nUsed>0 );
|
||||
assert( p->a!=0 );
|
||||
iMax = p->a[0];
|
||||
p->a[0] = p->a[--p->nUsed];
|
||||
i = 0;
|
||||
while( (j = i*2+1)<p->nUsed ){
|
||||
u64 tmp;
|
||||
if( j+1<p->nUsed && p->a[j+1]>p->a[j] ) j++;
|
||||
if( p->a[i]>p->a[j] ) break;
|
||||
tmp = p->a[i];
|
||||
p->a[i] = p->a[j];
|
||||
p->a[j] = tmp;
|
||||
i = j;
|
||||
}
|
||||
return iMax;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate OP_Destroy opcodes for every btree named in the given
|
||||
** RootStack object. Issue these OP_Destroy opcodes in order of decreasing
|
||||
** root page number. Then clean up any memory used by the RootStack.
|
||||
*/
|
||||
static void rootStackCode(Parse *pParse, RootStack *p){
|
||||
int iLastDb = -1;
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
int r2 = sqlite3GetTempReg(pParse);
|
||||
int regReturn = sqlite3GetTempReg(pParse);
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int addrSub = 0;
|
||||
while( pParse->nErr==0 && p->nUsed>0 ){
|
||||
u64 iNext = rootStackPop(p);
|
||||
Pgno pgno = iNext & 0xffffffff;
|
||||
int iDb = (iNext>>32)&0xffff;
|
||||
if( pgno<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
|
||||
sqlite3MayAbort(pParse);
|
||||
if( iDb!=iLastDb ){
|
||||
/* Code a subroutine to that will update the schema table when
|
||||
** a root page number changes. The old root page is in register r1.
|
||||
** Root page is moved to the value in register r2. */
|
||||
iLastDb = iDb;
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrSub = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q." LEGACY_SCHEMA_TABLE
|
||||
" SET rootpage=#%d WHERE rootpage=#%d",
|
||||
pParse->db->aDb[iDb].zDbSName, r2, r1);
|
||||
sqlite3VdbeAddOp1(v, OP_Return, regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrSub-1);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Destroy, pgno, r1, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, r1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pgno, r2);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, addrSub);
|
||||
}
|
||||
if( pParse->nErr==0 ){
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, regReturn);
|
||||
}
|
||||
sqlite3DbFree(pParse->db, p->a);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3367,7 +3412,12 @@ static void sqlite3ClearStatTables(
|
||||
/*
|
||||
** Generate code to drop a table.
|
||||
*/
|
||||
void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
static void sqlite3CodeDropTable(
|
||||
Parse *pParse, /* Parsing context */
|
||||
RootStack *pStack, /* List of pending OP_Destroys */
|
||||
Table *pTab, /* Table to be dropped */
|
||||
int iDb /* Schema holding pTab */
|
||||
){
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
Trigger *pTrigger;
|
||||
@@ -3420,8 +3470,13 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE
|
||||
" WHERE tbl_name=%Q and type!='trigger'",
|
||||
pDb->zDbSName, pTab->zName);
|
||||
if( !isView && !IsVirtual(pTab) ){
|
||||
destroyTable(pParse, pTab);
|
||||
if( IsOrdinaryTable(pTab) ){
|
||||
Index *pIdx;
|
||||
rootStackPush(pParse, pStack, pTab->tnum, iDb);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->tnum==pTab->tnum ) continue;
|
||||
rootStackPush(pParse, pStack, pIdx->tnum, iDb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the table entry from SQLite's internal schema and modify
|
||||
@@ -3477,106 +3532,134 @@ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
|
||||
*/
|
||||
void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
Table *pTab;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
int ii, jj;
|
||||
RootStack rootStack;
|
||||
|
||||
if( db->mallocFailed ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
memset(&rootStack, 0, sizeof(rootStack));
|
||||
(void)sqlite3GetVdbe(pParse);
|
||||
sqlite3ReadSchema(pParse);
|
||||
assert( pName!=0 || pParse->nErr!=0 );
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[ii]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
|
||||
if( pTab==0 ){
|
||||
if( noErr ){
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
if( pTab==0 ){
|
||||
if( noErr ){
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[ii].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
}
|
||||
testcase( ii+1<pName->nSrc );
|
||||
continue;
|
||||
}
|
||||
goto exit_drop_table;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
|
||||
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
|
||||
** it is initialized.
|
||||
*/
|
||||
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
|
||||
** it is initialized.
|
||||
*/
|
||||
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zArg2 = 0;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( isView ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_VIEW;
|
||||
}else{
|
||||
code = SQLITE_DROP_VIEW;
|
||||
{
|
||||
int code;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zArg2 = 0;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
if( isView ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_VIEW;
|
||||
}else{
|
||||
code = SQLITE_DROP_VIEW;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
}else if( IsVirtual(pTab) ){
|
||||
code = SQLITE_DROP_VTABLE;
|
||||
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
|
||||
}else if( IsVirtual(pTab) ){
|
||||
code = SQLITE_DROP_VTABLE;
|
||||
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
|
||||
#endif
|
||||
}else{
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_TABLE;
|
||||
}else{
|
||||
code = SQLITE_DROP_TABLE;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
code = SQLITE_DROP_TEMP_TABLE;
|
||||
}else{
|
||||
code = SQLITE_DROP_TABLE;
|
||||
}
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
goto exit_drop_table;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( tableMayNotBeDropped(db, pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( tableMayNotBeDropped(db, pTab) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
|
||||
** on a table.
|
||||
*/
|
||||
if( isView && !IsView(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
if( !isView && IsView(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
|
||||
** on a table.
|
||||
*/
|
||||
if( isView && !IsView(pTab) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
|
||||
break;
|
||||
}
|
||||
if( !isView && IsView(pTab) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* If this table or view has appeared previously in the list of tables
|
||||
** or views to be dropped, then the prior appearance is sufficient so
|
||||
** skip this one. */
|
||||
for(jj=ii-1; jj>=0 && pName->a[jj].pTab!=pTab; jj--){}
|
||||
if( jj>=0 ) continue;
|
||||
|
||||
/* Generate code to remove the table from the schema table
|
||||
** on disk.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
/* Remember the table for use in the second pass */
|
||||
pName->a[ii].pTab = pTab;
|
||||
pTab->nTabRef++;
|
||||
|
||||
/* Generate code to clear this table from sqlite_statN and to
|
||||
** cascade foreign key constraints.
|
||||
*/
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
if( !isView ){
|
||||
if( IsOrdinaryTable(pTab) ){
|
||||
sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
|
||||
sqlite3FkDropTable(pParse, pName, pTab);
|
||||
}
|
||||
sqlite3CodeDropTable(pParse, pTab, iDb, isView);
|
||||
}
|
||||
|
||||
exit_drop_table:
|
||||
/* Generate code to actually delete the tables/views in a second pass.
|
||||
** Btrees must be deleted largest root page first, to avoid problems
|
||||
** caused by autovacuum page reordering. */
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
pTab = pName->a[ii].pTab;
|
||||
if( pTab==0 ) continue;
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeDropTable(pParse, &rootStack, pTab, iDb);
|
||||
}
|
||||
sqlite3SrcListDelete(db, pName);
|
||||
rootStackCode(pParse, &rootStack);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4576,67 +4659,82 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
*/
|
||||
void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
Index *pIndex;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
Vdbe *v;
|
||||
int iDb;
|
||||
int ii, jj;
|
||||
RootStack rootStack;
|
||||
|
||||
if( db->mallocFailed ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
|
||||
assert( pName->nSrc==1 );
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
|
||||
if( pIndex==0 ){
|
||||
if( !ifExists ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
memset(&rootStack, 0, sizeof(rootStack));
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3ReadSchema(pParse);
|
||||
assert( pName!=0 || pParse->nErr!=0 );
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
pName->a[ii].regReturn = 0;
|
||||
pIndex = sqlite3FindIndex(db, pName->a[ii].zName, pName->a[ii].zDatabase);
|
||||
if( pIndex==0 ){
|
||||
if( !ifExists ){
|
||||
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a+ii);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, pName->a[ii].zDatabase);
|
||||
sqlite3ForceNotReadOnly(pParse);
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
continue;
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
goto exit_drop_index;
|
||||
}
|
||||
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
||||
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
||||
"or PRIMARY KEY constraint cannot be dropped", 0);
|
||||
goto exit_drop_index;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
|
||||
sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
|
||||
"or PRIMARY KEY constraint cannot be dropped", 0);
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
Table *pTab = pIndex->pTable;
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
goto exit_drop_index;
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
Table *pTab = pIndex->pTable;
|
||||
const char *zDb = db->aDb[iDb].zDbSName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
|
||||
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
|
||||
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code to remove the index and from the schema table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
/* Skip over redundant DROP INDEXes */
|
||||
for(jj=ii-1; jj>=0 && pName->a[jj].u2.pIdx!=pIndex; jj--){}
|
||||
if( jj>=0 ) continue;
|
||||
|
||||
/* Record that this index needs to be dropped. */
|
||||
pName->a[ii].u2.pIdx = pIndex;
|
||||
|
||||
/* Generate code to remove the index and from the schema table and
|
||||
** from sqlite_statN tables */
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
|
||||
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE
|
||||
" WHERE name=%Q AND type='index'",
|
||||
db->aDb[iDb].zDbSName, pIndex->zName
|
||||
);
|
||||
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
|
||||
|
||||
rootStackPush(pParse, &rootStack, pIndex->tnum, iDb);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
destroyRootPage(pParse, pIndex->tnum, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
|
||||
}
|
||||
|
||||
exit_drop_index:
|
||||
sqlite3SrcListDelete(db, pName);
|
||||
rootStackCode(pParse, &rootStack);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+25
-6
@@ -718,8 +718,9 @@ void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
|
||||
/*
|
||||
** This function is called to generate code that runs when table pTab is
|
||||
** being dropped from the database. The SrcList passed as the second argument
|
||||
** to this function contains a single entry guaranteed to resolve to
|
||||
** table pTab.
|
||||
** to this function contains entries for every table that is being dropped,
|
||||
** with the SrcItem.pTab line being set to the table being dropped. pTab
|
||||
** will be one of those tables.
|
||||
**
|
||||
** Normally, no code is required. However, if either
|
||||
**
|
||||
@@ -728,15 +729,23 @@ void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
|
||||
** determined at runtime that there are outstanding deferred FK
|
||||
** constraint violations in the database,
|
||||
**
|
||||
** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
|
||||
** the table from the database. Triggers are disabled while running this
|
||||
** DELETE, but foreign key actions are not.
|
||||
** then the equivalent of "DELETE FROM <tbl>" is executed for every table
|
||||
** being dropped, in the order specified in the DROP TABLE statement, which
|
||||
** is the same as the order in which these tables appear in pName.
|
||||
** Triggers are disabled while running these DELETEs, but foreign key
|
||||
** actions are not.
|
||||
**
|
||||
** This routine sets the SrcList.addrFillSub value for all pName entries
|
||||
** for which DELETE FROM has been run. This prevents the DELETE FROM
|
||||
** from being run multiple times.
|
||||
*/
|
||||
void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){
|
||||
int iSkip = 0;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
SrcList *pSrc;
|
||||
int ii;
|
||||
|
||||
assert( v ); /* VDBE has already been allocated */
|
||||
assert( IsOrdinaryTable(pTab) );
|
||||
@@ -756,7 +765,17 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
}
|
||||
|
||||
pParse->disableTriggers = 1;
|
||||
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
|
||||
for(ii=0; ii<pName->nSrc; ii++){
|
||||
if( pName->a[ii].pTab==0 ) continue;
|
||||
if( pName->a[ii].addrFillSub ) continue;
|
||||
pName->a[ii].addrFillSub = 1;
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
pSrc->a[0].zDatabase = sqlite3DbStrDup(db, pName->a[ii].zDatabase);
|
||||
pSrc->a[0].zName = sqlite3DbStrDup(db, pName->a[ii].zName);
|
||||
sqlite3DeleteFrom(pParse, pSrc, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
pParse->disableTriggers = 0;
|
||||
|
||||
/* If the DELETE has generated immediate foreign key constraint
|
||||
|
||||
+16
-4
@@ -471,7 +471,7 @@ resolvetype(A) ::= REPLACE. {A = OE_Replace;}
|
||||
|
||||
////////////////////////// The DROP TABLE /////////////////////////////////////
|
||||
//
|
||||
cmd ::= DROP TABLE ifexists(E) fullname(X). {
|
||||
cmd ::= DROP TABLE ifexists(E) fullnamelist(X). {
|
||||
sqlite3DropTable(pParse, X, 0, E);
|
||||
}
|
||||
%type ifexists {int}
|
||||
@@ -485,7 +485,7 @@ cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C)
|
||||
AS select(S). {
|
||||
sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E);
|
||||
}
|
||||
cmd ::= DROP VIEW ifexists(E) fullname(X). {
|
||||
cmd ::= DROP VIEW ifexists(E) fullnamelist(X). {
|
||||
sqlite3DropTable(pParse, X, 1, E);
|
||||
}
|
||||
%endif SQLITE_OMIT_VIEW
|
||||
@@ -774,6 +774,18 @@ fullname(A) ::= nm(X) DOT nm(Y). {
|
||||
if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y);
|
||||
}
|
||||
|
||||
%type fullnamelist {SrcList*}
|
||||
%destructor fullnamelist {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
fullnamelist(A) ::= fullname(A).
|
||||
fullnamelist(A) ::= fullnamelist(L) COMMA nm(X). {
|
||||
A = sqlite3SrcListAppend(pParse,L,&X,0);
|
||||
assert( !IN_RENAME_OBJECT ); /* Used only by DROP, which cannot be part of schema */
|
||||
}
|
||||
fullnamelist(A) ::= fullnamelist(L) COMMA nm(X) DOT nm(Y). {
|
||||
A = sqlite3SrcListAppend(pParse,L,&X,&Y);
|
||||
assert( !IN_RENAME_OBJECT ); /* Used only by DROP, which cannot be part of schema */
|
||||
}
|
||||
|
||||
%type xfullname {SrcList*}
|
||||
%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
xfullname(A) ::= nm(X).
|
||||
@@ -1504,7 +1516,7 @@ collate(C) ::= COLLATE ids. {C = 1;}
|
||||
|
||||
///////////////////////////// The DROP INDEX command /////////////////////////
|
||||
//
|
||||
cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
|
||||
cmd ::= DROP INDEX ifexists(E) fullnamelist(X). {sqlite3DropIndex(pParse, X, E);}
|
||||
|
||||
///////////////////////////// The VACUUM command /////////////////////////////
|
||||
//
|
||||
@@ -1661,7 +1673,7 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
|
||||
|
||||
//////////////////////// DROP TRIGGER statement //////////////////////////////
|
||||
%ifndef SQLITE_OMIT_TRIGGER
|
||||
cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
|
||||
cmd ::= DROP TRIGGER ifexists(NOERR) fullnamelist(X). {
|
||||
sqlite3DropTrigger(pParse,X,NOERR);
|
||||
}
|
||||
%endif !SQLITE_OMIT_TRIGGER
|
||||
|
||||
+3
-2
@@ -3314,6 +3314,8 @@ struct SrcItem {
|
||||
union {
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
|
||||
Trigger *pTrig; /* Trigger in argument list of DROP TRIGGER */
|
||||
Index *pIdx; /* Index in argument list to DROP INDEX */
|
||||
} u2;
|
||||
};
|
||||
|
||||
@@ -4926,7 +4928,6 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
|
||||
int sqlite3DbMaskAllZero(yDbMask);
|
||||
#endif
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3CodeDropTable(Parse*, Table*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3DeleteTableGeneric(sqlite3*, void*);
|
||||
void sqlite3FreeIndex(sqlite3*, Index*);
|
||||
@@ -5574,7 +5575,7 @@ const char *sqlite3JournalModename(int);
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
void sqlite3FkCheck(Parse*, Table*, int, int, int*, int);
|
||||
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
|
||||
void sqlite3FkDropTable(Parse*, SrcList*, Table*);
|
||||
void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
|
||||
int sqlite3FkRequired(Parse*, Table*, int*, int);
|
||||
u32 sqlite3FkOldmask(Parse*, Table*);
|
||||
|
||||
+30
-26
@@ -624,35 +624,39 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
|
||||
const char *zDb;
|
||||
const char *zName;
|
||||
sqlite3 *db = pParse->db;
|
||||
int ii, jj;
|
||||
|
||||
if( db->mallocFailed ) goto drop_trigger_cleanup;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
|
||||
assert( pName->nSrc==1 );
|
||||
zDb = pName->a[0].zDatabase;
|
||||
zName = pName->a[0].zName;
|
||||
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
||||
sqlite3ReadSchema(pParse);
|
||||
assert( pName!=0 || pParse->nErr!=0 );
|
||||
for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
|
||||
zDb = pName->a[ii].zDatabase;
|
||||
zName = pName->a[ii].zName;
|
||||
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
goto drop_trigger_cleanup;
|
||||
pName->a[ii].u2.pTrig = pTrigger;
|
||||
if( !pTrigger ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a+ii);
|
||||
}else{
|
||||
sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
||||
}
|
||||
testcase( ii>0 );
|
||||
testcase( ii+1<pName->nSrc );
|
||||
pParse->checkSchema = 1;
|
||||
continue;
|
||||
}
|
||||
for(jj=ii-1; jj>=0; jj--){
|
||||
if( pName->a[jj].u2.pTrig==pTrigger ) break;
|
||||
}
|
||||
if( jj>=0 ) continue;
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqlite3SrcListDelete(db, pName);
|
||||
}
|
||||
|
||||
|
||||
+6
-12
@@ -117,8 +117,7 @@ do_test aggnested-3.0 {
|
||||
#
|
||||
do_test aggnested-3.1 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
id1 INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value1 INTEGER
|
||||
@@ -150,8 +149,7 @@ do_test aggnested-3.1-rj {
|
||||
|
||||
do_test aggnested-3.2 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
id1 INTEGER,
|
||||
value1 INTEGER,
|
||||
@@ -178,8 +176,7 @@ do_test aggnested-3.2 {
|
||||
} {1 0}
|
||||
do_test aggnested-3.3 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1(id1, value1);
|
||||
INSERT INTO t1 VALUES(4469,2),(4469,1);
|
||||
CREATE TABLE t2 (value2);
|
||||
@@ -249,8 +246,7 @@ do_test aggnested-3.16 {
|
||||
# Problem found by dbsqlfuzz
|
||||
#
|
||||
do_execsql_test aggnested-4.1 {
|
||||
DROP TABLE IF EXISTS aa;
|
||||
DROP TABLE IF EXISTS bb;
|
||||
DROP TABLE IF EXISTS aa, bb;
|
||||
CREATE TABLE aa(x INT); INSERT INTO aa(x) VALUES(123);
|
||||
CREATE TABLE bb(y INT); INSERT INTO bb(y) VALUES(456);
|
||||
SELECT (SELECT sum(x+(SELECT y)) FROM bb) FROM aa;
|
||||
@@ -259,8 +255,7 @@ do_execsql_test aggnested-4.2 {
|
||||
SELECT (SELECT sum(x+y) FROM bb) FROM aa;
|
||||
} {579}
|
||||
do_execsql_test aggnested-4.3 {
|
||||
DROP TABLE IF EXISTS tx;
|
||||
DROP TABLE IF EXISTS ty;
|
||||
DROP TABLE IF EXISTS tx, ty;
|
||||
CREATE TABLE tx(x INT);
|
||||
INSERT INTO tx VALUES(1),(2),(3),(4),(5);
|
||||
CREATE TABLE ty(y INT);
|
||||
@@ -477,8 +472,7 @@ do_execsql_test 9.5 {
|
||||
# https://bugs.chromium.org/p/chromium/issues/detail?id=1511689
|
||||
#
|
||||
do_execsql_test 10.1 {
|
||||
DROP TABLE IF EXISTS t0;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t0, t1;
|
||||
CREATE TABLE t0(c1, c2); INSERT INTO t0 VALUES(1,2);
|
||||
CREATE TABLE t1(c3, c4); INSERT INTO t1 VALUES(3,4);
|
||||
SELECT * FROM t0 WHERE EXISTS (SELECT 1 FROM t1 GROUP BY c3 HAVING ( SELECT count(*) FROM (SELECT 1 UNION ALL SELECT sum(DISTINCT c1) ) ) ) BETWEEN 1 AND 1;
|
||||
|
||||
@@ -60,8 +60,7 @@ do_execsql_test aggorderby-4.1 {
|
||||
|
||||
|
||||
do_execsql_test aggorderby-5.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t3;
|
||||
DROP TABLE IF EXISTS t1, t3;
|
||||
CREATE TABLE t1(a TEXT); INSERT INTO t1 VALUES('aaa'),('bbb');
|
||||
CREATE TABLE t3(d TEXT); INSERT INTO t3 VALUES('/'),('-');
|
||||
SELECT (SELECT string_agg(a,d) FROM t3) FROM t1;
|
||||
|
||||
+2
-5
@@ -105,9 +105,7 @@ do_test alter3-1.99 {
|
||||
DROP TABLE t2;
|
||||
}
|
||||
execsql {
|
||||
DROP TABLE abc;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t3;
|
||||
DROP TABLE abc, t1, t3;
|
||||
}
|
||||
} {}
|
||||
|
||||
@@ -296,8 +294,7 @@ ifcapable attach {
|
||||
} {1 one 2 two}
|
||||
do_test alter3-5.99 {
|
||||
execsql {
|
||||
DROP TABLE aux.t1;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE aux.t1, main.t1;
|
||||
}
|
||||
} {}
|
||||
}
|
||||
|
||||
+1
-3
@@ -114,9 +114,7 @@ do_test alter4-1.99 {
|
||||
DROP TABLE t2;
|
||||
}
|
||||
execsql {
|
||||
DROP TABLE abc;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t3;
|
||||
DROP TABLE abc, t1, t3;
|
||||
}
|
||||
} {}
|
||||
|
||||
|
||||
+1
-2
@@ -195,8 +195,7 @@ do_test analyze-3.8 {
|
||||
CREATE INDEX t3i1 ON t3(a);
|
||||
CREATE INDEX t3i2 ON t3(a,b,c,d);
|
||||
CREATE INDEX t3i3 ON t3(d,b,c,a);
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1, t2;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
}
|
||||
} {}
|
||||
|
||||
+5
-5
@@ -216,7 +216,7 @@ do_test auth-1.21.1 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP TABLE t2}
|
||||
catchsql {DROP TABLE IF EXISTS none1, none2, t2, none3}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.21.2 {
|
||||
set ::authargs
|
||||
@@ -483,7 +483,7 @@ do_test auth-1.63 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP TABLE t2}
|
||||
catchsql {DROP TABLE IF EXISTS none1, t2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.64 {
|
||||
execsql {SELECT name FROM sqlite_master}
|
||||
@@ -726,7 +726,7 @@ do_test auth-1.101 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP VIEW v2}
|
||||
catchsql {DROP VIEW IF EXISTS none1, v2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.102 {
|
||||
set ::authargs
|
||||
@@ -1090,7 +1090,7 @@ do_test auth-1.153 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP TRIGGER r2}
|
||||
catchsql {DROP TRIGGER IF EXISTS none1, r2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.154 {
|
||||
set ::authargs
|
||||
@@ -1389,7 +1389,7 @@ do_test auth-1.205 {
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
catchsql {DROP INDEX i2}
|
||||
catchsql {DROP INDEX IF EXISTS none1, i2, none2}
|
||||
} {1 {not authorized}}
|
||||
do_test auth-1.205a {
|
||||
set ::authargs
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# 2024-02-29
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for DROP TABLE, DROP INDEX, DROP TRIGGER, and DROP VIEW that
|
||||
# list multiple objects to be dropped.
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix drop-many
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(a);
|
||||
CREATE TABLE t2(b, c UNIQUE);
|
||||
CREATE TABLE t3(d TEXT PRIMARY KEY, e);
|
||||
CREATE INDEX t3e ON t3(e);
|
||||
ATTACH ':memory:' AS aux1;
|
||||
CREATE TABLE aux1.t4(f INT, g INT, h INT PRIMARY KEY) WITHOUT ROWID;
|
||||
CREATE INDEX aux1.t4g ON t4(g);
|
||||
CREATE INDEX t2b ON t2(b);
|
||||
CREATE VIEW v5 AS SELECT 1,2,3;
|
||||
CREATE VIEW v6 AS SELECT * FROM t3;
|
||||
CREATE VIEW aux1.v7 AS SELECT 'hello';
|
||||
CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT 'this is trigger r1'; END;
|
||||
CREATE TRIGGER r2 BEFORE DELETE ON t2 BEGIN INSERT INTO t1 VALUES(old.b); END;
|
||||
CREATE TRIGGER aux1.r3 AFTER UPDATE ON t4 BEGIN SELECT 'trigger r3'; END;
|
||||
CREATE TRIGGER aux1.r4 INSTEAD OF UPDATE ON v7 BEGIN SELECT NULL; END;
|
||||
} {}
|
||||
do_execsql_test 1.2 {
|
||||
BEGIN;
|
||||
DROP TABLE t2, t4, t3, t1;
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 1.3.1 {
|
||||
DROP TABLE t2, t4, t3, t05, t1;
|
||||
} {1 {no such table: t05}}
|
||||
do_execsql_test 1.3.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
} {t1 t2 t3 t4}
|
||||
do_execsql_test 1.4 {
|
||||
BEGIN;
|
||||
DROP TABLE IF EXISTS t01, t2, t02, t4, t03, t3, t04, t1, t05;
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 1.5.1 {
|
||||
DROP TABLE IF EXISTS t2, t4, t3, v7, t1;
|
||||
} {1 {use DROP VIEW to delete view v7}}
|
||||
do_execsql_test 1.5.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='table'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='table'
|
||||
ORDER BY name;
|
||||
} {t1 t2 t3 t4}
|
||||
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
BEGIN;
|
||||
DROP VIEW v5, v6, v7;
|
||||
SELECT name FROM sqlite_schema WHERE type='view'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='view'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 2.2.1 {
|
||||
DROP VIEW v5, v6, v8, v7;
|
||||
} {1 {no such view: v8}}
|
||||
do_execsql_test 2.2.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='view'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='view'
|
||||
ORDER BY name;
|
||||
} {v5 v6 v7}
|
||||
do_catchsql_test 2.3.1 {
|
||||
DROP VIEW v5, v6, t1, v7;
|
||||
} {1 {use DROP TABLE to delete table t1}}
|
||||
do_execsql_test 2.3.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='view'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='view'
|
||||
ORDER BY name;
|
||||
} {v5 v6 v7}
|
||||
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
BEGIN;
|
||||
DROP INDEX t2b, aux1.t4g, main.t3e;
|
||||
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='index'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 3.2.1 {
|
||||
DROP INDEX t2b, aux1.t4g, t1, main.t3e;
|
||||
} {1 {no such index: t1}}
|
||||
do_execsql_test 3.2.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='index'
|
||||
ORDER BY name;
|
||||
} {t2b t3e t4g}
|
||||
do_execsql_test 3.3 {
|
||||
BEGIN;
|
||||
DROP INDEX IF EXISTS aux1.none, t2b, none2, aux1.t4g, main.t3e, none3;
|
||||
SELECT name FROM sqlite_schema WHERE type='index' AND name NOT LIKE 'sqlite%'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='index'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
BEGIN;
|
||||
DROP TRIGGER main.r1, r2, r3, aux1.r4;
|
||||
SELECT name FROM sqlite_schema WHERE type='trigger'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='trigger'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
do_catchsql_test 4.2.1 {
|
||||
DROP TRIGGER main.r1, r2, r3, main.t1, aux1.r4;
|
||||
} {1 {no such trigger: main.t1}}
|
||||
do_execsql_test 4.2.2 {
|
||||
SELECT name FROM sqlite_schema WHERE type='trigger'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='trigger'
|
||||
ORDER BY name;
|
||||
} {r1 r2 r3 r4}
|
||||
do_execsql_test 4.3 {
|
||||
BEGIN;
|
||||
DROP TRIGGER IF EXISTS none1, main.r1, r2, aux1.none2, r3, aux1.r4;
|
||||
SELECT name FROM sqlite_schema WHERE type='trigger'
|
||||
UNION ALL
|
||||
SELECT name from aux1.sqlite_schema WHERE type='trigger'
|
||||
ORDER BY name;
|
||||
ROLLBACK;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
@@ -71,6 +71,17 @@ do_test fkey1-2.1 {
|
||||
DROP TABLE t10;
|
||||
}
|
||||
} {}
|
||||
do_test fkey1-2.2 {
|
||||
execsql {
|
||||
CREATE TABLE t5(x references t4);
|
||||
CREATE TABLE t6(x references t4);
|
||||
CREATE TABLE t7(x references t4);
|
||||
CREATE TABLE t8(x references t4);
|
||||
CREATE TABLE t9(x references t4);
|
||||
CREATE TABLE t10(x references t4);
|
||||
DROP TABLE t7, t9, t5, t8, t6, t10;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test fkey1-3.1 {
|
||||
execsql {
|
||||
|
||||
Reference in New Issue
Block a user