From: drh <> Date: Fri, 1 Mar 2024 12:21:45 +0000 (+0000) Subject: When doing a multi-drop, delete btrees beginning with the largest root page X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=19fb027eb546e9be0809822525543b9095452734;p=thirdparty%2Fsqlite.git When doing a multi-drop, delete btrees beginning with the largest root page first and working toward smaller root pages, to avoid problems with root page renumbering due to autovacuum. FossilOrigin-Name: 37d4c5e207888b49c224275b05abfc1f63a2d8d2133bcc8970188b15387926ef --- diff --git a/manifest b/manifest index 84a66be780..f8caa0c481 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 @@ -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 25384963d1b9d6ebc73777bc7c1112973ba36ea8a8ca9f0a39bd94c047ba24eb +F src/build.c 39344791925e956a11ac74aca8d4ce3d34a5982e33a97bfea1b9a8ed8d5f995c F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b @@ -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 bdb0bba047cd39c8733c14131c379a91f3d1f437c57f11270db14860ab09dffd +F src/sqliteInt.h d5101433f13bd5944472c1b4c28a2eaa198c9773f8c54496b57095b27289bfe9 F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728 F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -2177,8 +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 2266086cf08ee710338667d1cf0b1e81ce7380101707db272ce27124404068a0 -R d3490d0df600a6062bf18828bf499fc3 +P 02f9fc73eef80f528097581580977aae46942baac2d7fb205c52f7f25472f2a8 +R 6e23b5efb65bccda72802397068f9d95 U drh -Z 68bbccadbf2f82f26c1558f6e4711d24 +Z f617c5603de9e2495d967184783943a7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7cbde21282..087e4f307d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -02f9fc73eef80f528097581580977aae46942baac2d7fb205c52f7f25472f2a8 \ No newline at end of file +37d4c5e207888b49c224275b05abfc1f63a2d8d2133bcc8970188b15387926ef \ No newline at end of file diff --git a/src/build.c b/src/build.c index dbad644304..9b2d808fe7 100644 --- a/src/build.c +++ b/src/build.c @@ -3479,7 +3479,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ Table *pTab; sqlite3 *db = pParse->db; int iDb; - int ii; + int ii, jj; (void)sqlite3GetVdbe(pParse); sqlite3ReadSchema(pParse); @@ -3575,40 +3575,41 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ /* 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; jja[jj].pTab!=pTab; jj++){} - if( 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 && iinSrc; 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; iinSrc; 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 && iinSrc; 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); } @@ -4613,11 +4614,12 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ 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 && iinSrc; ii++){ + pName->a[ii].regReturn = 0; pIndex = sqlite3FindIndex(db, pName->a[ii].zName, pName->a[ii].zDatabase); if( pIndex==0 ){ if( !ifExists ){ @@ -4660,19 +4662,17 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ #endif /* Skip over redundant DROP INDEXes */ - if( ii>0 ){ - int jj; - for(jj=0; jja[jj].addrFillSub!=iDb ) continue; - if( pName->a[jj].regReturn!=pIndex->tnum ) continue; - break; - } - if( jja[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); @@ -4682,6 +4682,23 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ 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; iinSrc; 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); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9a9a13f376..f91f2d9ae3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3315,6 +3315,7 @@ struct SrcItem { 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; };