-C Attempt\sto\sfix\smulti-object\sDROP.\s\sWorking\sbetter,\sbut\sstill\snot\sperfect.
-D 2024-02-29T19:40:38.822
+C When\sdoing\sa\smulti-drop,\sdelete\sbtrees\sbeginning\swith\sthe\slargest\sroot\spage\nfirst\sand\sworking\stoward\ssmaller\sroot\spages,\sto\savoid\sproblems\swith\sroot\spage\nrenumbering\sdue\sto\sautovacuum.
+D 2024-03-01T12:21:45.438
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/btree.c 285b493d843e7ba8ef78b6ae7d31238e904901dbc0c484f7904de4cf18fd8802
F src/btree.h 55066f513eb095db935169dab1dc2f7c7a747ef223c533f5d4ad4dfed346cbd0
F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
-F src/build.c 25384963d1b9d6ebc73777bc7c1112973ba36ea8a8ca9f0a39bd94c047ba24eb
+F src/build.c 39344791925e956a11ac74aca8d4ce3d34a5982e33a97bfea1b9a8ed8d5f995c
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
F src/sqlite.h.in 19a2db3995a699bd7f6dfb423856242bfceb7ec849a93c91d241d19fc28d9f0f
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h bdb0bba047cd39c8733c14131c379a91f3d1f437c57f11270db14860ab09dffd
+F src/sqliteInt.h d5101433f13bd5944472c1b4c28a2eaa198c9773f8c54496b57095b27289bfe9
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 2266086cf08ee710338667d1cf0b1e81ce7380101707db272ce27124404068a0
-R d3490d0df600a6062bf18828bf499fc3
+P 02f9fc73eef80f528097581580977aae46942baac2d7fb205c52f7f25472f2a8
+R 6e23b5efb65bccda72802397068f9d95
U drh
-Z 68bbccadbf2f82f26c1558f6e4711d24
+Z f617c5603de9e2495d967184783943a7
# Remove this line to create a well-formed Fossil manifest.
Table *pTab;
sqlite3 *db = pParse->db;
int iDb;
- int ii;
+ int ii, jj;
(void)sqlite3GetVdbe(pParse);
sqlite3ReadSchema(pParse);
/* 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. */
- if( ii>0 ){
- int jj;
- for(jj=0; jj<ii && pName->a[jj].pTab!=pTab; jj++){}
- if( jj<ii ) continue;
- }
+ for(jj=ii-1; jj>=0 && pName->a[jj].pTab!=pTab; jj--){}
+ if( jj>=0 ) continue;
/* Remember the table for use in the second pass */
pName->a[ii].pTab = pTab;
pTab->nTabRef++;
- }
+ pName->a[ii].regReturn = IsOrdinaryTable(pTab) ? pTab->tnum : 1;
- for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
- pTab = pName->a[ii].pTab;
- if( pTab ){
- iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
-
- /* Generate code to clear this table from sqlite_statN and to
- ** cascade foreign key constraints.
- */
- sqlite3BeginWriteOperation(pParse, 1, iDb);
- if( IsOrdinaryTable(pTab) ){
- sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
- sqlite3FkDropTable(pParse, &pName->a[ii], pTab);
+ /* Generate code to clear this table from sqlite_statN and to
+ ** cascade foreign key constraints.
+ */
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
+ if( IsOrdinaryTable(pTab) ){
+ sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
+ sqlite3FkDropTable(pParse, &pName->a[ii], pTab);
+ }
+ }
+
+ /* 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. */
+ while( pParse->nErr==0 ){
+ int iBest = 0;
+ for(ii=jj=0; ii<pName->nSrc; ii++){
+ if( pName->a[ii].regReturn<=0 ) continue;
+ if( pName->a[ii].regReturn>iBest ){
+ jj = ii;
+ iBest = pName->a[ii].regReturn;
}
}
- }
-
- /* Generate code to actually delete the tables/views in a second pass. */
- for(ii=0; pParse->nErr==0 && ii<pName->nSrc; ii++){
- pTab = pName->a[ii].pTab;
- if( pTab ){
- iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- sqlite3CodeDropTable(pParse, pTab, iDb, isView);
- }
+ if( iBest==0 ) break;
+ pTab = pName->a[jj].pTab;
+ pName->a[jj].regReturn = 0;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ sqlite3CodeDropTable(pParse, pTab, iDb, isView);
}
sqlite3SrcListDelete(db, pName);
}
sqlite3 *db = pParse->db;
Vdbe *v;
int iDb;
- int ii;
+ int ii, jj;
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 ){
#endif
/* Skip over redundant DROP INDEXes */
- if( ii>0 ){
- int jj;
- for(jj=0; jj<ii; jj++){
- if( pName->a[jj].addrFillSub!=iDb ) continue;
- if( pName->a[jj].regReturn!=pIndex->tnum ) continue;
- break;
- }
- if( jj<ii ) continue;
- }
- pName->a[ii].addrFillSub = iDb;
+ 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. Store the root page
+ ** number in SrcItem.regReturn so that indexes can be dropped largest
+ ** first to avoid problems with autovacuum reordering. */
+ pName->a[ii].u2.pIdx = pIndex;
pName->a[ii].regReturn = pIndex->tnum;
- /* Generate code to remove the index and from the schema table */
+ /* Generate code to remove the index and from the schema table and
+ ** from sqlite_statN tables */
v = sqlite3GetVdbe(pParse);
if( v==0 ) break;
sqlite3BeginWriteOperation(pParse, 1, iDb);
db->aDb[iDb].zDbSName, pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
+ }
+
+ /* Drop the indexes. Drop the ones with the largest root page first
+ ** to avoid problems with autovacuum. */
+ while( pParse->nErr==0 ){
+ int iBest = 0;
+ jj = 0;
+ for(ii=0; ii<pName->nSrc; ii++){
+ if( pName->a[ii].regReturn>iBest ){
+ jj = ii;
+ iBest = pName->a[ii].regReturn;
+ }
+ }
+ if( iBest<=0 ) break;
+ pIndex = pName->a[jj].u2.pIdx;
+ pName->a[jj].regReturn = 0;
+ iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
sqlite3ChangeCookie(pParse, iDb);
destroyRootPage(pParse, pIndex->tnum, iDb);
sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);