1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Limit the number of errors returned by PRAGMA integrity_check to 100 by

default.  Specify an alternative limit using an argument to the pragma.
Ticket #2176. (CVS 3609)

FossilOrigin-Name: d564a039f27be2bb2c3973e79dc99b25869139da
This commit is contained in:
drh
2007-01-27 02:24:54 +00:00
parent 4e78be693c
commit 1dcdbc0639
9 changed files with 241 additions and 60 deletions

View File

@@ -1,5 +1,5 @@
C Make\ssure\sthe\svdbeInt.h\sfile\sis\snot\s#included\smultiple\stimes.\s\sTicket\s#2194.\s(CVS\s3608) C Limit\sthe\snumber\sof\serrors\sreturned\sby\sPRAGMA\sintegrity_check\sto\s100\sby\ndefault.\s\sSpecify\san\salternative\slimit\susing\san\sargument\sto\sthe\spragma.\nTicket\s#2176.\s(CVS\s3609)
D 2007-01-26T21:08:05 D 2007-01-27T02:24:55
F Makefile.in 7fa74bf4359aa899da5586e394d17735f221315f F Makefile.in 7fa74bf4359aa899da5586e394d17735f221315f
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -57,8 +57,8 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
F src/attach.c b11eb4d5d3fb99a10a626956bccc7215f6b68b16 F src/attach.c b11eb4d5d3fb99a10a626956bccc7215f6b68b16
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
F src/btree.c 6837dcc4da8677e695a49fcc4505418ff1e0fc54 F src/btree.c 51aef6a4b18df165b83b332befd1447c011b4389
F src/btree.h 061c50e37de7f50b58528e352d400cf33ead7418 F src/btree.h 066444ee25bd6e6accb997bfd2cf5ace14dbcd00
F src/build.c 02aedde724dc73295d6e9b8dc29afb5dd38de507 F src/build.c 02aedde724dc73295d6e9b8dc29afb5dd38de507
F src/callback.c fd9bb39f7ff6b52bad8365617abc61c720640429 F src/callback.c fd9bb39f7ff6b52bad8365617abc61c720640429
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
@@ -88,7 +88,7 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c d6ad66eb119602cb2e6a097f8f635372ba677d23 F src/pager.c d6ad66eb119602cb2e6a097f8f635372ba677d23
F src/pager.h 2e6d42f4ae004ae748a037b8468112b851c447a7 F src/pager.h 2e6d42f4ae004ae748a037b8468112b851c447a7
F src/parse.y 2f571c5f6219428d7fb08737db3d113742b1cceb F src/parse.y 2f571c5f6219428d7fb08737db3d113742b1cceb
F src/pragma.c fd4df6cf0857dd78a7cb5be5f9805419b53ae7a0 F src/pragma.c 5091300911670ddaa552bfa12c45cbca1bb7e7d6
F src/prepare.c 484389c6811415b8f23d259ac9c029613e1c72c3 F src/prepare.c 484389c6811415b8f23d259ac9c029613e1c72c3
F src/printf.c aade23a789d7cc88b397ec0d33a0a01a33a7a9c1 F src/printf.c aade23a789d7cc88b397ec0d33a0a01a33a7a9c1
F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88 F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
@@ -102,7 +102,7 @@ F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
F src/tclsqlite.c d344c7f394d6f055ce3abfe0049b0480c5e34e56 F src/tclsqlite.c d344c7f394d6f055ce3abfe0049b0480c5e34e56
F src/test1.c 053f5224697efaefff1f4c647fd90fdea9346cc5 F src/test1.c 053f5224697efaefff1f4c647fd90fdea9346cc5
F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b
F src/test3.c fa0e85ddd1784f2dda5861a2cb4e7d27d1c932c1 F src/test3.c 875126eab6749f9d9e2b60b6ee6a65825b3d1fed
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
@@ -121,7 +121,7 @@ F src/update.c 951f95ef044cf6d28557c48dc35cb0711a0b9129
F src/utf.c 67ecb1032bc0b42c105e88d65ef9d9f626eb0e1f F src/utf.c 67ecb1032bc0b42c105e88d65ef9d9f626eb0e1f
F src/util.c 91d4cb189476906639ae611927d939691d1365f6 F src/util.c 91d4cb189476906639ae611927d939691d1365f6
F src/vacuum.c b4569b08aaa5afb141af3f76d0315745db4e9e4b F src/vacuum.c b4569b08aaa5afb141af3f76d0315745db4e9e4b
F src/vdbe.c 4d54659b7dbb7a61570d7136a34fbde12b61c509 F src/vdbe.c 31fe3e1e3cc00f5324a5fbde89d0ab603ad246b5
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
F src/vdbeInt.h 13ba07121cf534d5b80130d2f5eb0a4937a36bba F src/vdbeInt.h 13ba07121cf534d5b80130d2f5eb0a4937a36bba
F src/vdbeapi.c 2d1e6843af8705a1172e54a418d2a3d5febd1dd7 F src/vdbeapi.c 2d1e6843af8705a1172e54a418d2a3d5febd1dd7
@@ -269,7 +269,7 @@ F test/pager.test 6ee95e90ee8295e376e39a6c6566ef6df993601a
F test/pager2.test 49c0f57c7da0b060f0486b85fdd074025caa694e F test/pager2.test 49c0f57c7da0b060f0486b85fdd074025caa694e
F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4 F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4
F test/pagesize.test 05c74ea49f790734ec1e9ab765d9bf1cce79b8f2 F test/pagesize.test 05c74ea49f790734ec1e9ab765d9bf1cce79b8f2
F test/pragma.test d20fe81e31c6be9cb3182f1792cf5e5a6d4e97f6 F test/pragma.test b523286a32bfab309dd42d21ccdc9f5e51e3b2e9
F test/printf.test cdd8e20dd901382a385afcbaa777b9377815c2ad F test/printf.test cdd8e20dd901382a385afcbaa777b9377815c2ad
F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
F test/quick.test 6bc0f7c7b905f7de5fe4d3f13239ced3e4e66fe7 F test/quick.test 6bc0f7c7b905f7de5fe4d3f13239ced3e4e66fe7
@@ -416,7 +416,7 @@ F www/opcode.tcl 5bd68059416b223515a680d410a9f7cb6736485f
F www/optimizer.tcl d6812a10269bd0d7c488987aac0ad5036cace9dc F www/optimizer.tcl d6812a10269bd0d7c488987aac0ad5036cace9dc
F www/optimizing.tcl f0b2538988d1bbad16cbfe63ec6e8f48c9eb04e5 F www/optimizing.tcl f0b2538988d1bbad16cbfe63ec6e8f48c9eb04e5
F www/optoverview.tcl 815df406a38c9f69b27d37e8f7ede004c6d9f19e F www/optoverview.tcl 815df406a38c9f69b27d37e8f7ede004c6d9f19e
F www/pragma.tcl c3d103838ae1c66729f8286e276735618af2a88a F www/pragma.tcl 74544f5564bbb6d9809cf35b4c05ebdfee469165
F www/quickstart.tcl 8708a4ca83fbf55c66af1782992626f20c3df095 F www/quickstart.tcl 8708a4ca83fbf55c66af1782992626f20c3df095
F www/shared.gif 265bae80c5b311c5a86e47662821076ffaf5c6ea F www/shared.gif 265bae80c5b311c5a86e47662821076ffaf5c6ea
F www/sharedcache.tcl 3ebec81110e606af6fd65a3c4c19562cb173b29c F www/sharedcache.tcl 3ebec81110e606af6fd65a3c4c19562cb173b29c
@@ -428,7 +428,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P 02990fabd1c68fb51afc91a1b720802ef86bfec6 P 93edd3b0565d08383b3034c57f221073fde6de4b
R f3d4c318f331af035a24f47aae427d9a R 557df95c56e9de3c85559166fb533aa4
U drh U drh
Z b826f35654120ae9d4f4a22ffb14f63f Z 0cf02b2f60ab84b0a3c77c11c5fcb2c4

