-C Fix\ssome\sharmless\scompiler\swarnings.
-D 2015-07-01T04:08:40.538
+C Rework\sthe\sPRAGMA\sintegrity_check\slogic.\s\sSimplify\sthe\scheckTreePage()\sroutine\nand\sclean\sup\sthe\serror\smessages\sgenerated.
+D 2015-07-01T17:13:45.237
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 285a0a234ed7610d431d91671c136098c2bd86a9
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
-F src/btree.c 075ce6ddce9e66277c898f5b6a44a8a7c61c8125
+F src/btree.c 41c63a0f4e24ca02a9e1142020669a8a3485f22c
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
-F src/btreeInt.h c54d380cb262549c4176e0d665518cc1a3861bdf
+F src/btreeInt.h 2ad754dd4528baa8d0946a593cc373b890bf859e
F src/build.c b3f15255d5b16e42dafeaa638fd4f8a47c94ed70
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
F src/os_unix.c 23eb5f56fac54d8fe0cb204291f3b3b2d94f23fc
F src/os_win.c 27cc135e2d0b8b1e2e4944db1e2669a6a18fa0f8
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
-F src/pager.c 922d8ea28387b79a117488da06ee84f77d50d71e
-F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77
+F src/pager.c aa916ca28606ccf4b6877dfc2b643ccbca86589f
+F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2
F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8
F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0
F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
-F test/corrupt2.test f2064e0bf934124cc38868fd8badb8f0dd67b552
-F test/corrupt3.test 4b548d0bbe2933bc81d3f54099a05fc4d28aff18
+F test/corrupt2.test 929c68b858f066599960ca8f8529a43602bc2759
+F test/corrupt3.test 747c0d5993ee85a739600f17957cd6ab360f1d8d
F test/corrupt4.test b99652079d542b21f4965f6248703b983e40fe80
F test/corrupt5.test 8ead52af76006f3286e9396cb41898018ccea107
F test/corrupt6.test 269548d19427ac554c830763b1c5ea54a0252f80
-F test/corrupt7.test 22cc644c2e76c9804bc844121267aa6f8f7c0ded
+F test/corrupt7.test beb6b166443c392c7e0348f6b5b8d03fb75e7667
F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516
F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
F test/corruptA.test 53e56dafd180addcdadb402244b8cb9771d2ba26
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
F test/corruptC.test 3fcc0f73d2cf2d69befe2d96332b942426a6aae2
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
-F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
+F test/corruptE.test 4d81d3079c75f49ec2494221e5c46757a0bfac30
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test 6a88fd9ca15b804e9c20990773262ca67494058f
-F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2
+F test/pragma.test 75fcb9bc90940fea538e542e07798ac2732130b6
F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028
F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 59ad912c4c1f858e04d27b1b8f25581a5f6e5daf
-R 71a875c7f3b6312a533d9c1fd4d005d9
+P 307195c8709d7fd2a642baa8011eb0c88cfdc0ac
+R b1c4a6aaa6fdb8ddbfc860994709a186
+T *branch * integrity-check-refactor
+T *sym-integrity-check-refactor *
+T -sym-trunk *
U drh
-Z 39cb6954bdcd951136843b690dd37c51
+Z 7bdf3de567fd950f32ae21a90fed9aca
** These checks are done:
**
** 1. Make sure that cells and freeblocks do not overlap
-** but combine to completely cover the page.
-** NO 2. Make sure cell keys are in order.
-** NO 3. Make sure no key is less than or equal to zLowerBound.
-** NO 4. Make sure no key is greater than or equal to zUpperBound.
-** 5. Check the integrity of overflow pages.
-** 6. Recursively call checkTreePage on all children.
-** 7. Verify that the depth of all children is the same.
-** 8. Make sure this page is at least 33% full or else it is
-** the root of the tree.
+** 2. Ensure that every byte of the page is accounted for
+** 3. Make sure integer cell keys are in order.
+** 4. Check the integrity of overflow pages.
+** 5. Recursively call checkTreePage on all children.
+** 6. Verify that the depth of all children is the same.
*/
static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
int iPage, /* Page number of the page to check */
- i64 *pnParentMinKey,
- i64 *pnParentMaxKey
+ i64 minKey, /* All integer primary keys must be >= this value */
+ i64 maxKey /* All integer primary keys must be <= this value */
){
- MemPage *pPage;
+ MemPage *pPage = 0;
int i, rc, depth, d2, pgno, cnt;
int hdr, cellStart;
int nCell;
int usableSize;
u32 *heap = 0;
u32 x, prev = 0;
- i64 nMinKey = 0;
- i64 nMaxKey = 0;
+ u32 pc;
+ int doCoverageCheck = 1;
+ int contentOffset;
const char *saved_zPfx = pCheck->zPfx;
int saved_v1 = pCheck->v1;
int saved_v2 = pCheck->v2;
pCheck->zPfx = "Page %d: ";
pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
- checkAppendMsg(pCheck,
- "unable to get the page. error code=%d", rc);
+ checkAppendMsg(pCheck, "unreadable - error code=%d", rc);
depth = -1;
goto end_of_check;
}
pPage->isInit = 0;
if( (rc = btreeInitPage(pPage))!=0 ){
assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
- checkAppendMsg(pCheck,
- "btreeInitPage() returns error code %d", rc);
- releasePage(pPage);
+ checkAppendMsg(pCheck, "corrupt header or freelist");
depth = -1;
goto end_of_check;
}
- /* Check out all the cells.
- */
+ /* Initialize variables used during cell scan */
+ data = pPage->aData;
+ hdr = pPage->hdrOffset;
depth = 0;
+ contentOffset = get2byteNotZero(&data[hdr+5]);
+ assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
+
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
+ nCell = get2byte(&data[hdr+3]);
+ assert( nCell==pPage->nCell );
+
+ /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
+ ** immediately follows the b-tree page header. */
+ cellStart = pPage->cellOffset;
+
+ /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
+ ** integer offsets to the cell contents. */
+ pCheck->zPfx = "Page %d cell %d: ";
for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
- u8 *pCell;
- u32 sz;
CellInfo info;
- /* Check payload overflow pages
- */
- pCheck->zPfx = "On tree page %d cell %d: ";
- pCheck->v1 = iPage;
pCheck->v2 = i;
- pCell = findCell(pPage,i);
- pPage->xParseCell(pPage, pCell, &info);
- sz = info.nPayload;
- /* For intKey pages, check that the keys are in order.
- */
- if( pPage->intKey ){
- if( i==0 ){
- nMinKey = nMaxKey = info.nKey;
- }else if( info.nKey <= nMaxKey ){
- checkAppendMsg(pCheck,
- "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
- }
- nMaxKey = info.nKey;
- }
- if( (sz>info.nLocal)
- && (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize])
- ){
- int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
- Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
+ pc = get2byteAligned(&data[cellStart+i*2]);
+ if( pc<contentOffset || pc>usableSize-4 ){
+ checkAppendMsg(pCheck,
+ "offset (%d) out of range %d..%d",
+ pc, contentOffset, usableSize-4
+ );
+ doCoverageCheck = 0;
+ continue;
+ }
+ pPage->xParseCell(pPage, &data[pc], &info);
+ if( pc+info.nSize > usableSize ){
+ checkAppendMsg(pCheck, "oversized content");
+ doCoverageCheck = 0;
+ }else
+
+ /* Scan overflow pages */
+ if( info.nPayload>info.nLocal ){
+ int nPage;
+ Pgno pgnoOvfl;
+ assert( pc+info.iOverflow <= usableSize-4 );
+ nPage = (info.nPayload - info.nLocal + usableSize-5)/(usableSize-4);
+ pgnoOvfl = get4byte(&data[pc+info.iOverflow]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage);
checkList(pCheck, 0, pgnoOvfl, nPage);
}
- /* Check sanity of left child page.
- */
+ /* Check sanity of left child page. */
if( !pPage->leaf ){
- pgno = get4byte(pCell);
+ pgno = get4byte(&data[pc]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
- d2 = checkTreePage(pCheck, pgno, &nMinKey, i==0?NULL:&nMaxKey);
+ d2 = checkTreePage(pCheck, pgno, minKey, info.nKey);
if( i>0 && d2!=depth ){
- checkAppendMsg(pCheck, "Child page depth differs");
+ checkAppendMsg(pCheck, "inconsistent subtree depth");
}
depth = d2;
}
+
+ /* For intKey pages, check that the keys are in order. */
+ if( pPage->intKey ){
+ i64 mx = maxKey - (nCell - (i+1));
+ if( info.nKey<minKey || info.nKey>mx ){
+ checkAppendMsg(pCheck, "rowid %lld out of range %lld..%lld",
+ info.nKey, minKey, mx);
+ }else{
+ minKey = info.nKey+1;
+ }
+ }
}
if( !pPage->leaf ){
- pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- pCheck->zPfx = "On page %d at right child: ";
- pCheck->v1 = iPage;
+ pgno = get4byte(&data[pPage->hdrOffset+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
+ pCheck->zPfx = "Page %d right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
- checkTreePage(pCheck, pgno, NULL, !pPage->nCell?NULL:&nMaxKey);
- }
-
- /* For intKey leaf pages, check that the min/max keys are in order
- ** with any left/parent/right pages.
- */
- pCheck->zPfx = "Page %d: ";
- pCheck->v1 = iPage;
- if( pPage->leaf && pPage->intKey ){
- /* if we are a left child page */
- if( pnParentMinKey ){
- /* if we are the left most child page */
- if( !pnParentMaxKey ){
- if( nMaxKey > *pnParentMinKey ){
- checkAppendMsg(pCheck,
- "Rowid %lld out of order (max larger than parent min of %lld)",
- nMaxKey, *pnParentMinKey);
- }
- }else{
- if( nMinKey <= *pnParentMinKey ){
- checkAppendMsg(pCheck,
- "Rowid %lld out of order (min less than parent min of %lld)",
- nMinKey, *pnParentMinKey);
- }
- if( nMaxKey > *pnParentMaxKey ){
- checkAppendMsg(pCheck,
- "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 ){
- if( nMinKey <= *pnParentMaxKey ){
- checkAppendMsg(pCheck,
- "Rowid %lld out of order (min less than parent max of %lld)",
- nMinKey, *pnParentMaxKey);
- }
+ d2 = checkTreePage(pCheck, pgno, minKey, maxKey);
+ if( d2!=depth && nCell>0 ){
+ checkAppendMsg(pCheck, "inconsistent subtree depth");
}
}
/* Check for complete coverage of the page
*/
- data = pPage->aData;
- hdr = pPage->hdrOffset;
- heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
- pCheck->zPfx = 0;
- if( heap==0 ){
- pCheck->mallocFailed = 1;
- }else{
- int contentOffset = get2byteNotZero(&data[hdr+5]);
- assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
+ if( doCoverageCheck ){
+ heap = pCheck->heap;
heap[0] = 0;
btreeHeapInsert(heap, contentOffset-1);
- /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
- ** number of cells on the page. */
- nCell = get2byte(&data[hdr+3]);
- /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
- ** immediately follows the b-tree page header. */
- cellStart = hdr + 12 - 4*pPage->leaf;
- /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
- ** integer offsets to the cell contents. */
for(i=nCell-1; i>=0; i--){
u32 pc = get2byteAligned(&data[cellStart+i*2]);
u32 size = pPage->xCellSize(pPage, &data[pc]);
- if( (int)(pc+size-1)>=usableSize ){
- pCheck->zPfx = 0;
- checkAppendMsg(pCheck,
- "Corruption detected in cell %d on page %d",i,iPage);
- }else{
- btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
- }
+ assert( pc+size <= usableSize ); /* Otherwise doCoverageCheck==0 */
+ btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
/* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
** is the offset of the first freeblock, or zero if there are no
assert( heap[0]>0 );
assert( (heap[1]>>16)==0 );
btreeHeapPull(heap,&prev);
+ pCheck->zPfx = "Page %d: ";
while( btreeHeapPull(heap,&x) ){
if( (prev&0xffff)+1>(x>>16) ){
- checkAppendMsg(pCheck,
- "Multiple uses for byte %u of page %d", x>>16, iPage);
+ checkAppendMsg(pCheck, "multiple uses for byte %u", x>>16);
break;
}else{
cnt += (x>>16) - (prev&0xffff) - 1;
*/
if( heap[0]==0 && cnt!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %d",
- cnt, data[hdr+7], iPage);
+ "fragmentation of %d should be %d", data[hdr+7], cnt);
}
}
- sqlite3PageFree(heap);
- releasePage(pPage);
end_of_check:
+ releasePage(pPage);
pCheck->zPfx = saved_zPfx;
pCheck->v1 = saved_v1;
pCheck->v2 = saved_v2;
int *pnErr /* Write number of errors seen to this variable */
){
Pgno i;
- int nRef;
+ VVA_ONLY( int nRef );
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
+ int savedDbFlags = pBt->db->flags;
char zErr[100];
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
- nRef = sqlite3PagerRefcount(pBt->pPager);
+ assert( (nRef = sqlite3PagerRefcount(pBt->pPager))>=0 );
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.zPfx = 0;
sCheck.v1 = 0;
sCheck.v2 = 0;
- *pnErr = 0;
+ sCheck.aPgRef = 0;
+ sCheck.heap = 0;
+ sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
if( sCheck.nPage==0 ){
- sqlite3BtreeLeave(p);
- return 0;
+ goto integrity_ck_cleanup;
}
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
- *pnErr = 1;
- sqlite3BtreeLeave(p);
- return 0;
+ sCheck.nErr = 1;
+ goto integrity_ck_cleanup;
}
+ sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
+ if( sCheck.heap==0 ){
+ sCheck.mallocFailed = 1;
+ goto integrity_ck_cleanup;
+ }
+
i = PENDING_BYTE_PAGE(pBt);
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
- sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
/* Check the integrity of the freelist
*/
/* Check all the tables.
*/
+ pBt->db->flags &= ~SQLITE_CellSizeCk;
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
+
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
- sCheck.zPfx = "List of tree roots: ";
- checkTreePage(&sCheck, aRoot[i], NULL, NULL);
- sCheck.zPfx = 0;
+ checkTreePage(&sCheck, aRoot[i], SMALLEST_INT64, LARGEST_INT64);
}
+ pBt->db->flags = savedDbFlags;
/* Make sure every page in the file is referenced
*/
#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);
+integrity_ck_cleanup:
+ sqlite3PageFree(sCheck.heap);
sqlite3_free(sCheck.aPgRef);
if( sCheck.mallocFailed ){
sqlite3StrAccumReset(&sCheck.errMsg);
- *pnErr = sCheck.nErr+1;
- return 0;
+ sCheck.nErr++;
}
*pnErr = sCheck.nErr;
if( sCheck.nErr==0 ) sqlite3StrAccumReset(&sCheck.errMsg);
+ /* Make sure this analysis did not leave any unref() pages. */
+ assert( nRef==sqlite3PagerRefcount(pBt->pPager) );
+ sqlite3BtreeLeave(p);
return sqlite3StrAccumFinish(&sCheck.errMsg);
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */