]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the ability to DROP one or more objects of the same class
authordrh <>
Thu, 29 Feb 2024 13:44:15 +0000 (13:44 +0000)
committerdrh <>
Thu, 29 Feb 2024 13:44:15 +0000 (13:44 +0000)
in a single statement by listing the objects as multiple arguments to the
DROP command.

FossilOrigin-Name: 2266086cf08ee710338667d1cf0b1e81ce7380101707db272ce27124404068a0

13 files changed:
manifest
manifest.uuid
src/build.c
src/parse.y
src/trigger.c
test/aggnested.test
test/aggorderby.test
test/alter3.test
test/alter4.test
test/analyze.test
test/auth.test
test/drop-many.test [new file with mode: 0644]
test/fkey1.test

index 28b15c7a433b07ac3a545adc351a0110a9c0ee1d..8e933bf204c606a6a9ad3ea80553b7acf486a958 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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 Add\sthe\sability\sto\sDROP\sone\sor\smore\sobjects\sof\sthe\ssame\sclass\nin\sa\ssingle\sstatement\sby\slisting\sthe\sobjects\sas\smultiple\sarguments\sto\sthe\nDROP\scommand.
+D 2024-02-29T13:44:15.183
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -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 786e47a8ccefa14fbdca52e22bc51dbe24074a9c7dbe4f2afd2050736a7352c5
 F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
@@ -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 85e7464c09fe05a9c1e9ba85fb2fc2dcd647fbcfb6ed3e17424ec938a3daddc0
 F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
 F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
@@ -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 a23049b9771927763ade8389fb6a0494324bad15394893895f6aa4e346e6b295
 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 w test/drop1.test
 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 803481f25020f3c25941f1e7d1a8071937820dea951e8798198b0b0fa3fb48ce
+R b06b7d333b1bcab630a4dab891f8b26c
+U drh
+Z 594e686b84606bfb7b18560464880c6c
 # Remove this line to create a well-formed Fossil manifest.
index 2f2c96f612a757504d29f287cd1aa4a703dee741..c56c4d0e0a31f80333798c19c1a34e17a0fbfd83 100644 (file)
@@ -1 +1 @@
-803481f25020f3c25941f1e7d1a8071937820dea951e8798198b0b0fa3fb48ce
\ No newline at end of file
+2266086cf08ee710338667d1cf0b1e81ce7380101707db272ce27124404068a0
\ No newline at end of file
index 15f8fe1d24f5cd5e798d3d9dccde716751f83121..9302e0d195b756b010515d96f719cbd55abc2983 100644 (file)
@@ -3480,102 +3480,112 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
   Vdbe *v;
   sqlite3 *db = pParse->db;
   int iDb;
-
-  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--;
-
-  if( pTab==0 ){
-    if( noErr ){
-      sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
-      sqlite3ForceNotReadOnly(pParse);
+  int ii;
+
+  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[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
 
-  /* Generate code to remove the table from the schema table
-  ** on disk.
-  */
-  v = sqlite3GetVdbe(pParse);
-  if( v ){
-    sqlite3BeginWriteOperation(pParse, 1, iDb);
-    if( !isView ){
-      sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
-      sqlite3FkDropTable(pParse, pName, pTab);
+    /* Generate code to remove the table from the schema table
+    ** on disk.
+    */
+    v = sqlite3GetVdbe(pParse);
+    if( v ){
+      sqlite3BeginWriteOperation(pParse, 1, iDb);
+      if( !isView ){
+        sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
+        sqlite3FkDropTable(pParse, pName, pTab);
+      }
+      sqlite3CodeDropTable(pParse, pTab, iDb, isView);
     }
-    sqlite3CodeDropTable(pParse, pTab, iDb, isView);
   }
-
-exit_drop_table:
   sqlite3SrcListDelete(db, pName);
 }
 
@@ -4579,63 +4589,67 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
   Vdbe *v;
   sqlite3 *db = pParse->db;
   int iDb;
-
-  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);
+  int ii;
+
+  sqlite3ReadSchema(pParse);
+  assert( pName!=0 || pParse->nErr!=0 );
+  for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
+    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);
-#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;
+    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;
     }