View File

@@ -1 +1 @@
93edd3b0565d08383b3034c57f221073fde6de4b d564a039f27be2bb2c3973e79dc99b25869139da

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btree.c,v 1.333 2007/01/05 02:00:47 drh Exp $ ** $Id: btree.c,v 1.334 2007/01/27 02:24:55 drh Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@@ -5958,10 +5958,12 @@ Pager *sqlite3BtreePager(Btree *p){
typedef struct IntegrityCk IntegrityCk; typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk { struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */ BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */ int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */ int *anRef; /* Number of times each page is referenced */
char *zErrMsg; /* An error message. NULL of no errors seen. */ int mxErr; /* Stop accumulating errors when this reaches zero */
char *zErrMsg; /* An error message. NULL if no errors seen. */
int nErr; /* Number of messages written to zErrMsg so far */
}; };
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
@@ -5976,6 +5978,9 @@ static void checkAppendMsg(
){ ){
va_list ap; va_list ap;
char *zMsg2; char *zMsg2;
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
va_start(ap, zFormat); va_start(ap, zFormat);
zMsg2 = sqlite3VMPrintf(zFormat, ap); zMsg2 = sqlite3VMPrintf(zFormat, ap);
va_end(ap); va_end(ap);
@@ -6059,7 +6064,7 @@ static void checkList(
int i; int i;
int expected = N; int expected = N;
int iFirst = iPage; int iFirst = iPage;
while( N-- > 0 ){ while( N-- > 0 && pCheck->mxErr ){
unsigned char *pOvfl; unsigned char *pOvfl;
if( iPage<1 ){ if( iPage<1 ){
checkAppendMsg(pCheck, zContext, checkAppendMsg(pCheck, zContext,
@@ -6171,7 +6176,7 @@ static int checkTreePage(
/* Check out all the cells. /* Check out all the cells.
*/ */
depth = 0; depth = 0;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
u8 *pCell; u8 *pCell;
int sz; int sz;
CellInfo info; CellInfo info;
@@ -6286,7 +6291,13 @@ static int checkTreePage(
** and a pointer to that error message is returned. The calling function ** and a pointer to that error message is returned. The calling function
** is responsible for freeing the error message when it is done. ** is responsible for freeing the error message when it is done.
*/ */
char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){ char *sqlite3BtreeIntegrityCheck(
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 */
){
int i; int i;
int nRef; int nRef;
IntegrityCk sCheck; IntegrityCk sCheck;
@@ -6299,6 +6310,9 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
sCheck.pBt = pBt; sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager; sCheck.pPager = pBt->pPager;
sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager); sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
*pnErr = 0;
if( sCheck.nPage==0 ){ if( sCheck.nPage==0 ){
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
return 0; return 0;
@@ -6306,6 +6320,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
if( !sCheck.anRef ){ if( !sCheck.anRef ){
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
*pnErr = 1;
return sqlite3MPrintf("Unable to malloc %d bytes", return sqlite3MPrintf("Unable to malloc %d bytes",
(sCheck.nPage+1)*sizeof(sCheck.anRef[0])); (sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
} }
@@ -6323,7 +6338,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Check all the tables. /* Check all the tables.
*/ */
for(i=0; i<nRoot; i++){ for(i=0; i<nRoot && sCheck.mxErr; i++){
if( aRoot[i]==0 ) continue; if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){ if( pBt->autoVacuum && aRoot[i]>1 ){
@@ -6335,7 +6350,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure every page in the file is referenced /* Make sure every page in the file is referenced
*/ */
for(i=1; i<=sCheck.nPage; i++){ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM #ifdef SQLITE_OMIT_AUTOVACUUM
if( sCheck.anRef[i]==0 ){ if( sCheck.anRef[i]==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i); checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
@@ -6368,6 +6383,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Clean up and report errors. /* Clean up and report errors.
*/ */
sqliteFree(sCheck.anRef); sqliteFree(sCheck.anRef);
*pnErr = sCheck.nErr;
return sCheck.zErrMsg; return sCheck.zErrMsg;
} }
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */

View File

@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description ** subsystem. See comments in the source code for a detailed description
** of what each interface routine does. ** of what each interface routine does.
** **
** @(#) $Id: btree.h,v 1.71 2006/06/27 16:34:57 danielk1977 Exp $ ** @(#) $Id: btree.h,v 1.72 2007/01/27 02:24:55 drh Exp $
*/ */
#ifndef _BTREE_H_ #ifndef _BTREE_H_
#define _BTREE_H_ #define _BTREE_H_
@@ -131,7 +131,7 @@ const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*); struct Pager *sqlite3BtreePager(Btree*);

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the PRAGMA command. ** This file contains code used to implement the PRAGMA command.
** **
** $Id: pragma.c,v 1.126 2007/01/04 22:13:42 drh Exp $ ** $Id: pragma.c,v 1.127 2007/01/27 02:24:56 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -640,9 +640,13 @@ void sqlite3Pragma(
} }
}else }else
#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){ if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr; int i, j, addr, mxErr;
/* Code that appears at the end of the integrity check. If no error /* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the ** messages have been generated, output OK. Otherwise output the
@@ -660,7 +664,16 @@ void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
mxErr = atoi(zRight);
if( mxErr<=0 ){
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
}
}
sqlite3VdbeAddOp(v, OP_MemInt, mxErr, 0);
/* Do an integrity check on each database file */ /* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
@@ -671,6 +684,9 @@ void sqlite3Pragma(
if( OMIT_TEMPDB && i==1 ) continue; if( OMIT_TEMPDB && i==1 ) continue;
sqlite3CodeVerifySchema(pParse, i); sqlite3CodeVerifySchema(pParse, i);
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
/* Do an integrity check of the B-Tree /* Do an integrity check of the B-Tree
*/ */
@@ -685,28 +701,28 @@ void sqlite3Pragma(
cnt++; cnt++;
} }
} }
assert( cnt>0 ); if( cnt==0 ) continue;
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i); sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
sqlite3VdbeAddOp(v, OP_Dup, 0, 1); addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName), sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
P3_DYNAMIC); P3_DYNAMIC);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Concat, 0, 1); sqlite3VdbeAddOp(v, OP_Concat, 0, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly. /* Make sure all the indices are constructed correctly.
*/ */
sqlite3CodeVerifySchema(pParse, i);
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x); Table *pTab = sqliteHashData(x);
Index *pIdx; Index *pIdx;
int loopTop; int loopTop;
if( pTab->pIndex==0 ) continue; if( pTab->pIndex==0 ) continue;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1); sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
@@ -714,7 +730,7 @@ void sqlite3Pragma(
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2; int jmp2;
static const VdbeOpList idxErr[] = { static const VdbeOpList idxErr[] = {
{ OP_MemIncr, 1, 0, 0}, { OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "rowid "}, { OP_String8, 0, 0, "rowid "},
{ OP_Rowid, 1, 0, 0}, { OP_Rowid, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "}, { OP_String8, 0, 0, " missing from index "},
@@ -739,13 +755,16 @@ void sqlite3Pragma(
{ OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0}, { OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 6 */ { OP_Eq, 0, 0, 0}, /* 6 */
{ OP_MemIncr, 1, 0, 0}, { OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "}, { OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 9 */ { OP_String8, 0, 0, 0}, /* 9 */
{ OP_Concat, 0, 0, 0}, { OP_Concat, 0, 0, 0},
{ OP_Callback, 1, 0, 0}, { OP_Callback, 1, 0, 0},
}; };
if( pIdx->tnum==0 ) continue; if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx); addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+1, j+2); sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+1, addr+4); sqlite3VdbeChangeP2(v, addr+1, addr+4);
@@ -757,6 +776,7 @@ void sqlite3Pragma(
} }
} }
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeChangeP1(v, addr+1, mxErr);
sqlite3VdbeJumpHere(v, addr+2); sqlite3VdbeJumpHere(v, addr+2);
}else }else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** testing of the SQLite library.
** **
** $Id: test3.c,v 1.68 2007/01/03 23:37:28 drh Exp $ ** $Id: test3.c,v 1.69 2007/01/27 02:24:56 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "pager.h" #include "pager.h"
@@ -567,6 +567,7 @@ static int btree_integrity_check(
int nRoot; int nRoot;
int *aRoot; int *aRoot;
int i; int i;
int nErr;
char *zResult; char *zResult;
if( argc<3 ){ if( argc<3 ){
@@ -581,7 +582,7 @@ static int btree_integrity_check(
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
} }
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot); zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
#else #else
zResult = 0; zResult = 0;
#endif #endif

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.586 2007/01/12 23:43:43 drh Exp $ ** $Id: vdbe.c,v 1.587 2007/01/27 02:24:56 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -4120,11 +4120,16 @@ case OP_DropTrigger: { /* no-push */
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
/* Opcode: IntegrityCk * P2 * /* Opcode: IntegrityCk P1 P2 *
** **
** Do an analysis of the currently open database. Push onto the ** Do an analysis of the currently open database. Push onto the
** stack the text of an error message describing any problems. ** stack the text of an error message describing any problems.
** If there are no errors, push a "ok" onto the stack. ** If no problems are found, push a NULL onto the stack.
**
** P1 is the address of a memory cell that contains the maximum
** number of allowed errors. At most mem[P1] errors will be reported.
** In other words, the analysis stops as soon as mem[P1] errors are
** seen. Mem[P1] is updated with the number of errors remaining.
** **
** The root page numbers of all tables in the database are integer ** The root page numbers of all tables in the database are integer
** values on the stack. This opcode pulls as many integers as it ** values on the stack. This opcode pulls as many integers as it
@@ -4133,13 +4138,15 @@ case OP_DropTrigger: { /* no-push */
** If P2 is not zero, the check is done on the auxiliary database ** If P2 is not zero, the check is done on the auxiliary database
** file, not the main database file. ** file, not the main database file.
** **
** This opcode is used for testing purposes only. ** This opcode is used to implement the integrity_check pragma.
*/ */
case OP_IntegrityCk: { case OP_IntegrityCk: {
int nRoot; int nRoot;
int *aRoot; int *aRoot;
int j; int j;
int nErr;
char *z; char *z;
Mem *pnErr;
for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){ for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
if( (pTos[-nRoot].flags & MEM_Int)==0 ) break; if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
@@ -4147,6 +4154,10 @@ case OP_IntegrityCk: {
assert( nRoot>0 ); assert( nRoot>0 );
aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) ); aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
if( aRoot==0 ) goto no_mem; if( aRoot==0 ) goto no_mem;
j = pOp->p1;
assert( j>=0 && j<p->nMem );
pnErr = &p->aMem[j];
assert( (pnErr->flags & MEM_Int)!=0 );
for(j=0; j<nRoot; j++){ for(j=0; j<nRoot; j++){
Mem *pMem = &pTos[-j]; Mem *pMem = &pTos[-j];
aRoot[j] = pMem->i; aRoot[j] = pMem->i;
@@ -4154,12 +4165,12 @@ case OP_IntegrityCk: {
aRoot[j] = 0; aRoot[j] = 0;
popStack(&pTos, nRoot); popStack(&pTos, nRoot);
pTos++; pTos++;
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot); z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
if( z==0 || z[0]==0 ){ pnErr->i, &nErr);
if( z ) sqliteFree(z); pnErr->i -= nErr;
pTos->z = "ok"; if( nErr==0 ){
pTos->n = 2; assert( z==0 );
pTos->flags = MEM_Str | MEM_Static | MEM_Term; pTos->flags = MEM_Null;
}else{ }else{
pTos->z = z; pTos->z = z;
pTos->n = strlen(z); pTos->n = strlen(z);

View File

@@ -12,7 +12,7 @@
# #
# This file implements tests for the PRAGMA command. # This file implements tests for the PRAGMA command.
# #
# $Id: pragma.test,v 1.47 2007/01/22 13:02:24 drh Exp $ # $Id: pragma.test,v 1.48 2007/01/27 02:24:56 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -259,12 +259,141 @@ if {![sqlite3 -has-codec] && $sqlite_options(integrityck)} {
btree_close $db btree_close $db
execsql {PRAGMA integrity_check} execsql {PRAGMA integrity_check}
} {{rowid 1 missing from index i2} {wrong # of entries in index i2}} } {{rowid 1 missing from index i2} {wrong # of entries in index i2}}
do_test pragma-3.3 {
execsql {PRAGMA integrity_check=1}
} {{rowid 1 missing from index i2}}
do_test pragma-3.4 {
execsql {
ATTACH DATABASE 'test.db' AS t2;
PRAGMA integrity_check
}
} {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
do_test pragma-3.5 {
execsql {
PRAGMA integrity_check=3
}
} {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2}}
do_test pragma-3.6 {
execsql {
PRAGMA integrity_check=xyz
}
} {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
do_test pragma-3.7 {
execsql {
PRAGMA integrity_check=0
}
} {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
# Add additional corruption by appending unused pages to the end of
# the database file testerr.db
#
do_test pragma-3.8 {
execsql {DETACH t2}
file delete -force testerr.db testerr.db-journal
set out [open testerr.db wb]
set in [open test.db rb]
puts -nonewline $out [read $in]
seek $in 0
puts -nonewline $out [read $in]
close $in
close $out
execsql {REINDEX t2}
execsql {PRAGMA integrity_check}
} {ok}
do_test pragma-3.9 {
execsql {
ATTACH 'testerr.db' AS t2;
PRAGMA integrity_check
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
do_test pragma-3.10 {
execsql {
PRAGMA integrity_check=1
}
} {{*** in database t2 ***
Page 4 is never used}}
do_test pragma-3.11 {
execsql {
PRAGMA integrity_check=5
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
do_test pragma-3.12 {
execsql {
PRAGMA integrity_check=4
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2}}
do_test pragma-3.13 {
execsql {
PRAGMA integrity_check=3
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used}}
do_test pragma-3.14 {
execsql {
PRAGMA integrity_check(2)
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used}}
do_test pragma-3.15 {
execsql {
ATTACH 'testerr.db' AS t3;
PRAGMA integrity_check
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
do_test pragma-3.16 {
execsql {
PRAGMA integrity_check(9)
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2}}
do_test pragma-3.17 {
execsql {
PRAGMA integrity_check=7
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
Page 4 is never used
Page 5 is never used}}
do_test pragma-3.18 {
execsql {
PRAGMA integrity_check=4
}
} {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2}}
} }
do_test pragma-3.3 { do_test pragma-3.99 {
execsql { file delete -force testerr.db testerr.db-journal
DROP INDEX i2; catchsql {DETACH t3}
} catchsql {DETACH t2}
} {} catchsql {DROP INDEX i2}
} {0 {}}
# Test modifying the cache_size of an attached database. # Test modifying the cache_size of an attached database.
ifcapable pager_pragmas { ifcapable pager_pragmas {

View File

@@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the pragma.html file. # Run this Tcl script to generate the pragma.html file.
# #
set rcsid {$Id: pragma.tcl,v 1.18 2006/06/20 00:22:38 drh Exp $} set rcsid {$Id: pragma.tcl,v 1.19 2007/01/27 02:24:57 drh Exp $}
source common.tcl source common.tcl
header {Pragma statements supported by SQLite} header {Pragma statements supported by SQLite}
@@ -487,12 +487,16 @@ Section {Pragmas to debug the library} debug
puts { puts {
<ul> <ul>
<a name="pragma_integrity_check"></a> <a name="pragma_integrity_check"></a>
<li><p><b>PRAGMA integrity_check;</b></p> <li><p><b>PRAGMA integrity_check;
<br>PRAGMA integrity_check(</b><i>integer</i><b>)</b></p>
<p>The command does an integrity check of the entire database. It <p>The command does an integrity check of the entire database. It
looks for out-of-order records, missing pages, malformed records, and looks for out-of-order records, missing pages, malformed records, and
corrupt indices. corrupt indices.
If any problems are found, then a single string is returned which is If any problems are found, then strings are returned (as multiple
a description of all problems. If everything is in order, "ok" is rows with a single column per row) which describe
the problems. At most <i>integer</i> errors will be reported
before the analysis quits. The default value for <i>integer</i>
is 100. If no errors are found, a single row with the value "ok" is
returned.</p></li> returned.</p></li>
<a name="pragma_parser_trace"></a> <a name="pragma_parser_trace"></a>