/ Check-in [11e58f5b]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhanced detection of problems on the freelist and on overflow list in PRAGMA integrity_check.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 11e58f5b37d99848978007d834d187c262d904eb9d58924742e028d7cb324e64
User & Date: drh 2018-07-20 13:39:28
Context
2018-07-20
15:44
New checks in PRAGMA integrity_check to validate the autovacuum settings in the header. check-in: a4663f09 user: drh tags: trunk
13:39
Enhanced detection of problems on the freelist and on overflow list in PRAGMA integrity_check. check-in: 11e58f5b user: drh tags: trunk
2018-07-19
15:27
Avoid a branch in the commit logic that is unreachable when compiled without SQLITE_ENABLE_BATCH_ATOMIC_WRITE. check-in: 271b8980 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/btree.c.

  9333   9333   ** reference to the page, add an error message to pCheck->zErrMsg.
  9334   9334   ** Return 1 if there are 2 or more references to the page and 0 if
  9335   9335   ** if this is the first reference to the page.
  9336   9336   **
  9337   9337   ** Also check that the page number is in bounds.
  9338   9338   */
  9339   9339   static int checkRef(IntegrityCk *pCheck, Pgno iPage){
  9340         -  if( iPage==0 ) return 1;
  9341         -  if( iPage>pCheck->nPage ){
         9340  +  if( iPage>pCheck->nPage || iPage==0 ){
  9342   9341       checkAppendMsg(pCheck, "invalid page number %d", iPage);
  9343   9342       return 1;
  9344   9343     }
  9345   9344     if( getPageReferenced(pCheck, iPage) ){
  9346   9345       checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
  9347   9346       return 1;
  9348   9347     }
................................................................................
  9389   9388     IntegrityCk *pCheck,  /* Integrity checking context */
  9390   9389     int isFreeList,       /* True for a freelist.  False for overflow page list */
  9391   9390     int iPage,            /* Page number for first page in the list */
  9392   9391     int N                 /* Expected number of pages in the list */
  9393   9392   ){
  9394   9393     int i;
  9395   9394     int expected = N;
  9396         -  int iFirst = iPage;
  9397         -  while( N-- > 0 && pCheck->mxErr ){
         9395  +  int nErrAtStart = pCheck->nErr;
         9396  +  while( iPage!=0 && pCheck->mxErr ){
  9398   9397       DbPage *pOvflPage;
  9399   9398       unsigned char *pOvflData;
  9400         -    if( iPage<1 ){
  9401         -      checkAppendMsg(pCheck,
  9402         -         "%d of %d pages missing from overflow list starting at %d",
  9403         -          N+1, expected, iFirst);
  9404         -      break;
  9405         -    }
  9406   9399       if( checkRef(pCheck, iPage) ) break;
         9400  +    N--;
  9407   9401       if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
  9408   9402         checkAppendMsg(pCheck, "failed to get page %d", iPage);
  9409   9403         break;
  9410   9404       }
  9411   9405       pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
  9412   9406       if( isFreeList ){
  9413   9407         int n = get4byte(&pOvflData[4]);
................................................................................
  9443   9437           i = get4byte(pOvflData);
  9444   9438           checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage);
  9445   9439         }
  9446   9440       }
  9447   9441   #endif
  9448   9442       iPage = get4byte(pOvflData);
  9449   9443       sqlite3PagerUnref(pOvflPage);
  9450         -
  9451         -    if( isFreeList && N<(iPage!=0) ){
  9452         -      checkAppendMsg(pCheck, "free-page count in header is too small");
  9453   9444       }
         9445  +  if( N && nErrAtStart==pCheck->nErr ){
         9446  +    checkAppendMsg(pCheck,
         9447  +      "%s is %d but should be %d",
         9448  +      isFreeList ? "size" : "overflow list length",
         9449  +      expected-N, expected);
  9454   9450     }
  9455   9451   }
  9456   9452   #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
  9457   9453   
  9458   9454   /*
  9459   9455   ** An implementation of a min-heap.
  9460   9456   **

Changes to test/corrupt2.test.

   587    587     sqlite3 db test.db
   588    588     execsql { PRAGMA freelist_count }
   589    589   } {2}
   590    590   
   591    591   do_execsql_test 14.3 {
   592    592     PRAGMA integrity_check;
   593    593   } {{*** in database main ***
   594         -Main freelist: free-page count in header is too small}}
          594  +Main freelist: size is 3 but should be 2}}
   595    595   
   596    596   # Use 2 of the free pages on the free-list.
   597    597   #
   598    598   do_execsql_test 14.4 {
   599    599     INSERT INTO t1 VALUES(randomblob(2500));
   600    600     PRAGMA freelist_count;
   601    601   } {0}
   602    602   
   603    603   do_execsql_test 14.5 {
   604    604     PRAGMA integrity_check;
   605    605   } {{*** in database main ***
   606         -Page 3 is never used}}
          606  +Main freelist: size is 1 but should be 0}}
   607    607   
   608    608   
   609    609   finish_test
   610    610   
   611    611   finish_test

Changes to test/corrupt3.test.

    63     63   do_test corrupt3-1.5 {
    64     64     hexio_get_int [hexio_read test.db 2048 4]
    65     65   } 0      ;# First chained overflow is 0
    66     66   
    67     67   integrity_check corrupt3-1.6
    68     68   
    69     69   # Make the overflow chain loop back on itself.   See if the
    70         -# corruption is detected.   (Actually, the last pointer in
    71         -# an overflow chain is ignored, so this is not an error.)
           70  +# corruption is detected.
    72     71   #
    73     72   do_test corrupt3-1.7 {
    74     73     db close
    75     74     hexio_write test.db 2048 [hexio_render_int32 3]
    76     75     sqlite3 db test.db
    77     76     catchsql {
    78     77       SELECT x FROM t1
    79     78     }
    80     79   } [list 0 $bigstring]
    81         -integrity_check corrupt3-1.8
           80  +do_test corrupt3-1.8 {
           81  +  catchsql {
           82  +    PRAGMA integrity_check
           83  +  }
           84  +} {0 {{*** in database main ***
           85  +On tree page 2 cell 0: 2nd reference to page 3}}}
    82     86   
    83     87   # Change the pointer for the first page of the overflow
    84     88   # change to be a non-existant page.
    85     89   #
    86     90   do_test corrupt3-1.9 {
    87     91     db close
    88     92     hexio_write test.db 2044 [hexio_render_int32 4]
................................................................................
   107    111     }
   108    112   } [list 1 {database disk image is malformed}]
   109    113   do_test corrupt3-1.12 {
   110    114     catchsql {
   111    115       PRAGMA integrity_check
   112    116     }
   113    117   } {0 {{*** in database main ***
   114         -On tree page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0
          118  +On tree page 2 cell 0: overflow list length is 0 but should be 1
   115    119   Page 3 is never used}}}
   116    120   
   117    121   finish_test