Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -8921,37 +8921,34 @@ ** return 1, and so forth. ** ** 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; u8 *data; BtShared *pBt; 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; /* Check that the page exists @@ -8961,166 +8958,130 @@ if( iPage==0 ) return 0; if( checkRef(pCheck, iPage) ) return 0; 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; } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ 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; inCell && 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( pcusableSize-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); } #endif checkList(pCheck, 0, pgnoOvfl, nPage); } - /* Check sanity of left child page. - */ - if( !pPage->leaf ){ - pgno = get4byte(pCell); -#ifndef SQLITE_OMIT_AUTOVACUUM - if( pBt->autoVacuum ){ - checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); - } -#endif - d2 = checkTreePage(pCheck, pgno, &nMinKey, i==0?NULL:&nMaxKey); - if( i>0 && d2!=depth ){ - checkAppendMsg(pCheck, "Child page depth differs"); - } - depth = d2; - } - } - - if( !pPage->leaf ){ - pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - pCheck->zPfx = "On page %d at right child: "; - pCheck->v1 = iPage; -#ifndef SQLITE_OMIT_AUTOVACUUM - if( pBt->autoVacuum ){ - 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); - } + /* Check sanity of left child page. */ + if( !pPage->leaf ){ + pgno = get4byte(&data[pc]); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); + } +#endif + d2 = checkTreePage(pCheck, pgno, minKey, info.nKey); + if( i>0 && d2!=depth ){ + 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.nKeymx ){ + checkAppendMsg(pCheck, "rowid %lld out of range %lld..%lld", + info.nKey, minKey, mx); + }else{ + minKey = info.nKey+1; + } + } + } + + if( !pPage->leaf ){ + 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 + 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 ** freeblocks on the page. */ i = get2byte(&data[hdr+1]); @@ -9143,14 +9104,14 @@ } cnt = 0; 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; prev = x; } @@ -9161,18 +9122,16 @@ ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the ** number of fragmented free bytes within the cell content area. */ 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; return depth+1; } @@ -9198,42 +9157,48 @@ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ 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.mxErr = mxErr; sCheck.nErr = 0; sCheck.mallocFailed = 0; 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 */ sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), @@ -9240,21 +9205,22 @@ get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; /* Check all the tables. */ + pBt->db->flags &= ~SQLITE_CellSizeCk; for(i=0; (int)iautoVacuum && 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 */ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM @@ -9274,32 +9240,24 @@ 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); +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 */ /* Index: src/btreeInt.h ================================================================== --- src/btreeInt.h +++ src/btreeInt.h @@ -680,10 +680,11 @@ int nErr; /* Number of messages written to zErrMsg so far */ int mallocFailed; /* A memory allocation error has occurred */ const char *zPfx; /* Error message prefix */ int v1, v2; /* Values for up to two %d fields in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ + u32 *heap; /* Min-heap used for analyzing cell coverage */ }; /* ** Routines to read or write a two- and four-byte big-endian integer values. */ Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -6385,16 +6385,18 @@ */ u8 sqlite3PagerIsreadonly(Pager *pPager){ return pPager->readOnly; } +#ifdef SQLITE_DEBUG /* ** Return the number of references to the pager. */ int sqlite3PagerRefcount(Pager *pPager){ return sqlite3PcacheRefCount(pPager->pPCache); } +#endif /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. */ Index: src/pager.h ================================================================== --- src/pager.h +++ src/pager.h @@ -171,11 +171,13 @@ #endif /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); u32 sqlite3PagerDataVersion(Pager*); -int sqlite3PagerRefcount(Pager*); +#ifdef SQLITE_DEBUG + int sqlite3PagerRefcount(Pager*); +#endif int sqlite3PagerMemUsed(Pager*); const char *sqlite3PagerFilename(Pager*, int); const sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); const char *sqlite3PagerJournalname(Pager*); Index: test/corrupt2.test ================================================================== --- test/corrupt2.test +++ test/corrupt2.test @@ -246,12 +246,12 @@ set result [db2 eval {pragma integrity_check}] break } set result } {{*** in database main *** -On tree page 2 cell 0: 2nd reference to page 10 -On tree page 2 cell 1: Child page depth differs +Page 2 cell 0: 2nd reference to page 10 +Page 2 cell 1: inconsistent subtree depth Page 4 is never used}} db2 close proc corruption_test {args} { Index: test/corrupt3.test ================================================================== --- test/corrupt3.test +++ test/corrupt3.test @@ -95,11 +95,11 @@ do_test corrupt3-1.10 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** -On tree page 2 cell 0: invalid page number 4 +Page 2 cell 0: invalid page number 4 Page 3 is never used}}} do_test corrupt3-1.11 { db close hexio_write test.db 2044 [hexio_render_int32 0] sqlite3 db test.db @@ -110,9 +110,9 @@ do_test corrupt3-1.12 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** -On tree page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0 +Page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0 Page 3 is never used}}} finish_test Index: test/corrupt7.test ================================================================== --- test/corrupt7.test +++ test/corrupt7.test @@ -67,41 +67,24 @@ # on page 2 of the database. # # The error message is different depending on whether or not the # SQLITE_ENABLE_OVERSIZE_CELL_CHECK compile-time option is engaged. # -ifcapable oversize_cell_check { - do_test corrupt7-2.1 { - db close - hexio_write test.db 1062 FF - sqlite3 db test.db - db eval {PRAGMA integrity_check(1)} - } {{*** in database main *** -Page 2: btreeInitPage() returns error code 11}} - do_test corrupt7-2.2 { - db close - hexio_write test.db 1062 04 - sqlite3 db test.db - db eval {PRAGMA integrity_check(1)} - } {{*** in database main *** -Page 2: btreeInitPage() returns error code 11}} -} else { - do_test corrupt7-2.1 { - db close - hexio_write test.db 1062 FF - sqlite3 db test.db - db eval {PRAGMA integrity_check(1)} - } {{*** in database main *** -Corruption detected in cell 15 on page 2}} - do_test corrupt7-2.2 { - db close - hexio_write test.db 1062 04 - sqlite3 db test.db - db eval {PRAGMA integrity_check(1)} - } {{*** in database main *** -On tree page 2 cell 15: Rowid 0 out of order (previous was 15)}} -} +do_test corrupt7-2.1 { + db close + hexio_write test.db 1062 FF + sqlite3 db test.db + db eval {PRAGMA cell_size_check=OFF; PRAGMA integrity_check(1)} +} {{*** in database main *** +Page 2 cell 15: offset (65457) out of range 945..1020}} +do_test corrupt7-2.2 { + db close + hexio_write test.db 1062 04 + sqlite3 db test.db + db eval {PRAGMA cell_size_check=OFF; PRAGMA integrity_check(1)} +} {{*** in database main *** +Page 2 cell 15: offset (1201) out of range 945..1020}} # The code path that was causing the buffer overrun that this test # case was checking for was removed. # #do_test corrupt7-3.1 { Index: test/corruptE.test ================================================================== --- test/corruptE.test +++ test/corruptE.test @@ -80,13 +80,12 @@ sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] - list [regexp {out of order.*previous was} $ans] \ - [regexp {out of order.*max larger than parent max} $ans] -} {1 1} + regexp {rowid \d+ out of range \d+\.\.\d+} $ans] +} {1} do_test corruptE-2.2 { db close forcecopy test.bu test.db @@ -96,13 +95,12 @@ sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] - list [regexp {out of order.*previous was} $ans] \ - [regexp {out of order.*min less than parent min} $ans] -} {1 1} + regexp {rowid \d+ out of range \d+\.\.\d+} $ans] +} {1} do_test corruptE-2.3 { db close forcecopy test.bu test.db @@ -113,11 +111,11 @@ sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] - list [regexp {out of order.*max larger than parent min} $ans] + regexp {rowid \d+ out of range \d+\.\.\d+} $ans] } {1} do_test corruptE-2.4 { db close forcecopy test.bu test.db @@ -128,13 +126,12 @@ sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] - list [regexp {out of order.*min less than parent max} $ans] + regexp {rowid \d+ out of range \d+\.\.\d+} $ans] } {1} - set tests [list {10233 0xd0} \ {941 0x42} \ {1028 0x53} \ {2041 0xd0} \ @@ -169,11 +166,11 @@ sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] - list [regexp {out of order} $ans] + list [regexp {out of range|database disk image is malformed} $ans] } {1} incr tc 1 } finish_test Index: test/pragma.test ================================================================== --- test/pragma.test +++ test/pragma.test @@ -1747,18 +1747,18 @@ forcecopy test.db testerr.db hexio_write testerr.db 15000 [string repeat 55 100] } {100} set mainerr {*** in database main *** -Multiple uses for byte 672 of page 15} +Page 15: multiple uses for byte 672} set auxerr {*** in database aux *** -Multiple uses for byte 672 of page 15} +Page 15: Multiple uses for byte 672} set mainerr {/{\*\*\* in database main \*\*\* -Multiple uses for byte 672 of page 15}.*/} +Page 15: multiple uses for byte 672}.*/} set auxerr {/{\*\*\* in database aux \*\*\* -Multiple uses for byte 672 of page 15}.*/} +Page 15: multiple uses for byte 672}.*/} do_test 22.2 { catch { db close } sqlite3 db testerr.db execsql { PRAGMA integrity_check }