Example #1
0
 // was:sqlite3BtreeCreateTable
 public RC CreateTable(ref int piTable, CREATETABLE flags)
 {
     sqlite3BtreeEnter();
     var rc = btreeCreateTable(ref piTable, flags);
     sqlite3BtreeLeave();
     return rc;
 }
Example #2
0
 // was:sqlite3BtreeCreateTable
 public RC CreateTable(ref int piTable, CREATETABLE flags)
 {
     sqlite3BtreeEnter();
     var rc = btreeCreateTable(ref piTable, flags);
     sqlite3BtreeLeave();
     return rc;
 }
Example #3
0
        internal RC btreeCreateTable(ref int piTable, CREATETABLE createTabFlags)
        {
            var  pBt      = this.Shared;
            var  pRoot    = new MemPage();
            Pgno pgnoRoot = 0;
            int  ptfFlags;         // Page-type flage for the root page of new table
            RC   rc;

            Debug.Assert(sqlite3BtreeHoldsMutex());
            Debug.Assert(pBt.InTransaction == TRANS.WRITE);
            Debug.Assert(!pBt.ReadOnly);
#if SQLITE_OMIT_AUTOVACUUM
            rc = allocateBtreePage(pBt, ref pRoot, ref pgnoRoot, 1, 0);
            if (rc != SQLITE.OK)
            {
                return(rc);
            }
#else
            if (pBt.AutoVacuum)
            {
                Pgno pgnoMove  = 0;             // Move a page here to make room for the root-page
                var  pPageMove = new MemPage(); // The page to move to.
                // Creating a new table may probably require moving an existing database to make room for the new tables root page. In case this page turns
                // out to be an overflow page, delete all overflow page-map caches held by open cursors.
                invalidateAllOverflowCache(pBt);
                // Read the value of meta[3] from the database to determine where the root page of the new table should go. meta[3] is the largest root-page
                // created so far, so the new root-page is (meta[3]+1).
                GetMeta((int)META.LARGEST_ROOT_PAGE, ref pgnoRoot);
                pgnoRoot++;
                // The new root-page may not be allocated on a pointer-map page, or the PENDING_BYTE page.
                while (pgnoRoot == MemPage.PTRMAP_PAGENO(pBt, pgnoRoot) || pgnoRoot == MemPage.PENDING_BYTE_PAGE(pBt))
                {
                    pgnoRoot++;
                }
                Debug.Assert(pgnoRoot >= 3);
                // Allocate a page. The page that currently resides at pgnoRoot will be moved to the allocated page (unless the allocated page happens to reside at pgnoRoot).
                rc = pBt.allocateBtreePage(ref pPageMove, ref pgnoMove, pgnoRoot, 1);
                if (rc != RC.OK)
                {
                    return(rc);
                }
                if (pgnoMove != pgnoRoot)
                {
                    // pgnoRoot is the page that will be used for the root-page of the new table (assuming an error did not occur). But we were
                    // allocated pgnoMove. If required (i.e. if it was not allocated by extending the file), the current page at position pgnoMove
                    // is already journaled.
                    PTRMAP eType    = 0;
                    Pgno   iPtrPage = 0;
                    pPageMove.releasePage();
                    // Move the page currently at pgnoRoot to pgnoMove.
                    rc = pBt.btreeGetPage(pgnoRoot, ref pRoot, 0);
                    if (rc != RC.OK)
                    {
                        return(rc);
                    }
                    rc = pBt.ptrmapGet(pgnoRoot, ref eType, ref iPtrPage);
                    if (eType == PTRMAP.ROOTPAGE || eType == PTRMAP.FREEPAGE)
                    {
                        rc = SysEx.SQLITE_CORRUPT_BKPT();
                    }
                    if (rc != RC.OK)
                    {
                        pRoot.releasePage();
                        return(rc);
                    }
                    Debug.Assert(eType != PTRMAP.ROOTPAGE);
                    Debug.Assert(eType != PTRMAP.FREEPAGE);
                    rc = MemPage.relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0);
                    pRoot.releasePage();
                    // Obtain the page at pgnoRoot
                    if (rc != RC.OK)
                    {
                        return(rc);
                    }
                    rc = pBt.btreeGetPage(pgnoRoot, ref pRoot, 0);
                    if (rc != RC.OK)
                    {
                        return(rc);
                    }
                    rc = Pager.Write(pRoot.DbPage);
                    if (rc != RC.OK)
                    {
                        pRoot.releasePage();
                        return(rc);
                    }
                }
                else
                {
                    pRoot = pPageMove;
                }
                // Update the pointer-map and meta-data with the new root-page number.
                pBt.ptrmapPut(pgnoRoot, PTRMAP.ROOTPAGE, 0, ref rc);
                if (rc != RC.OK)
                {
                    pRoot.releasePage();
                    return(rc);
                }
                // When the new root page was allocated, page 1 was made writable in order either to increase the database filesize, or to decrement the
                // freelist count.  Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
                Debug.Assert(Pager.IsPageWriteable(pBt.Page1.DbPage));
                rc = SetMeta(4, pgnoRoot);
                if (Check.NEVER(rc != RC.OK))
                {
                    pRoot.releasePage();
                    return(rc);
                }
            }
            else
            {
                rc = pBt.allocateBtreePage(ref pRoot, ref pgnoRoot, 1, 0);
                if (rc != RC.OK)
                {
                    return(rc);
                }
            }
