diff options
Diffstat (limited to 'src/btree.c')
-rw-r--r-- | src/btree.c | 87 |
1 files changed, 56 insertions, 31 deletions
diff --git a/src/btree.c b/src/btree.c index 342ff2bf7..8d2dc37da 100644 --- a/src/btree.c +++ b/src/btree.c @@ -10120,6 +10120,15 @@ end_of_check: ** allocation errors, an error message held in memory obtained from ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is ** returned. If a memory allocation error occurs, NULL is returned. +** +** If the first entry in aRoot[] is 0, that indicates that the list of +** root pages is incomplete. This is a "partial integrity-check". This +** happens when performing an integrity check on a single table. The +** zero is skipped, of course. But in addition, the freelist checks +** and the checks to make sure every page is referenced are also skipped, +** since obviously it is not possible to know which pages are covered by +** the unverified btrees. Except, if aRoot[1] is 1, then the freelist +** checks are still performed. */ char *sqlite3BtreeIntegrityCheck( sqlite3 *db, /* Database connection that is running the check */ @@ -10135,6 +10144,16 @@ char *sqlite3BtreeIntegrityCheck( u64 savedDbFlags = pBt->db->flags; char zErr[100]; VVA_ONLY( int nRef ); + int bPartial = 0; /* True if not checking all btrees */ + int bCkFreelist = 1; /* True to scan the freelist */ + assert( nRoot>0 ); + + /* aRoot[0]==0 means this is a partial check */ + if( aRoot[0]==0 ){ + assert( nRoot>1 ); + bPartial = 1; + if( aRoot[1]!=1 ) bCkFreelist = 0; + } sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); @@ -10174,29 +10193,33 @@ char *sqlite3BtreeIntegrityCheck( /* Check the integrity of the freelist */ - sCheck.zPfx = "Main freelist: "; - checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), - get4byte(&pBt->pPage1->aData[36])); - sCheck.zPfx = 0; + if( bCkFreelist ){ + sCheck.zPfx = "Main freelist: "; + checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), + get4byte(&pBt->pPage1->aData[36])); + sCheck.zPfx = 0; + } /* Check all the tables. */ #ifndef SQLITE_OMIT_AUTOVACUUM - if( pBt->autoVacuum ){ - int mx = 0; - int mxInHdr; - for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i]; - mxInHdr = get4byte(&pBt->pPage1->aData[52]); - if( mx!=mxInHdr ){ + if( !bPartial ){ + if( pBt->autoVacuum ){ + int mx = 0; + int mxInHdr; + for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i]; + mxInHdr = get4byte(&pBt->pPage1->aData[52]); + if( mx!=mxInHdr ){ + checkAppendMsg(&sCheck, + "max rootpage (%d) disagrees with header (%d)", + mx, mxInHdr + ); + } + }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ checkAppendMsg(&sCheck, - "max rootpage (%d) disagrees with header (%d)", - mx, mxInHdr + "incremental_vacuum enabled with a max rootpage of zero" ); } - }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ - checkAppendMsg(&sCheck, - "incremental_vacuum enabled with a max rootpage of zero" - ); } #endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); @@ -10205,7 +10228,7 @@ char *sqlite3BtreeIntegrityCheck( i64 notUsed; if( aRoot[i]==0 ) continue; #ifndef SQLITE_OMIT_AUTOVACUUM - if( pBt->autoVacuum && aRoot[i]>1 ){ + if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif @@ -10215,22 +10238,24 @@ char *sqlite3BtreeIntegrityCheck( /* Make sure every page in the file is referenced */ - for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ + if( !bPartial ){ + for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM - if( getPageReferenced(&sCheck, i)==0 ){ - checkAppendMsg(&sCheck, "Page %d is never used", i); - } + if( getPageReferenced(&sCheck, i)==0 ){ + checkAppendMsg(&sCheck, "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(&sCheck, i)==0 && - (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, "Page %d is never used", i); - } - if( getPageReferenced(&sCheck, i)!=0 && - (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); + /* If the database supports auto-vacuum, make sure no tables contain + ** references to pointer-map pages. + */ + if( getPageReferenced(&sCheck, i)==0 && + (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Page %d is never used", i); + } + if( getPageReferenced(&sCheck, i)!=0 && + (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); + } } #endif } |