SQLite

Check-in [11e58f5b37]
Login

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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 11e58f5b37d99848978007d834d187c262d904eb9d58924742e028d7cb324e64
User & Date: drh 2018-07-20 13:39:28.100
Context
2018-07-20
15:44
New checks in PRAGMA integrity_check to validate the autovacuum settings in the header. (check-in: a4663f09c9 user: drh tags: trunk)
13:39
Enhanced detection of problems on the freelist and on overflow list in PRAGMA integrity_check. (check-in: 11e58f5b37 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: 271b8980c3 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/btree.c.
9333
9334
9335
9336
9337
9338
9339
9340
9341
9342
9343
9344
9345
9346
9347
9348
** reference to the page, add an error message to pCheck->zErrMsg.
** Return 1 if there are 2 or more references to the page and 0 if
** if this is the first reference to the page.
**
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
  if( iPage==0 ) return 1;
  if( iPage>pCheck->nPage ){
    checkAppendMsg(pCheck, "invalid page number %d", iPage);
    return 1;
  }
  if( getPageReferenced(pCheck, iPage) ){
    checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
    return 1;
  }







<
|







9333
9334
9335
9336
9337
9338
9339

9340
9341
9342
9343
9344
9345
9346
9347
** reference to the page, add an error message to pCheck->zErrMsg.
** Return 1 if there are 2 or more references to the page and 0 if
** if this is the first reference to the page.
**
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){

  if( iPage>pCheck->nPage || iPage==0 ){
    checkAppendMsg(pCheck, "invalid page number %d", iPage);
    return 1;
  }
  if( getPageReferenced(pCheck, iPage) ){
    checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
    return 1;
  }
9389
9390
9391
9392
9393
9394
9395
9396
9397
9398
9399
9400
9401
9402
9403
9404
9405
9406

9407
9408
9409
9410
9411
9412
9413
  IntegrityCk *pCheck,  /* Integrity checking context */
  int isFreeList,       /* True for a freelist.  False for overflow page list */
  int iPage,            /* Page number for first page in the list */
  int N                 /* Expected number of pages in the list */
){
  int i;
  int expected = N;
  int iFirst = iPage;
  while( N-- > 0 && pCheck->mxErr ){
    DbPage *pOvflPage;
    unsigned char *pOvflData;
    if( iPage<1 ){
      checkAppendMsg(pCheck,
         "%d of %d pages missing from overflow list starting at %d",
          N+1, expected, iFirst);
      break;
    }
    if( checkRef(pCheck, iPage) ) break;

    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
      checkAppendMsg(pCheck, "failed to get page %d", iPage);
      break;
    }
    pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
    if( isFreeList ){
      int n = get4byte(&pOvflData[4]);







|
|


<
<
<
<
<
<

>







9388
9389
9390
9391
9392
9393
9394
9395
9396
9397
9398






9399
9400
9401
9402
9403
9404
9405
9406
9407
  IntegrityCk *pCheck,  /* Integrity checking context */
  int isFreeList,       /* True for a freelist.  False for overflow page list */
  int iPage,            /* Page number for first page in the list */
  int N                 /* Expected number of pages in the list */
){
  int i;
  int expected = N;
  int nErrAtStart = pCheck->nErr;
  while( iPage!=0 && pCheck->mxErr ){
    DbPage *pOvflPage;
    unsigned char *pOvflData;






    if( checkRef(pCheck, iPage) ) break;
    N--;
    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
      checkAppendMsg(pCheck, "failed to get page %d", iPage);
      break;
    }
    pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
    if( isFreeList ){
      int n = get4byte(&pOvflData[4]);
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453



9454
9455
9456
9457
9458
9459
9460
        i = get4byte(pOvflData);
        checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage);
      }
    }
#endif
    iPage = get4byte(pOvflData);
    sqlite3PagerUnref(pOvflPage);

    if( isFreeList && N<(iPage!=0) ){
      checkAppendMsg(pCheck, "free-page count in header is too small");
    }



  }
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */

/*
** An implementation of a min-heap.
**







|
|
|
<
>
>
>







9437
9438
9439
9440
9441
9442
9443
9444
9445
9446

9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
        i = get4byte(pOvflData);
        checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage);
      }
    }
#endif
    iPage = get4byte(pOvflData);
    sqlite3PagerUnref(pOvflPage);
  }
  if( N && nErrAtStart==pCheck->nErr ){
    checkAppendMsg(pCheck,

      "%s is %d but should be %d",
      isFreeList ? "size" : "overflow list length",
      expected-N, expected);
  }
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */

/*
** An implementation of a min-heap.
**
Changes to test/corrupt2.test.
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  sqlite3 db test.db
  execsql { PRAGMA freelist_count }
} {2}

do_execsql_test 14.3 {
  PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: free-page count in header is too small}}

# Use 2 of the free pages on the free-list.
#
do_execsql_test 14.4 {
  INSERT INTO t1 VALUES(randomblob(2500));
  PRAGMA freelist_count;
} {0}

do_execsql_test 14.5 {
  PRAGMA integrity_check;
} {{*** in database main ***
Page 3 is never used}}


finish_test

finish_test







|











|





587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  sqlite3 db test.db
  execsql { PRAGMA freelist_count }
} {2}

do_execsql_test 14.3 {
  PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: size is 3 but should be 2}}

# Use 2 of the free pages on the free-list.
#
do_execsql_test 14.4 {
  INSERT INTO t1 VALUES(randomblob(2500));
  PRAGMA freelist_count;
} {0}

do_execsql_test 14.5 {
  PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: size is 1 but should be 0}}


finish_test

finish_test
Changes to test/corrupt3.test.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81



82
83
84
85
86
87
88
do_test corrupt3-1.5 {
  hexio_get_int [hexio_read test.db 2048 4]
} 0      ;# First chained overflow is 0

integrity_check corrupt3-1.6

# Make the overflow chain loop back on itself.   See if the
# corruption is detected.   (Actually, the last pointer in
# an overflow chain is ignored, so this is not an error.)
#
do_test corrupt3-1.7 {
  db close
  hexio_write test.db 2048 [hexio_render_int32 3]
  sqlite3 db test.db
  catchsql {
    SELECT x FROM t1
  }
} [list 0 $bigstring]


integrity_check corrupt3-1.8




# Change the pointer for the first page of the overflow
# change to be a non-existant page.
#
do_test corrupt3-1.9 {
  db close
  hexio_write test.db 2044 [hexio_render_int32 4]







|
<









>
>
|
>
>
>







63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
do_test corrupt3-1.5 {
  hexio_get_int [hexio_read test.db 2048 4]
} 0      ;# First chained overflow is 0

integrity_check corrupt3-1.6

# Make the overflow chain loop back on itself.   See if the
# corruption is detected.

#
do_test corrupt3-1.7 {
  db close
  hexio_write test.db 2048 [hexio_render_int32 3]
  sqlite3 db test.db
  catchsql {
    SELECT x FROM t1
  }
} [list 0 $bigstring]
do_test corrupt3-1.8 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: 2nd reference to page 3}}}

# Change the pointer for the first page of the overflow
# change to be a non-existant page.
#
do_test corrupt3-1.9 {
  db close
  hexio_write test.db 2044 [hexio_render_int32 4]
107
108
109
110
111
112
113
114
115
116
117
  }
} [list 1 {database disk image is malformed}]
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 3 is never used}}}

finish_test







|



111
112
113
114
115
116
117
118
119
120
121
  }
} [list 1 {database disk image is malformed}]
do_test corrupt3-1.12 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: overflow list length is 0 but should be 1
Page 3 is never used}}}

finish_test