Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch integrity-check-refactor Excluding Merge-Ins
This is equivalent to a diff from 307195c8 to 1c522123
2015-07-01
| ||
17:53 | Simplification of PRAGMA integrity_check logic. Make sure that the depth of the right-most subtree is correct. Size reduction and performance increase, with no change in output. (check-in: 550705fc user: drh tags: trunk) | |
17:13 | Rework the PRAGMA integrity_check logic. Simplify the checkTreePage() routine and clean up the error messages generated. (Closed-Leaf check-in: 1c522123 user: drh tags: integrity-check-refactor) | |
04:08 | Fix some harmless compiler warnings. (check-in: 307195c8 user: drh tags: trunk) | |
01:31 | Change integrity_check to analyze the cells of a page in reverse order, as this will tend to insert the cells into the analysis heap in increasing order by address, which is the most efficient way to load a min-heap. (check-in: 59ad912c user: drh tags: trunk) | |
Changes to src/btree.c.
︙ | ︙ | |||
8919 8920 8921 8922 8923 8924 8925 | ** Do various sanity checks on a single page of a tree. Return ** the tree depth. Root pages return 0. Parents of root pages ** return 1, and so forth. ** ** These checks are done: ** ** 1. Make sure that cells and freeblocks do not overlap | | | < < | | | < < | | | | | > | < | < < | < > > > > > > > > > > > > > > > > > < < < < < < < < | < < | < < < | | > > > > | > | > > > | > | > > | < | | | < | | | | | | < < | < | | > > > | < < | | | | < > > > | < < < < < < < | < < | < < | < < < < | < < < < < < | < | < < < < < < | < | < < < < < < < < < < < | < < < < | < | 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 | ** Do various sanity checks on a single page of a tree. Return ** the tree depth. Root pages return 0. Parents of root pages ** return 1, and so forth. ** ** These checks are done: ** ** 1. Make sure that cells and freeblocks do not overlap ** 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 minKey, /* All integer primary keys must be >= this value */ i64 maxKey /* All integer primary keys must be <= this value */ ){ 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; 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 */ pBt = pCheck->pBt; usableSize = pBt->usableSize; 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, "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, "corrupt header or freelist"); depth = -1; goto end_of_check; } /* 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++){ CellInfo info; pCheck->v2 = i; 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); } #endif checkList(pCheck, 0, pgnoOvfl, nPage); } /* 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.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(&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 */ if( doCoverageCheck ){ heap = pCheck->heap; heap[0] = 0; btreeHeapInsert(heap, contentOffset-1); for(i=nCell-1; i>=0; i--){ u32 pc = get2byteAligned(&data[cellStart+i*2]); u32 size = pPage->xCellSize(pPage, &data[pc]); 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]); while( i>0 ){ int size, j; |
︙ | ︙ | |||
9141 9142 9143 9144 9145 9146 9147 9148 9149 | assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */ i = j; } cnt = 0; assert( heap[0]>0 ); assert( (heap[1]>>16)==0 ); btreeHeapPull(heap,&prev); while( btreeHeapPull(heap,&x) ){ if( (prev&0xffff)+1>(x>>16) ){ | > | < < | < < > | 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 | assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */ i = j; } 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", x>>16); break; }else{ cnt += (x>>16) - (prev&0xffff) - 1; prev = x; } } cnt += usableSize - (prev&0xffff) - 1; /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments ** is stored in the fifth field of the b-tree page header. ** 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 should be %d", data[hdr+7], cnt); } } end_of_check: releasePage(pPage); pCheck->zPfx = saved_zPfx; pCheck->v1 = saved_v1; pCheck->v2 = saved_v2; return depth+1; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ |
︙ | ︙ | |||
9196 9197 9198 9199 9200 9201 9202 | Btree *p, /* The btree to be checked */ int *aRoot, /* An array of root pages numbers for individual trees */ 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; | | > | > | > < < > | > > | < > > > > < > > < | < > | 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 | Btree *p, /* The btree to be checked */ int *aRoot, /* An array of root pages numbers for individual trees */ 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; 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 ); 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; sCheck.aPgRef = 0; sCheck.heap = 0; sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); if( sCheck.nPage==0 ){ goto integrity_ck_cleanup; } sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); if( !sCheck.aPgRef ){ 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); /* Check the integrity of the freelist */ sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; /* 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 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 if( getPageReferenced(&sCheck, i)==0 ){ checkAppendMsg(&sCheck, "Page %d is never used", i); |
︙ | ︙ | |||
9272 9273 9274 9275 9276 9277 9278 | if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); } #endif } | < < < < < < < < < < < > | | < > > > | 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 | if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); } #endif } /* Clean up and report errors. */ integrity_ck_cleanup: sqlite3PageFree(sCheck.heap); sqlite3_free(sCheck.aPgRef); if( sCheck.mallocFailed ){ sqlite3StrAccumReset(&sCheck.errMsg); 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 */ /* ** Return the full pathname of the underlying database file. Return ** an empty string if the database is in-memory or a TEMP database. |
︙ | ︙ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
678 679 680 681 682 683 684 685 686 687 688 689 690 691 | Pgno nPage; /* Number of pages in the database */ int mxErr; /* Stop accumulating errors when this reaches zero */ 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 */ }; /* ** Routines to read or write a two- and four-byte big-endian integer values. */ #define get2byte(x) ((x)[0]<<8 | (x)[1]) #define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v)) | > | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | Pgno nPage; /* Number of pages in the database */ int mxErr; /* Stop accumulating errors when this reaches zero */ 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. */ #define get2byte(x) ((x)[0]<<8 | (x)[1]) #define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v)) |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 | ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. */ u8 sqlite3PagerIsreadonly(Pager *pPager){ return pPager->readOnly; } /* ** Return the number of references to the pager. */ int sqlite3PagerRefcount(Pager *pPager){ return sqlite3PcacheRefCount(pPager->pPCache); } /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. */ int sqlite3PagerMemUsed(Pager *pPager){ int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) | > > | 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 | ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. */ 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. */ int sqlite3PagerMemUsed(Pager *pPager){ int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
169 170 171 172 173 174 175 | #ifdef SQLITE_ENABLE_ZIPVFS int sqlite3PagerWalFramesize(Pager *pPager); #endif /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); u32 sqlite3PagerDataVersion(Pager*); | > | > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | #ifdef SQLITE_ENABLE_ZIPVFS int sqlite3PagerWalFramesize(Pager *pPager); #endif /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); u32 sqlite3PagerDataVersion(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*); int sqlite3PagerNosync(Pager*); void *sqlite3PagerTempSpace(Pager*); |
︙ | ︙ |
Changes to test/corrupt2.test.
︙ | ︙ | |||
244 245 246 247 248 249 250 | db2 eval $::presql db2 eval {SELECT rowid FROM t1} { set result [db2 eval {pragma integrity_check}] break } set result } {{*** in database main *** | | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | db2 eval $::presql db2 eval {SELECT rowid FROM t1} { set result [db2 eval {pragma integrity_check}] break } set result } {{*** in database main *** 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} { set A(-corrupt) {} set A(-sqlprep) {} |
︙ | ︙ |
Changes to test/corrupt3.test.
︙ | ︙ | |||
93 94 95 96 97 98 99 | } } [list 0 0123456789] do_test corrupt3-1.10 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | } } [list 0 0123456789] do_test corrupt3-1.10 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** 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 catchsql { SELECT substr(x,1,10) FROM t1 } } [list 1 {database disk image is malformed}] do_test corrupt3-1.12 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** Page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0 Page 3 is never used}}} finish_test |
Changes to test/corrupt7.test.
︙ | ︙ | |||
65 66 67 68 69 70 71 | # Deliberately corrupt some of the cell offsets in the btree page # 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. # | < | | | | | | < < < < < < < < < < < < < < < | | | | | | | | < | 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 | # Deliberately corrupt some of the cell offsets in the btree page # 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. # 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 { # execsql { # DROP TABLE t1; |
︙ | ︙ |
Changes to test/corruptE.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 | hexio_write test.db 2041 [format %02x 0x2e] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] | | < | | < | | | < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | hexio_write test.db 2041 [format %02x 0x2e] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] regexp {rowid \d+ out of range \d+\.\.\d+} $ans] } {1} do_test corruptE-2.2 { db close forcecopy test.bu test.db # insert corrupt byte(s) hexio_write test.db 2047 [format %02x 0x84] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] regexp {rowid \d+ out of range \d+\.\.\d+} $ans] } {1} do_test corruptE-2.3 { db close forcecopy test.bu test.db # insert corrupt byte(s) hexio_write test.db 7420 [format %02x 0xa8] hexio_write test.db 10459 [format %02x 0x8d] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] regexp {rowid \d+ out of range \d+\.\.\d+} $ans] } {1} do_test corruptE-2.4 { db close forcecopy test.bu test.db # insert corrupt byte(s) hexio_write test.db 10233 [format %02x 0xd0] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] regexp {rowid \d+ out of range \d+\.\.\d+} $ans] } {1} set tests [list {10233 0xd0} \ {941 0x42} \ {1028 0x53} \ {2041 0xd0} \ {2042 0x1f} \ {2047 0xaa} \ |
︙ | ︙ | |||
167 168 169 170 171 172 173 | hexio_write test.db [lindex $test 0] [format %02x [lindex $test 1]] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 | hexio_write test.db [lindex $test 0] [format %02x [lindex $test 1]] sqlite3 db test.db set res [ catchsql {PRAGMA integrity_check} ] set ans [lindex $res 1] list [regexp {out of range|database disk image is malformed} $ans] } {1} incr tc 1 } finish_test |
Changes to test/pragma.test.
︙ | ︙ | |||
1745 1746 1747 1748 1749 1750 1751 | } db close forcecopy test.db testerr.db hexio_write testerr.db 15000 [string repeat 55 100] } {100} set mainerr {*** in database main *** | | | | | | 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 | } db close forcecopy test.db testerr.db hexio_write testerr.db 15000 [string repeat 55 100] } {100} set mainerr {*** in database main *** Page 15: multiple uses for byte 672} set auxerr {*** in database aux *** Page 15: Multiple uses for byte 672} set mainerr {/{\*\*\* in database main \*\*\* Page 15: multiple uses for byte 672}.*/} set auxerr {/{\*\*\* in database aux \*\*\* Page 15: multiple uses for byte 672}.*/} do_test 22.2 { catch { db close } sqlite3 db testerr.db execsql { PRAGMA integrity_check } } $mainerr |
︙ | ︙ |