]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Rework the PRAGMA integrity_check logic. Simplify the checkTreePage() routine integrity-check-refactor
authordrh <drh@noemail.net>
Wed, 1 Jul 2015 17:13:45 +0000 (17:13 +0000)
committerdrh <drh@noemail.net>
Wed, 1 Jul 2015 17:13:45 +0000 (17:13 +0000)
and clean up the error messages generated.

FossilOrigin-Name: 1c52212369692ca7c0b16a14e3a403cd4c5fbffc

manifest
manifest.uuid
src/btree.c
src/btreeInt.h
src/pager.c
src/pager.h
test/corrupt2.test
test/corrupt3.test
test/corrupt7.test
test/corruptE.test
test/pragma.test

index ad6e53acd509382cb6ac52b2d235dacd92cda6b1..2a439fcfa1acdb2df93737cab1eb3ceb61da452c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -269,9 +269,9 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
 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
@@ -314,8 +314,8 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
 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
@@ -518,19 +518,19 @@ F test/conflict2.test 0d3af4fb534fa1bd020c79960bb56e4d52655f09
 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
@@ -903,7 +903,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
 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
@@ -1364,7 +1364,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 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
index 71a9643813d9fdf4a54a522aa4352e1d2037bda4..ad09793ef00bd42b6a4f1e54668f189d1da10504 100644 (file)
@@ -1 +1 @@
-307195c8709d7fd2a642baa8011eb0c88cfdc0ac
\ No newline at end of file
+1c52212369692ca7c0b16a14e3a403cd4c5fbffc
\ No newline at end of file
index a8e5beb22741c2b28739ec5f2ed62424a21da645..76c016631bb5ddcfd953f242c4e2dd6e6026f9f2 100644 (file)
@@ -8923,23 +8923,19 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
 ** 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;
@@ -8948,8 +8944,9 @@ static int checkTreePage(
   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;
@@ -8963,8 +8960,7 @@ static int checkTreePage(
   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;
   }
@@ -8974,45 +8970,56 @@ static int checkTreePage(
   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);
@@ -9021,104 +9028,58 @@ static int checkTreePage(
       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
@@ -9145,10 +9106,10 @@ static int checkTreePage(
     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;
@@ -9163,14 +9124,12 @@ static int checkTreePage(
     */
     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;
@@ -9200,14 +9159,15 @@ char *sqlite3BtreeIntegrityCheck(
   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);
@@ -9217,21 +9177,26 @@ char *sqlite3BtreeIntegrityCheck(
   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
   */
@@ -9242,17 +9207,18 @@ char *sqlite3BtreeIntegrityCheck(
 
   /* 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
   */
@@ -9276,28 +9242,20 @@ char *sqlite3BtreeIntegrityCheck(
 #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 d74ea5557f719e26a7cc4307db4733ffcf46f63e..cbf6c998479e427d5247504c3047b5962e93bca4 100644 (file)
@@ -682,6 +682,7 @@ struct IntegrityCk {
   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 */
 };
 
 /*
index 982413ca8a698dfd2497e02467f8fe928649fb8c..060edb8d1dd7755b30cacdc5a090dbc03fcb66c7 100644 (file)
@@ -6387,12 +6387,14 @@ 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
index e07fa88fc5fe6cfcc7ff525a1dec6ef085e4c0a3..e3b57f435e1ea0af92ca6156487ba5b4c47f4b32 100644 (file)
@@ -173,7 +173,9 @@ int sqlite3PagerSharedLock(Pager *pPager);
 /* 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*);
index 805a6148f0b4d8e48d0eb99b7475dde1bd140d55..3cc2ed3d9a1064588f750da67b68acfaff636b63 100644 (file)
@@ -248,8 +248,8 @@ do_test corrupt2-5.1 {
   }
   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
index 436a466189a2bb281f08fdf603a39ec764f91c85..230626a447be10285c7c12eb5666b84bc7a5437b 100644 (file)
@@ -97,7 +97,7 @@ do_test corrupt3-1.10 {
     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
@@ -112,7 +112,7 @@ do_test corrupt3-1.12 {
     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 db92cf1de9f2b4b49bb7622340ef0d7056754f87..18deefb19b9de75b31ad1a4ed17c078991e6bd74 100644 (file)
@@ -69,37 +69,20 @@ integrity_check corrupt7-1.4
 # 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.
index 4d5b5db3d680134abb8731b88e14d43ca8fe1564..10555126d33b70f19205ed93406d7b45df4dfa0f 100644 (file)
@@ -82,9 +82,8 @@ do_test corruptE-2.1 {
   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
@@ -98,9 +97,8 @@ do_test corruptE-2.2 {
   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
@@ -115,7 +113,7 @@ do_test corruptE-2.3 {
   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 {
@@ -130,10 +128,9 @@ do_test corruptE-2.4 {
   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} \
@@ -171,7 +168,7 @@ foreach test $tests {
     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
 }
index 587a03c8a60119d74f4d4ecee7f1836460b84543..aa238cedf2299802d38db40446628065f5e56c42 100644 (file)
@@ -1749,14 +1749,14 @@ do_test 21.1 {
 } {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 }