コード例 #1
0
        internal static void checkPtrmap(IntegrityCk pCheck, Pgno iChild, byte eType, Pgno iParent, string zContext)
        {
            byte ePtrmapType   = 0;
            Pgno iPtrmapParent = 0;
            var  rc            = ptrmapGet(pCheck.pBt, iChild, ref ePtrmapType, ref iPtrmapParent);

            if (rc != SQLITE.OK)
            {
                checkAppendMsg(pCheck, zContext, "Failed to read ptrmap key=%d", iChild);
                return;
            }
            if (ePtrmapType != eType || iPtrmapParent != iParent)
            {
                checkAppendMsg(pCheck, zContext, "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", iChild, eType, iParent, ePtrmapType, iPtrmapParent);
            }
        }
コード例 #2
0
 internal static int checkRef(IntegrityCk pCheck, Pgno iPage, string zContext)
 {
     if (iPage == 0)
     {
         return(1);
     }
     if (iPage > pCheck.nPage)
     {
         checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
         return(1);
     }
     if (pCheck.anRef[iPage] == 1)
     {
         checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
         return(1);
     }
     return(((pCheck.anRef[iPage]++) > 1) ? 1 : 0);
 }
コード例 #3
0
 internal static void checkAppendMsg(IntegrityCk pCheck, StringBuilder zMsg1, string zFormat, params object[] ap)
 {
     if (pCheck.mxErr == 0)
     {
         return;
     }
     lock (lock_va_list)
     {
         pCheck.mxErr--;
         pCheck.nErr++;
         va_start(ap, zFormat);
         if (pCheck.errMsg.zText.Length != 0)
         {
             sqlite3StrAccumAppend(pCheck.errMsg, "\n", 1);
         }
         if (zMsg1.Length > 0)
         {
             sqlite3StrAccumAppend(pCheck.errMsg, zMsg1.ToString(), -1);
         }
         sqlite3VXPrintf(pCheck.errMsg, 1, zFormat, ap);
         va_end(ref ap);
     }
 }
コード例 #4
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
        public string IntegrityCheck(Pid[] roots, int rootsLength, int maxErrors, out int errors)
        {
            BtShared bt = Bt;
            Enter();
            Debug.Assert(InTrans > TRANS.NONE && bt.InTransaction > TRANS.NONE);
            int refs = bt.Pager.get_Refs();
            IntegrityCk check = new IntegrityCk();
            check.Bt = bt;
            check.Pager = bt.Pager;
            check.Pages = btreePagecount(check.Bt);
            check.MaxErrors = maxErrors;
            check.Errors = 0;
            check.MallocFailed = false;
            errors = 0;
            if (check.Pages == 0)
            {
                Leave();
                return null;
            }
            check.PgRefs = C._alloc((int)(check.Pages / 8) + 1);
            if (check.PgRefs == null)
            {
                errors = 1;
                Leave();
                return null;
            }
            Pid i = PENDING_BYTE_PAGE(bt);
            if (i <= check.Pages) setPageReferenced(check, i);
            TextBuilder.Init(check.ErrMsg, 1000, 20000);

            // Check the integrity of the freelist
            checkList(check, true, (Pid)ConvertEx.Get4(bt.Page1.Data, 32), (int)ConvertEx.Get4(bt.Page1.Data, 36), "Main freelist: ");

            // Check all the tables.
            for (i = 0; (int)i < rootsLength && check.MaxErrors != 0; i++)
            {
                if (roots[i] == 0) continue;
#if !OMIT_AUTOVACUUM
                if (bt.AutoVacuum && roots[i] > 1)
                    checkPtrmap(check, roots[i], PTRMAP.ROOTPAGE, 0, null);
#endif
                checkTreePage(check, roots[i], "List of tree roots: ", ref _nullRef_, false, ref _nullRef_, false);
            }

            // Make sure every page in the file is referenced
            for (i = 1; i <= check.Pages && check.MaxErrors != 0; i++)
            {
#if OMIT_AUTOVACUUM
                if (check.PgRefs[i] == null)
                    checkAppendMsg(check, null, "Page %d is never used", i);
#else
                // If the database supports auto-vacuum, make sure no tables contain references to pointer-map pages.
                if (!getPageReferenced(check, i) && (PTRMAP_PAGENO(bt, i) != i || !bt.AutoVacuum))
                    checkAppendMsg(check, (string)null, "Page %d is never used", i);
                if (getPageReferenced(check, i) && (PTRMAP_PAGENO(bt, i) == i && bt.AutoVacuum))
                    checkAppendMsg(check, (string)null, "Pointer map page %d is referenced", i);
#endif
            }

            // Make sure this analysis did not leave any unref() pages. This is an internal consistency check; an integrity check
            // of the integrity check.
            if (C._NEVER(refs != bt.Pager.get_Refs()))
                checkAppendMsg(check, (string)null, "Outstanding page count goes from %d to %d during this analysis", refs, bt.Pager.get_Refs());

            // Clean  up and report errors.
            Leave();
            check.PgRefs = null;
            if (check.MallocFailed)
            {
                check.ErrMsg.Reset();
                errors = check.Errors + 1;
                return null;
            }
            errors = check.Errors;
            if (check.Errors == 0)
                check.ErrMsg.Reset();
            return check.ErrMsg.ToString();
        }