#endif
            Debug.Assert(Pager.IsPageWriteable(pRoot.DbPage));
            ptfFlags = ((createTabFlags & CREATETABLE.INTKEY) != 0 ? PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF : PTF_ZERODATA | PTF_LEAF);
            pRoot.zeroPage(ptfFlags);
            Pager.Unref(pRoot.DbPage);
            Debug.Assert((pBt.OpenFlags & OPEN.SINGLE) == 0 || pgnoRoot == 2);
            piTable = (int)pgnoRoot;
            return(RC.OK);
        }
Example #4
0
 internal RC btreeCreateTable(ref int piTable, CREATETABLE createTabFlags)
 {
     var pBt = this.Shared;
     var pRoot = new MemPage();
     Pgno pgnoRoot = 0;
     int ptfFlags;          // Page-type flage for the root page of new table
     RC rc;
     Debug.Assert(sqlite3BtreeHoldsMutex());
     Debug.Assert(pBt.InTransaction == TRANS.WRITE);
     Debug.Assert(!pBt.ReadOnly);
     #if SQLITE_OMIT_AUTOVACUUM
     rc = allocateBtreePage(pBt, ref pRoot, ref pgnoRoot, 1, 0);
     if (rc != SQLITE.OK)
         return rc;
     #else
     if (pBt.AutoVacuum)
     {
         Pgno pgnoMove = 0; // Move a page here to make room for the root-page
         var pPageMove = new MemPage(); // The page to move to.
         // Creating a new table may probably require moving an existing database to make room for the new tables root page. In case this page turns
         // out to be an overflow page, delete all overflow page-map caches held by open cursors.
         invalidateAllOverflowCache(pBt);
         // Read the value of meta[3] from the database to determine where the root page of the new table should go. meta[3] is the largest root-page
         // created so far, so the new root-page is (meta[3]+1).
         GetMeta((int)META.LARGEST_ROOT_PAGE, ref pgnoRoot);
         pgnoRoot++;
         // The new root-page may not be allocated on a pointer-map page, or the PENDING_BYTE page.
         while (pgnoRoot == MemPage.PTRMAP_PAGENO(pBt, pgnoRoot) || pgnoRoot == MemPage.PENDING_BYTE_PAGE(pBt))
             pgnoRoot++;
         Debug.Assert(pgnoRoot >= 3);
         // Allocate a page. The page that currently resides at pgnoRoot will be moved to the allocated page (unless the allocated page happens to reside at pgnoRoot).
         rc = pBt.allocateBtreePage(ref pPageMove, ref pgnoMove, pgnoRoot, 1);
         if (rc != RC.OK)
             return rc;
         if (pgnoMove != pgnoRoot)
         {
             // pgnoRoot is the page that will be used for the root-page of the new table (assuming an error did not occur). But we were
             // allocated pgnoMove. If required (i.e. if it was not allocated by extending the file), the current page at position pgnoMove
             // is already journaled.
             PTRMAP eType = 0;
             Pgno iPtrPage = 0;
             pPageMove.releasePage();
             // Move the page currently at pgnoRoot to pgnoMove.
             rc = pBt.btreeGetPage(pgnoRoot, ref pRoot, 0);
             if (rc != RC.OK)
                 return rc;
             rc = pBt.ptrmapGet(pgnoRoot, ref eType, ref iPtrPage);
             if (eType == PTRMAP.ROOTPAGE || eType == PTRMAP.FREEPAGE)
                 rc = SysEx.SQLITE_CORRUPT_BKPT();
             if (rc != RC.OK)
             {
                 pRoot.releasePage();
                 return rc;
             }
             Debug.Assert(eType != PTRMAP.ROOTPAGE);
             Debug.Assert(eType != PTRMAP.FREEPAGE);
             rc = MemPage.relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0);
             pRoot.releasePage();
             // Obtain the page at pgnoRoot
             if (rc != RC.OK)
                 return rc;
             rc = pBt.btreeGetPage(pgnoRoot, ref pRoot, 0);
             if (rc != RC.OK)
                 return rc;
             rc = Pager.Write(pRoot.DbPage);
             if (rc != RC.OK)
             {
                 pRoot.releasePage();
                 return rc;
             }
         }
         else
             pRoot = pPageMove;
         // Update the pointer-map and meta-data with the new root-page number.
         pBt.ptrmapPut(pgnoRoot, PTRMAP.ROOTPAGE, 0, ref rc);
         if (rc != RC.OK)
         {
             pRoot.releasePage();
             return rc;
         }
         // When the new root page was allocated, page 1 was made writable in order either to increase the database filesize, or to decrement the
         // freelist count.  Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
         Debug.Assert(Pager.IsPageWriteable(pBt.Page1.DbPage));
         rc = SetMeta(4, pgnoRoot);
         if (Check.NEVER(rc != RC.OK))
         {
             pRoot.releasePage();
             return rc;
         }
     }
     else
     {
         rc = pBt.allocateBtreePage(ref pRoot, ref pgnoRoot, 1, 0);
         if (rc != RC.OK)
             return rc;
     }
     #endif
     Debug.Assert(Pager.IsPageWriteable(pRoot.DbPage));
     ptfFlags = ((createTabFlags & CREATETABLE.INTKEY) != 0 ? PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF : PTF_ZERODATA | PTF_LEAF);
     pRoot.zeroPage(ptfFlags);
     Pager.Unref(pRoot.DbPage);
     Debug.Assert((pBt.OpenFlags & OPEN.SINGLE) == 0 || pgnoRoot == 2);
     piTable = (int)pgnoRoot;
     return RC.OK;
 }