-    if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
-    if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
-      goto exit_drop_index;
+    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) ){
+        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;
+      }
     }
-  }
 #endif
 
-  /* Generate code to remove the index and from the schema table */
-  v = sqlite3GetVdbe(pParse);
-  if( v ){
-    sqlite3BeginWriteOperation(pParse, 1, iDb);
-    sqlite3NestedParse(pParse,
-       "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
-       db->aDb[iDb].zDbSName, pIndex->zName
-    );
-    sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
-    sqlite3ChangeCookie(pParse, iDb);
-    destroyRootPage(pParse, pIndex->tnum, iDb);
-    sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
+    /* Generate code to remove the index and from the schema table */
+    v = sqlite3GetVdbe(pParse);
+    if( v ){
+      sqlite3BeginWriteOperation(pParse, 1, iDb);
+      sqlite3NestedParse(pParse,
+         "DELETE FROM %Q." LEGACY_SCHEMA_TABLE
+         " WHERE name=%Q AND type='index'",
+         db->aDb[iDb].zDbSName, pIndex->zName
+      );
+      sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
+      sqlite3ChangeCookie(pParse, iDb);
+      destroyRootPage(pParse, pIndex->tnum, iDb);
+      sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
+    }
   }
-
-exit_drop_index:
   sqlite3SrcListDelete(db, pName);
 }
 
index 37c9fa8bc9e222162f284977ddeb1e7130541d49..9ee27de3d24a543fd3385132345a1cbae7c308e8 100644 (file)
@@ -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);
+  if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &X);
+}
+fullnamelist(A) ::= fullnamelist(L) COMMA nm(X) DOT nm(Y). {
+  A = sqlite3SrcListAppend(pParse,L,&X,&Y);
+  if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y);
+}
+
 %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
index 97ca249be58175b58229383953f87e84e704d976..c388bacfbe419840a35f2cf73126a1d6c7813f52 100644 (file)
@@ -624,35 +624,34 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
   const char *zDb;
   const char *zName;
   sqlite3 *db = pParse->db;
-
-  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);
+  int ii;
+
+  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;
+    }
+    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;
     }else{
-      sqlite3CodeVerifyNamedSchema(pParse, zDb);
+      sqlite3DropTriggerPtr(pParse, pTrigger);
     }
-    pParse->checkSchema = 1;
-    goto drop_trigger_cleanup;
   }
-  sqlite3DropTriggerPtr(pParse, pTrigger);
-
-drop_trigger_cleanup:
   sqlite3SrcListDelete(db, pName);
 }
 
index f3539076bddccfbba70304934d8b0e751ba31423..627bdf98ca24af539f9663362b040d776069d976 100644 (file)
@@ -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;
index eed1f83a7e00474f92d6520973a77915531f583b..fe82d36bd1edb5ef86334f695049df090571136d 100644 (file)
@@ -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;
index c6f26b0c50f141b14cca09a275dd85255971199b..649a50320dc5540cfa71c9ae5d0c01a9f3103506 100644 (file)
@@ -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;
     }
   } {}
 }
index c63ba6b07231eacb2268fd98aed70c701f785ace..6a778ed89f99975f3387abbec3d7fb5af7cb7046 100644 (file)
@@ -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; 
   }
 } {}
 
index f97c78aff1d3a39eb10669e32637ce22ecc0c79e..c42c6ca751ba3300edbdbcf0bb17f0b7fa285da7 100644 (file)
@@ -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;
   }
 } {}
index 1d56f70343563f026fc0d7d87b4ea57f107ed6a1..9a1639a0ee5edfa7e4b8b6b811aab8b3972fdbdd 100644 (file)
@@ -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
diff --git a/test/drop-many.test b/test/drop-many.test
new file mode 100644 (file)
index 0000000..9991763
--- /dev/null
@@ -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
index 46e7f64a193be12db2e3dd9e4802f75c11783580..82f7779ca4bc8177e2d17116b2e59be09670c747 100644 (file)
@@ -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 {