예제 #1
0
        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);
        }
예제 #2
0
 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;
 }
예제 #3
0
        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);
        }
예제 #4
0
 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;
 }