コード例 #5
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
        static int checkTreePage(IntegrityCk check, Pid pageID, string parentContext, ref long parentMinKey, bool hasParentMinKey, ref long parentMaxKey, bool hasParentMaxKey)
        {
            var msg = new StringBuilder(100);
            msg.AppendFormat("Page {0}: ", pageID);

            // Check that the page exists
            var bt = check.Bt;
            var usableSize = (int)bt.UsableSize;
            if (pageID == 0) return 0;
            if (checkRef(check, pageID, parentContext)) return 0;
            RC rc;
            MemPage page = new MemPage();
            if ((rc = btreeGetPage(bt, pageID, ref page, false)) != RC.OK)
            {
                checkAppendMsg(check, msg.ToString(), "unable to get the page. error code=%d", rc);
                return 0;
            }

            // Clear MemPage.isInit to make sure the corruption detection code in btreeInitPage() is executed.
            page.IsInit = false;
            if ((rc = btreeInitPage(page)) != RC.OK)
            {
                Debug.Assert(rc == RC.CORRUPT); // The only possible error from InitPage
                checkAppendMsg(check, msg.ToString(), "btreeInitPage() returns error code %d", rc);
                releasePage(page);
                return 0;
            }

            // Check out all the cells.
            Pid id;
            uint i;
            int depth = 0;
            long minKey = 0;
            long maxKey = 0;
            for (i = 0U; i < page.Cells && check.MaxErrors != 0; i++)
            {
                // Check payload overflow pages
                msg.AppendFormat("On tree page {0} cell {1}: ", pageID, i);
                uint cell_ = findCell(page, i);
                var info = new CellInfo();
                btreeParseCellPtr(page, cell_, ref info);
                uint sizeCell = info.Data;
                if (!page.IntKey) sizeCell += (uint)info.Key;
                // For intKey pages, check that the keys are in order.
                else if (i == 0) minKey = maxKey = info.Key;
                else
                {
                    if (info.Key <= maxKey)
                        checkAppendMsg(check, msg.ToString(), "Rowid %lld out of order (previous was %lld)", info.Key, maxKey);
                    maxKey = info.Key;
                }
                Debug.Assert(sizeCell == info.Payload);
                if (sizeCell > info.Local) //&& pCell[info.iOverflow]<=&pPage.aData[pBt.usableSize]
                {
                    int pages = (int)(sizeCell - info.Local + usableSize - 5) / (usableSize - 4);
                    Pid ovflID = ConvertEx.Get4(page.Data, cell_ + info.Overflow);
#if !OMIT_AUTOVACUUM
                    if (bt.AutoVacuum)
                        checkPtrmap(check, ovflID, PTRMAP.OVERFLOW1, pageID, msg.ToString());
#endif
                    checkList(check, false, ovflID, pages, msg.ToString());
                }

                // Check sanity of left child page.
                if (!page.Leaf)
                {
                    id = (Pid)ConvertEx.Get4(page.Data, cell_);
#if !OMIT_AUTOVACUUM
                    if (bt.AutoVacuum)
                        checkPtrmap(check, id, PTRMAP.BTREE, pageID, msg.ToString());
#endif
                    int depth2;
                    if (i == 0)
                        depth2 = checkTreePage(check, id, msg.ToString(), ref minKey, true, ref _nullRef_, false);
                    else
                        depth2 = checkTreePage(check, id, msg.ToString(), ref minKey, true, ref maxKey, true);

                    if (i > 0 && depth2 != depth)
                        checkAppendMsg(check, msg, "Child page depth differs");
                    depth = depth2;
                }
            }
            if (!page.Leaf)
            {
                id = (Pid)ConvertEx.Get4(page.Data, page.HdrOffset + 8);
                msg.AppendFormat("On page {0} at right child: ", pageID);
#if !OMIT_AUTOVACUUM
                if (bt.AutoVacuum)
                    checkPtrmap(check, id, PTRMAP.BTREE, pageID, msg.ToString());
#endif
                if (page.Cells == 0)
                    checkTreePage(check, id, msg.ToString(), ref _nullRef_, false, ref _nullRef_, false);
                else
                    checkTreePage(check, id, msg.ToString(), ref _nullRef_, false, ref maxKey, true);
            }

            // For intKey leaf pages, check that the min/max keys are in order with any left/parent/right pages.
            if (page.Leaf && page.IntKey)
            {
                // if we are a left child page
                if (hasParentMinKey)
                {
                    // if we are the left most child page
                    if (!hasParentMaxKey)
                    {
                        if (maxKey > parentMinKey)
                            checkAppendMsg(check, msg, "Rowid %lld out of order (max larger than parent min of %lld)", maxKey, parentMinKey);
                    }
                    else
                    {
                        if (minKey <= parentMinKey)
                            checkAppendMsg(check, msg, "Rowid %lld out of order (min less than parent min of %lld)", minKey, parentMinKey);
                        if (maxKey > parentMaxKey)
                            checkAppendMsg(check, msg, "Rowid %lld out of order (max larger than parent max of %lld)", maxKey, parentMaxKey);
                        parentMinKey = maxKey;
                    }
                }
                // else if we're a right child page
                else if (hasParentMaxKey)
                {
                    if (minKey <= parentMaxKey)
                        checkAppendMsg(check, msg, "Rowid %lld out of order (min less than parent max of %lld)", minKey, parentMaxKey);
                }
            }

            // Check for complete coverage of the page
            byte[] data = page.Data;
            uint hdr = page.HdrOffset;
            byte[] hit = PCache.PageAlloc2((int)bt.PageSize);
            if (hit == null)
                check.MallocFailed = true;
            else
            {
                uint contentOffset = ConvertEx.Get2nz(data, hdr + 5);
                Debug.Assert(contentOffset <= usableSize); // Enforced by btreeInitPage()
                Array.Clear(hit, (int)contentOffset, (int)(usableSize - contentOffset));
                { for (uint z = contentOffset - 1; z >= 0; z--) hit[z] = 1; }// memset(hit, 1, contentOffset);
                uint cells = ConvertEx.Get2(data, hdr + 3);
                uint cellStart = hdr + 12 - 4 * (page.Leaf ? 1U : 0U);
                for (i = 0; i < cells; i++)
                {
                    var sizeCell = 65536U;
                    uint pc = ConvertEx.Get2(data, cellStart + i * 2);
                    if (pc <= usableSize - 4)
                        sizeCell = cellSizePtr(page, data, pc);
                    if ((int)(pc + sizeCell - 1) >= usableSize)
                        checkAppendMsg(check, (string)null, "Corruption detected in cell %d on page %d", i, pageID);
                    else
                        for (var j = (int)(pc + sizeCell - 1); j >= pc; j--) hit[j]++;
                }
                i = ConvertEx.Get2(data, hdr + 1);
                while (i > 0)
                {
                    Debug.Assert(i <= usableSize - 4); // Enforced by btreeInitPage()
                    uint size = ConvertEx.Get2(data, i + 2);
                    Debug.Assert(i + size <= usableSize); // Enforced by btreeInitPage()
                    uint j;
                    for (j = i + size - 1; j >= i; j--) hit[j]++;
                    j = ConvertEx.Get2(data, i);
                    Debug.Assert(j == 0 || j > i + size); // Enforced by btreeInitPage()
                    Debug.Assert(j <= usableSize - 4); // Enforced by btreeInitPage()
                    i = j;
                }
                uint cnt;
                for (i = cnt = 0; i < usableSize; i++)
                {
                    if (hit[i] == 0)
                        cnt++;
                    else if (hit[i] > 1)
                    {
                        checkAppendMsg(check, (string)null, "Multiple uses for byte %d of page %d", i, pageID);
                        break;
                    }
                }
                if (cnt != data[hdr + 7])
                    checkAppendMsg(check, (string)null, "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr + 7], pageID);
            }
            PCache.PageFree2(ref hit);
            releasePage(page);
            return depth + 1;
        }
コード例 #6
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
        static void checkList(IntegrityCk check, bool isFreeList, Pid pageID, int length, string context)
        {
            int expected = length;
            Pid firstID = pageID;
            while (length-- > 0 && check.MaxErrors != 0)
            {
                if (pageID < 1)
                {
                    checkAppendMsg(check, context, "%d of %d pages missing from overflow list starting at %d", length + 1, expected, firstID);
                    break;
                }
                if (checkRef(check, pageID, context)) break;
                PgHdr ovflPage = new PgHdr();
                if (check.Pager.Acquire((Pid)pageID, ref ovflPage, false) != RC.OK)
                {
                    checkAppendMsg(check, context, "failed to get page %d", pageID);
                    break;
                }
                byte[] ovflData = Pager.GetData(ovflPage);
                if (isFreeList)
                {
                    int n = (int)ConvertEx.Get4(ovflData, 4);
#if !OMIT_AUTOVACUUM
                    if (check.Bt.AutoVacuum)
                        checkPtrmap(check, (uint)pageID, PTRMAP.FREEPAGE, 0, context);
#endif
                    if (n > (int)check.Bt.UsableSize / 4 - 2)
                    {
                        checkAppendMsg(check, context, "freelist leaf count too big on page %d", pageID);
                        length--;
                    }
                    else
                    {
                        for (int i = 0; i < n; i++)
                        {
                            Pid freePageID = ConvertEx.Get4(ovflData, 8 + i * 4);
#if !OMIT_AUTOVACUUM
                            if (check.Bt.AutoVacuum)
                                checkPtrmap(check, freePageID, PTRMAP.FREEPAGE, 0, context);
#endif
                            checkRef(check, freePageID, context);
                        }
                        length -= n;
                    }
                }
#if !OMIT_AUTOVACUUM
                else
                {
                    // If this database supports auto-vacuum and iPage is not the last page in this overflow list, check that the pointer-map entry for
                    // the following page matches iPage.
                    if (check.Bt.AutoVacuum && length > 0)
                    {
                        int i = (int)ConvertEx.Get4(ovflData);
                        checkPtrmap(check, (uint)i, PTRMAP.OVERFLOW2, (uint)pageID, context);
                    }
                }
#endif
                pageID = (Pid)ConvertEx.Get4(ovflData);
                Pager.Unref(ovflPage);
            }
        }
コード例 #7
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
        static void checkPtrmap(IntegrityCk check, Pid childID, PTRMAP type, Pid parentID, string context)
        {
            PTRMAP ptrmapType = 0;
            Pid ptrmapParentID = 0;
            RC rc = ptrmapGet(check.Bt, childID, ref ptrmapType, ref ptrmapParentID);
            if (rc != RC.OK)
            {
                if (rc == RC.NOMEM || rc == RC.IOERR_NOMEM) check.MallocFailed = true;
                checkAppendMsg(check, context, "Failed to read ptrmap key=%d", childID);
                return;
            }

            if (ptrmapType != type || ptrmapParentID != parentID)
                checkAppendMsg(check, context, "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", childID, type, parentID, ptrmapType, ptrmapParentID);
        }
コード例 #8
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
 static bool checkRef(IntegrityCk check, Pid pageID, string context)
 {
     if (pageID == 0) return true;
     if (pageID > check.Pages)
     {
         checkAppendMsg(check, context, "invalid page number %d", pageID);
         return true;
     }
     if (getPageReferenced(check, pageID))
     {
         checkAppendMsg(check, context, "2nd reference to page %d", pageID);
         return true;
     }
     setPageReferenced(check, pageID);
     return true;
 }
コード例 #9
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
 static void setPageReferenced(IntegrityCk check, Pid pageID)
 {
     Debug.Assert(pageID <= check.Pages && sizeof(byte) == 1);
     check.PgRefs[pageID / 8] |= (byte)(1 << (int)(pageID & 0x07));
 }
コード例 #10
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
 static bool getPageReferenced(IntegrityCk check, Pid pageID)
 {
     Debug.Assert(pageID <= check.Pages && sizeof(byte) == 1);
     return ((check.PgRefs[pageID / 8] & (1 << (int)(pageID & 0x07))) != 0);
 }
コード例 #11
0
ファイル: Btree.cs プロジェクト: BclEx/GpuStructs
 static void checkAppendMsg(IntegrityCk check, StringBuilder msg1, string format, params object[] args)
 {
     if (check.MaxErrors == 0) return;
     //va_list ap;
     //lock (_va_listLock)
     {
         check.MaxErrors--;
         check.Errors++;
         //va_start(args, format);
         //if (check.errMsg.zText.Length != 0)
         //    sqlite3StrAccumAppend(check.errMsg, "\n", 1);
         //if (msg1.Length > 0)
         //    sqlite3StrAccumAppend(check.errMsg, msg1.ToString(), -1);
         //sqlite3VXPrintf(check.errMsg, 1, format, args);
         //va_end(ref args);
     }
 }
コード例 #12
0
        static string sqlite3BtreeIntegrityCheck(
            Btree p,      /* The btree to be checked */
            int[] aRoot,  /* An array of root pages numbers for individual trees */
            int nRoot,    /* Number of entries in aRoot[] */
            int mxErr,    /* Stop reporting errors after this many */
            ref int pnErr /* Write number of errors seen to this variable */
            )
        {
            Pgno          i;
            int           nRef;
            IntegrityCk   sCheck = new IntegrityCk();
            BtShared      pBt    = p.pBt;
            StringBuilder zErr   = new StringBuilder(100);//char zErr[100];

            sqlite3BtreeEnter(p);
            Debug.Assert(p.inTrans > TRANS_NONE && pBt.inTransaction > TRANS_NONE);
            nRef          = sqlite3PagerRefcount(pBt.pPager);
            sCheck.pBt    = pBt;
            sCheck.pPager = pBt.pPager;
            sCheck.nPage  = btreePagecount(sCheck.pBt);
            sCheck.mxErr  = mxErr;
            sCheck.nErr   = 0;
            //sCheck.mallocFailed = 0;
            pnErr = 0;
            if (sCheck.nPage == 0)
            {
                sqlite3BtreeLeave(p);
                return("");
            }
            sCheck.anRef = sqlite3Malloc(sCheck.anRef, (int)sCheck.nPage + 1);
            //if( !sCheck.anRef ){
            //  pnErr = 1;
            //  sqlite3BtreeLeave(p);
            //  return 0;
            //}
            // for (i = 0; i <= sCheck.nPage; i++) { sCheck.anRef[i] = 0; }
            i = PENDING_BYTE_PAGE(pBt);
            if (i <= sCheck.nPage)
            {
                sCheck.anRef[i] = 1;
            }
            sqlite3StrAccumInit(sCheck.errMsg, null, 1000, 20000);
            //sCheck.errMsg.useMalloc = 2;

            /* Check the integrity of the freelist
             */
            checkList(sCheck, 1, (int)sqlite3Get4byte(pBt.pPage1.aData, 32),
                      (int)sqlite3Get4byte(pBt.pPage1.aData, 36), "Main freelist: ");

            /* Check all the tables.
             */
            for (i = 0; (int)i < nRoot && sCheck.mxErr != 0; i++)
            {
                if (aRoot[i] == 0)
                {
                    continue;
                }
#if !SQLITE_OMIT_AUTOVACUUM
                if (pBt.autoVacuum && aRoot[i] > 1)
                {
                    checkPtrmap(sCheck, (u32)aRoot[i], PTRMAP_ROOTPAGE, 0, "");
                }
#endif
                checkTreePage(sCheck, aRoot[i], "List of tree roots: ", ref refNULL, ref refNULL, null, null);
            }

            /* Make sure every page in the file is referenced
             */
            for (i = 1; i <= sCheck.nPage && sCheck.mxErr != 0; i++)
            {
#if SQLITE_OMIT_AUTOVACUUM
                if (sCheck.anRef[i] == null)
                {
                    checkAppendMsg(sCheck, 0, "Page %d is never used", i);
                }
#else
                /* If the database supports auto-vacuum, make sure no tables contain
                ** references to pointer-map pages.
                */
                if (sCheck.anRef[i] == 0 &&
                    (PTRMAP_PAGENO(pBt, i) != i || !pBt.autoVacuum))
                {
                    checkAppendMsg(sCheck, "", "Page %d is never used", i);
                }
                if (sCheck.anRef[i] != 0 &&
                    (PTRMAP_PAGENO(pBt, i) == i && pBt.autoVacuum))
                {
                    checkAppendMsg(sCheck, "", "Pointer map page %d is referenced", i);
                }
#endif
            }

            /* Make sure this analysis did not leave any unref() pages.
            ** This is an internal consistency check; an integrity check
            ** of the integrity check.
            */
            if (NEVER(nRef != sqlite3PagerRefcount(pBt.pPager)))
            {
                checkAppendMsg(sCheck, "",
                               "Outstanding page count goes from %d to %d during this analysis",
                               nRef, sqlite3PagerRefcount(pBt.pPager)
                               );
            }

            /* Clean  up and report errors.
             */
            sqlite3BtreeLeave(p);
            sCheck.anRef = null;// sqlite3_free( ref sCheck.anRef );
            //if( sCheck.mallocFailed ){
            //  sqlite3StrAccumReset(sCheck.errMsg);
            //  pnErr = sCheck.nErr+1;
            //  return 0;
            //}
            pnErr = sCheck.nErr;
            if (sCheck.nErr == 0)
            {
                sqlite3StrAccumReset(sCheck.errMsg);
            }
            return(sqlite3StrAccumFinish(sCheck.errMsg));
        }
コード例 #13
0
        static i64 refNULL = 0;   //Dummy for C# ref NULL

        static int checkTreePage(
            IntegrityCk pCheck,    /* Context for the sanity check */
            int iPage,             /* Page number of the page to check */
            string zParentContext, /* Parent context */
            ref i64 pnParentMinKey,
            ref i64 pnParentMaxKey,
            object _pnParentMinKey, /* C# Needed to determine if content passed*/
            object _pnParentMaxKey  /* C# Needed to determine if content passed*/
            )
        {
            MemPage pPage = new MemPage();
            int     i, rc, depth, d2, pgno, cnt;
            int     hdr, cellStart;
            int     nCell;

            u8[]          data;
            BtShared      pBt;
            int           usableSize;
            StringBuilder zContext = new StringBuilder(100);

            byte[] hit     = null;
            i64    nMinKey = 0;
            i64    nMaxKey = 0;


            sqlite3_snprintf(200, zContext, "Page %d: ", iPage);

            /* Check that the page exists
             */
            pBt        = pCheck.pBt;
            usableSize = (int)pBt.usableSize;
            if (iPage == 0)
            {
                return(0);
            }
            if (checkRef(pCheck, (u32)iPage, zParentContext) != 0)
            {
                return(0);
            }
            if ((rc = btreeGetPage(pBt, (Pgno)iPage, ref pPage, 0)) != 0)
            {
                checkAppendMsg(pCheck, zContext.ToString(),
                               "unable to get the page. error code=%d", rc);
                return(0);
            }

            /* Clear MemPage.isInit to make sure the corruption detection code in
            ** btreeInitPage() is executed.  */
            pPage.isInit = 0;
            if ((rc = btreeInitPage(pPage)) != 0)
            {
                Debug.Assert(rc == SQLITE_CORRUPT);  /* The only possible error from InitPage */
                checkAppendMsg(pCheck, zContext.ToString(),
                               "btreeInitPage() returns error code %d", rc);
                releasePage(pPage);
                return(0);
            }

            /* Check out all the cells.
             */
            depth = 0;
            for (i = 0; i < pPage.nCell && pCheck.mxErr != 0; i++)
            {
                u8[]     pCell;
                u32      sz;
                CellInfo info = new CellInfo();

                /* Check payload overflow pages
                 */
                sqlite3_snprintf(200, zContext,
                                 "On tree page %d cell %d: ", iPage, i);
                int iCell = findCell(pPage, i);            //pCell = findCell( pPage, i );
                pCell = pPage.aData;
                btreeParseCellPtr(pPage, iCell, ref info); //btreeParseCellPtr( pPage, pCell, info );
                sz = info.nData;
                if (0 == pPage.intKey)
                {
                    sz += (u32)info.nKey;
                }

                /* For intKey pages, check that the keys are in order.
                 */
                else if (i == 0)
                {
                    nMinKey = nMaxKey = info.nKey;
                }
                else
                {
                    if (info.nKey <= nMaxKey)
                    {
                        checkAppendMsg(pCheck, zContext.ToString(),
                                       "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
                    }
                    nMaxKey = info.nKey;
                }
                Debug.Assert(sz == info.nPayload);
                if ((sz > info.nLocal)
                    //&& (pCell[info.iOverflow]<=&pPage.aData[pBt.usableSize])
                    )
                {
                    int  nPage    = (int)(sz - info.nLocal + usableSize - 5) / (usableSize - 4);
                    Pgno pgnoOvfl = sqlite3Get4byte(pCell, iCell, info.iOverflow);
#if !SQLITE_OMIT_AUTOVACUUM
                    if (pBt.autoVacuum)
                    {
                        checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, (u32)iPage, zContext.ToString());
                    }
#endif
                    checkList(pCheck, 0, (int)pgnoOvfl, nPage, zContext.ToString());
                }

                /* Check sanity of left child page.
                 */
                if (0 == pPage.leaf)
                {
                    pgno = (int)sqlite3Get4byte(pCell, iCell); //sqlite3Get4byte( pCell );
#if !SQLITE_OMIT_AUTOVACUUM
                    if (pBt.autoVacuum)
                    {
                        checkPtrmap(pCheck, (u32)pgno, PTRMAP_BTREE, (u32)iPage, zContext.ToString());
                    }
#endif
                    if (i == 0)
                    {
                        d2 = checkTreePage(pCheck, pgno, zContext.ToString(), ref nMinKey, ref refNULL, pCheck, null);
                    }
                    else
                    {
                        d2 = checkTreePage(pCheck, pgno, zContext.ToString(), ref nMinKey, ref nMaxKey, pCheck, pCheck);
                    }

                    if (i > 0 && d2 != depth)
                    {
                        checkAppendMsg(pCheck, zContext, "Child page depth differs");
                    }
                    depth = d2;
                }
            }
            if (0 == pPage.leaf)
            {
                pgno = (int)sqlite3Get4byte(pPage.aData, pPage.hdrOffset + 8);
                sqlite3_snprintf(200, zContext,
                                 "On page %d at right child: ", iPage);
#if !SQLITE_OMIT_AUTOVACUUM
                if (pBt.autoVacuum)
                {
                    checkPtrmap(pCheck, (u32)pgno, PTRMAP_BTREE, (u32)iPage, zContext.ToString());
                }
#endif
                //    checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey);
                if (0 == pPage.nCell)
                {
                    checkTreePage(pCheck, pgno, zContext.ToString(), ref refNULL, ref refNULL, null, null);
                }
                else
                {
                    checkTreePage(pCheck, pgno, zContext.ToString(), ref refNULL, ref nMaxKey, null, pCheck);
                }
            }

            /* For intKey leaf pages, check that the min/max keys are in order
            ** with any left/parent/right pages.
            */
            if (pPage.leaf != 0 && pPage.intKey != 0)
            {
                /* if we are a left child page */
                if (_pnParentMinKey != null)
                {
                    /* if we are the left most child page */
                    if (_pnParentMaxKey == null)
                    {
                        if (nMaxKey > pnParentMinKey)
                        {
                            checkAppendMsg(pCheck, zContext,
                                           "Rowid %lld out of order (max larger than parent min of %lld)",
                                           nMaxKey, pnParentMinKey);
                        }
                    }
                    else
                    {
                        if (nMinKey <= pnParentMinKey)
                        {
                            checkAppendMsg(pCheck, zContext,
                                           "Rowid %lld out of order (min less than parent min of %lld)",
                                           nMinKey, pnParentMinKey);
                        }
                        if (nMaxKey > pnParentMaxKey)
                        {
                            checkAppendMsg(pCheck, zContext,
                                           "Rowid %lld out of order (max larger than parent max of %lld)",
                                           nMaxKey, pnParentMaxKey);
                        }
                        pnParentMinKey = nMaxKey;
                    }
                    /* else if we're a right child page */
                }
                else if (_pnParentMaxKey != null)
                {
                    if (nMinKey <= pnParentMaxKey)
                    {
                        checkAppendMsg(pCheck, zContext,
                                       "Rowid %lld out of order (min less than parent max of %lld)",
                                       nMinKey, pnParentMaxKey);
                    }
                }
            }

            /* Check for complete coverage of the page
             */
            data = pPage.aData;
            hdr  = pPage.hdrOffset;
            hit  = sqlite3Malloc(pBt.pageSize);
            //if( hit==null ){
            //  pCheck.mallocFailed = 1;
            //}else
            {
                int contentOffset = get2byteNotZero(data, hdr + 5);
                Debug.Assert(contentOffset <= usableSize);                   /* Enforced by btreeInitPage() */
                Array.Clear(hit, contentOffset, usableSize - contentOffset); //memset(hit+contentOffset, 0, usableSize-contentOffset);
                for (int iLoop = contentOffset - 1; iLoop >= 0; iLoop--)
                {
                    hit[iLoop] = 1;//memset(hit, 1, contentOffset);
                }
                nCell     = get2byte(data, hdr + 3);
                cellStart = hdr + 12 - 4 * pPage.leaf;
                for (i = 0; i < nCell; i++)
                {
                    int pc   = get2byte(data, cellStart + i * 2);
                    u32 size = 65536;
                    int j;
                    if (pc <= usableSize - 4)
                    {
                        size = cellSizePtr(pPage, data, pc);
                    }
                    if ((int)(pc + size - 1) >= usableSize)
                    {
                        checkAppendMsg(pCheck, "",
                                       "Corruption detected in cell %d on page %d", i, iPage);
                    }
                    else
                    {
                        for (j = (int)(pc + size - 1); j >= pc; j--)
                        {
                            hit[j]++;
                        }
                    }
                }
                i = get2byte(data, hdr + 1);
                while (i > 0)
                {
                    int size, j;
                    Debug.Assert(i <= usableSize - 4);     /* Enforced by btreeInitPage() */
                    size = get2byte(data, i + 2);
                    Debug.Assert(i + size <= usableSize);  /* Enforced by btreeInitPage() */
                    for (j = i + size - 1; j >= i; j--)
                    {
                        hit[j]++;
                    }
                    j = get2byte(data, i);
                    Debug.Assert(j == 0 || j > i + size); /* Enforced by btreeInitPage() */
                    Debug.Assert(j <= usableSize - 4);    /* Enforced by btreeInitPage() */
                    i = j;
                }
                for (i = cnt = 0; i < usableSize; i++)
                {
                    if (hit[i] == 0)
                    {
                        cnt++;
                    }
                    else if (hit[i] > 1)
                    {
                        checkAppendMsg(pCheck, "",
                                       "Multiple uses for byte %d of page %d", i, iPage);
                        break;
                    }
                }
                if (cnt != data[hdr + 7])
                {
                    checkAppendMsg(pCheck, "",
                                   "Fragmentation of %d bytes reported as %d on page %d",
                                   cnt, data[hdr + 7], iPage);
                }
            }
            sqlite3PageFree(ref hit);
            releasePage(pPage);
            return(depth + 1);
        }
コード例 #14
0
        internal static void checkList(IntegrityCk pCheck, int isFreeList, int iPage, int N, string zContext)
        {
            int i;
            int expected = N;
            int iFirst   = iPage;

            while (N-- > 0 && pCheck.mxErr != 0)
            {
                var pOvflPage = new PgHdr();

                if (iPage < 1)
                {
                    checkAppendMsg(pCheck, zContext, "%d of %d pages missing from overflow list starting at %d", N + 1, expected, iFirst);
                    break;
                }
                if (checkRef(pCheck, (uint)iPage, zContext) != 0)
                {
                    break;
                }
                byte[] pOvflData;
                if (Pager.sqlite3PagerGet(pCheck.pPager, (Pgno)iPage, ref pOvflPage) != 0)
                {
                    checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage);
                    break;
                }
                pOvflData = Pager.sqlite3PagerGetData(pOvflPage);
                if (isFreeList != 0)
                {
                    int n = (int)ConvertEx.sqlite3Get4byte(pOvflData, 4);
#if !SQLITE_OMIT_AUTOVACUUM
                    if (pCheck.pBt.autoVacuum)
                    {
                        checkPtrmap(pCheck, (uint)iPage, PTRMAP_FREEPAGE, 0, zContext);
                    }
#endif
                    if (n > (int)pCheck.pBt.usableSize / 4 - 2)
                    {
                        checkAppendMsg(pCheck, zContext, "freelist leaf count too big on page %d", iPage);
                        N--;
                    }
                    else
                    {
                        for (i = 0; i < n; i++)
                        {
                            Pgno iFreePage = ConvertEx.sqlite3Get4byte(pOvflData, 8 + i * 4);
#if !SQLITE_OMIT_AUTOVACUUM
                            if (pCheck.pBt.autoVacuum)
                            {
                                checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext);
                            }
#endif
                            checkRef(pCheck, iFreePage, zContext);
                        }
                        N -= n;
                    }
                }
#if !SQLITE_OMIT_AUTOVACUUM
                else
                {
                    /* If this database supports auto-vacuum and iPage is not the last
                    ** page in this overflow list, check that the pointer-map entry for
                    ** the following page matches iPage.
                    */
                    if (pCheck.pBt.autoVacuum && N > 0)
                    {
                        i = (int)ConvertEx.sqlite3Get4byte(pOvflData);
                        checkPtrmap(pCheck, (uint)i, PTRMAP_OVERFLOW2, (uint)iPage, zContext);
                    }
                }
#endif
                iPage = (int)ConvertEx.sqlite3Get4byte(pOvflData);
                Pager.sqlite3PagerUnref(pOvflPage);
            }
        }