internal RC clearDatabasePage(Pgno pgno, int freePageFlag, ref int pnChange) { var pPage = new MemPage(); Debug.Assert(MutexEx.Held(this.Mutex)); if (pgno > btreePagecount()) { return(SysEx.SQLITE_CORRUPT_BKPT()); } var rc = getAndInitPage(pgno, ref pPage); if (rc != RC.OK) { return(rc); } for (var i = 0; i < pPage.Cells; i++) { var iCell = pPage.FindCell(i); var pCell = pPage.Data; if (pPage.Leaf == 0) { rc = clearDatabasePage(ConvertEx.Get4(pCell, iCell), 1, ref pnChange); if (rc != RC.OK) { goto cleardatabasepage_out; } } rc = pPage.clearCell(iCell); if (rc != RC.OK) { goto cleardatabasepage_out; } } if (pPage.Leaf == 0) { rc = clearDatabasePage(ConvertEx.Get4(pPage.Data, 8), 1, ref pnChange); if (rc != RC.OK) { goto cleardatabasepage_out; } } else { pnChange += pPage.Cells; } if (freePageFlag != 0) { pPage.freePage(ref rc); } else if ((rc = Pager.Write(pPage.DbPage)) == RC.OK) { pPage.zeroPage(pPage.Data[0] | Btree.PTF_LEAF); } cleardatabasepage_out: pPage.releasePage(); return(rc); }
internal RC clearDatabasePage(Pgno pgno, int freePageFlag, ref int pnChange) { var pPage = new MemPage(); Debug.Assert(MutexEx.Held(this.Mutex)); if (pgno > btreePagecount()) return SysEx.SQLITE_CORRUPT_BKPT(); var rc = getAndInitPage(pgno, ref pPage); if (rc != RC.OK) return rc; for (var i = 0; i < pPage.Cells; i++) { var iCell = pPage.FindCell(i); var pCell = pPage.Data; if (pPage.Leaf == 0) { rc = clearDatabasePage(ConvertEx.Get4(pCell, iCell), 1, ref pnChange); if (rc != RC.OK) goto cleardatabasepage_out; } rc = pPage.clearCell(iCell); if (rc != RC.OK) goto cleardatabasepage_out; } if (pPage.Leaf == 0) { rc = clearDatabasePage(ConvertEx.Get4(pPage.Data, 8), 1, ref pnChange); if (rc != RC.OK) goto cleardatabasepage_out; } else pnChange += pPage.Cells; if (freePageFlag != 0) pPage.freePage(ref rc); else if ((rc = Pager.Write(pPage.DbPage)) == RC.OK) pPage.zeroPage(pPage.Data[0] | Btree.PTF_LEAF); cleardatabasepage_out: pPage.releasePage(); return rc; }
internal RC btreeDropTable(Pgno iTable, ref int piMoved) { MemPage pPage = null; var pBt = this.Shared; Debug.Assert(sqlite3BtreeHoldsMutex()); Debug.Assert(this.InTransaction == TRANS.WRITE); // It is illegal to drop a table if any cursors are open on the database. This is because in auto-vacuum mode the backend may // need to move another root-page to fill a gap left by the deleted root page. If an open cursor was using this page a problem would occur. // This error is caught long before control reaches this point. if (Check.NEVER(pBt.Cursors) != null) { sqlite3b.sqlite3ConnectionBlocked(this.DB, pBt.Cursors.Tree.DB); return(RC.LOCKED_SHAREDCACHE); } var rc = pBt.btreeGetPage((Pgno)iTable, ref pPage, 0); if (rc != RC.OK) { return(rc); } var dummy0 = 0; rc = ClearTable((int)iTable, ref dummy0); if (rc != RC.OK) { pPage.releasePage(); return(rc); } piMoved = 0; if (iTable > 1) { #if SQLITE_OMIT_AUTOVACUUM freePage(pPage, ref rc); releasePage(pPage); #else if (pBt.AutoVacuum) { Pgno maxRootPgno = 0; GetMeta((int)META.LARGEST_ROOT_PAGE, ref maxRootPgno); if (iTable == maxRootPgno) { // If the table being dropped is the table with the largest root-page number in the database, put the root page on the free list. pPage.freePage(ref rc); pPage.releasePage(); if (rc != RC.OK) { return(rc); } } else { // The table being dropped does not have the largest root-page number in the database. So move the page that does into the // gap left by the deleted root-page. var pMove = new MemPage(); pPage.releasePage(); rc = pBt.btreeGetPage(maxRootPgno, ref pMove, 0); if (rc != RC.OK) { return(rc); } rc = MemPage.relocatePage(pBt, pMove, PTRMAP.ROOTPAGE, 0, iTable, 0); pMove.releasePage(); if (rc != RC.OK) { return(rc); } pMove = null; rc = pBt.btreeGetPage(maxRootPgno, ref pMove, 0); pMove.freePage(ref rc); pMove.releasePage(); if (rc != RC.OK) { return(rc); } piMoved = (int)maxRootPgno; } // Set the new 'max-root-page' value in the database header. This is the old value less one, less one more if that happens to // be a root-page number, less one again if that is the PENDING_BYTE_PAGE. maxRootPgno--; while (maxRootPgno == MemPage.PENDING_BYTE_PAGE(pBt) || MemPage.PTRMAP_ISPAGE(pBt, maxRootPgno)) { maxRootPgno--; } Debug.Assert(maxRootPgno != MemPage.PENDING_BYTE_PAGE(pBt)); rc = SetMeta(4, maxRootPgno); } else { pPage.freePage(ref rc); pPage.releasePage(); } #endif } else { // If sqlite3BtreeDropTable was called on page 1. This really never should happen except in a corrupt database. pPage.zeroPage(PTF_INTKEY | PTF_LEAF); pPage.releasePage(); } return(rc); }
internal RC btreeDropTable(Pgno iTable, ref int piMoved) { MemPage pPage = null; var pBt = this.Shared; Debug.Assert(sqlite3BtreeHoldsMutex()); Debug.Assert(this.InTransaction == TRANS.WRITE); // It is illegal to drop a table if any cursors are open on the database. This is because in auto-vacuum mode the backend may // need to move another root-page to fill a gap left by the deleted root page. If an open cursor was using this page a problem would occur. // This error is caught long before control reaches this point. if (Check.NEVER(pBt.Cursors) != null) { sqlite3b.sqlite3ConnectionBlocked(this.DB, pBt.Cursors.Tree.DB); return RC.LOCKED_SHAREDCACHE; } var rc = pBt.btreeGetPage((Pgno)iTable, ref pPage, 0); if (rc != RC.OK) return rc; var dummy0 = 0; rc = ClearTable((int)iTable, ref dummy0); if (rc != RC.OK) { pPage.releasePage(); return rc; } piMoved = 0; if (iTable > 1) { #if SQLITE_OMIT_AUTOVACUUM freePage(pPage, ref rc); releasePage(pPage); #else if (pBt.AutoVacuum) { Pgno maxRootPgno = 0; GetMeta((int)META.LARGEST_ROOT_PAGE, ref maxRootPgno); if (iTable == maxRootPgno) { // If the table being dropped is the table with the largest root-page number in the database, put the root page on the free list. pPage.freePage(ref rc); pPage.releasePage(); if (rc != RC.OK) return rc; } else { // The table being dropped does not have the largest root-page number in the database. So move the page that does into the // gap left by the deleted root-page. var pMove = new MemPage(); pPage.releasePage(); rc = pBt.btreeGetPage(maxRootPgno, ref pMove, 0); if (rc != RC.OK) return rc; rc = MemPage.relocatePage(pBt, pMove, PTRMAP.ROOTPAGE, 0, iTable, 0); pMove.releasePage(); if (rc != RC.OK) return rc; pMove = null; rc = pBt.btreeGetPage(maxRootPgno, ref pMove, 0); pMove.freePage(ref rc); pMove.releasePage(); if (rc != RC.OK) return rc; piMoved = (int)maxRootPgno; } // Set the new 'max-root-page' value in the database header. This is the old value less one, less one more if that happens to // be a root-page number, less one again if that is the PENDING_BYTE_PAGE. maxRootPgno--; while (maxRootPgno == MemPage.PENDING_BYTE_PAGE(pBt) || MemPage.PTRMAP_ISPAGE(pBt, maxRootPgno)) maxRootPgno--; Debug.Assert(maxRootPgno != MemPage.PENDING_BYTE_PAGE(pBt)); rc = SetMeta(4, maxRootPgno); } else { pPage.freePage(ref rc); pPage.releasePage(); } #endif } else { // If sqlite3BtreeDropTable was called on page 1. This really never should happen except in a corrupt database. pPage.zeroPage(PTF_INTKEY | PTF_LEAF); pPage.releasePage(); } return rc; }