]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Limit the number of errors returned by PRAGMA integrity_check to 100 by
authordrh <drh@noemail.net>
Sat, 27 Jan 2007 02:24:54 +0000 (02:24 +0000)
committerdrh <drh@noemail.net>
Sat, 27 Jan 2007 02:24:54 +0000 (02:24 +0000)
default.  Specify an alternative limit using an argument to the pragma.
Ticket #2176. (CVS 3609)

FossilOrigin-Name: d564a039f27be2bb2c3973e79dc99b25869139da

manifest
manifest.uuid
src/btree.c
src/btree.h
src/pragma.c
src/test3.c
src/vdbe.c
test/pragma.test
www/pragma.tcl

index 49abe62e2af791acdbbd35cbef61ab2988e87317..0246e350b80745909153bacc41d2206a91bf7358 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\sthe\svdbeInt.h\sfile\sis\snot\s#included\smultiple\stimes.\s\sTicket\s#2194.\s(CVS\s3608)
-D 2007-01-26T21:08:05
+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-27T02:24:55
 F Makefile.in 7fa74bf4359aa899da5586e394d17735f221315f
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -57,8 +57,8 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
 F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
 F src/attach.c b11eb4d5d3fb99a10a626956bccc7215f6b68b16
 F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
-F src/btree.c 6837dcc4da8677e695a49fcc4505418ff1e0fc54
-F src/btree.h 061c50e37de7f50b58528e352d400cf33ead7418
+F src/btree.c 51aef6a4b18df165b83b332befd1447c011b4389
+F src/btree.h 066444ee25bd6e6accb997bfd2cf5ace14dbcd00
 F src/build.c 02aedde724dc73295d6e9b8dc29afb5dd38de507
 F src/callback.c fd9bb39f7ff6b52bad8365617abc61c720640429
 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
@@ -88,7 +88,7 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
 F src/pager.c d6ad66eb119602cb2e6a097f8f635372ba677d23
 F src/pager.h 2e6d42f4ae004ae748a037b8468112b851c447a7
 F src/parse.y 2f571c5f6219428d7fb08737db3d113742b1cceb
-F src/pragma.c fd4df6cf0857dd78a7cb5be5f9805419b53ae7a0
+F src/pragma.c 5091300911670ddaa552bfa12c45cbca1bb7e7d6
 F src/prepare.c 484389c6811415b8f23d259ac9c029613e1c72c3
 F src/printf.c aade23a789d7cc88b397ec0d33a0a01a33a7a9c1
 F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
@@ -102,7 +102,7 @@ F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
 F src/tclsqlite.c d344c7f394d6f055ce3abfe0049b0480c5e34e56
 F src/test1.c 053f5224697efaefff1f4c647fd90fdea9346cc5
 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b
-F src/test3.c fa0e85ddd1784f2dda5861a2cb4e7d27d1c932c1
+F src/test3.c 875126eab6749f9d9e2b60b6ee6a65825b3d1fed
 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
 F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
@@ -121,7 +121,7 @@ F src/update.c 951f95ef044cf6d28557c48dc35cb0711a0b9129
 F src/utf.c 67ecb1032bc0b42c105e88d65ef9d9f626eb0e1f
 F src/util.c 91d4cb189476906639ae611927d939691d1365f6
 F src/vacuum.c b4569b08aaa5afb141af3f76d0315745db4e9e4b
-F src/vdbe.c 4d54659b7dbb7a61570d7136a34fbde12b61c509
+F src/vdbe.c 31fe3e1e3cc00f5324a5fbde89d0ab603ad246b5
 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
 F src/vdbeInt.h 13ba07121cf534d5b80130d2f5eb0a4937a36bba
 F src/vdbeapi.c 2d1e6843af8705a1172e54a418d2a3d5febd1dd7
@@ -269,7 +269,7 @@ F test/pager.test 6ee95e90ee8295e376e39a6c6566ef6df993601a
 F test/pager2.test 49c0f57c7da0b060f0486b85fdd074025caa694e
 F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4
 F test/pagesize.test 05c74ea49f790734ec1e9ab765d9bf1cce79b8f2
-F test/pragma.test d20fe81e31c6be9cb3182f1792cf5e5a6d4e97f6
+F test/pragma.test b523286a32bfab309dd42d21ccdc9f5e51e3b2e9
 F test/printf.test cdd8e20dd901382a385afcbaa777b9377815c2ad
 F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
 F test/quick.test 6bc0f7c7b905f7de5fe4d3f13239ced3e4e66fe7
@@ -416,7 +416,7 @@ F www/opcode.tcl 5bd68059416b223515a680d410a9f7cb6736485f
 F www/optimizer.tcl d6812a10269bd0d7c488987aac0ad5036cace9dc
 F www/optimizing.tcl f0b2538988d1bbad16cbfe63ec6e8f48c9eb04e5
 F www/optoverview.tcl 815df406a38c9f69b27d37e8f7ede004c6d9f19e
-F www/pragma.tcl c3d103838ae1c66729f8286e276735618af2a88a
+F www/pragma.tcl 74544f5564bbb6d9809cf35b4c05ebdfee469165
 F www/quickstart.tcl 8708a4ca83fbf55c66af1782992626f20c3df095
 F www/shared.gif 265bae80c5b311c5a86e47662821076ffaf5c6ea
 F www/sharedcache.tcl 3ebec81110e606af6fd65a3c4c19562cb173b29c
@@ -428,7 +428,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 02990fabd1c68fb51afc91a1b720802ef86bfec6
-R f3d4c318f331af035a24f47aae427d9a
+P 93edd3b0565d08383b3034c57f221073fde6de4b
+R 557df95c56e9de3c85559166fb533aa4
 U drh
-Z b826f35654120ae9d4f4a22ffb14f63f
+Z 0cf02b2f60ab84b0a3c77c11c5fcb2c4
index f2b71816b635105737aabdeda27d45ca09c937e4..3668855f5c9e750270797fa8a12449a7e896520a 100644 (file)
@@ -1 +1 @@
-93edd3b0565d08383b3034c57f221073fde6de4b
\ No newline at end of file
+d564a039f27be2bb2c3973e79dc99b25869139da
\ No newline at end of file
index b8f3f378b52a10754d92829a4cccf95335354fa2..8ac469ded954b9b8449afe0fb7b2c533438168d8 100644 (file)
@@ -9,7 +9,7 @@
 **    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.
 ** For a detailed discussion of BTrees, refer to
@@ -5958,10 +5958,12 @@ Pager *sqlite3BtreePager(Btree *p){
 typedef struct IntegrityCk IntegrityCk;
 struct IntegrityCk {
   BtShared *pBt;    /* The tree being checked out */
-  Pager *pPager; /* The associated pager.  Also accessible by pBt->pPager */
-  int nPage;     /* Number of pages in the database */
-  int *anRef;    /* Number of times each page is referenced */
-  char *zErrMsg; /* An error message.  NULL of no errors seen. */
+  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
+  int nPage;        /* Number of pages in the database */
+  int *anRef;       /* Number of times each page is referenced */
+  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
@@ -5976,6 +5978,9 @@ static void checkAppendMsg(
 ){
   va_list ap;
   char *zMsg2;
+  if( !pCheck->mxErr ) return;
+  pCheck->mxErr--;
+  pCheck->nErr++;
   va_start(ap, zFormat);
   zMsg2 = sqlite3VMPrintf(zFormat, ap);
   va_end(ap);
@@ -6059,7 +6064,7 @@ static void checkList(
   int i;
   int expected = N;
   int iFirst = iPage;
-  while( N-- > 0 ){
+  while( N-- > 0 && pCheck->mxErr ){
     unsigned char *pOvfl;
     if( iPage<1 ){
       checkAppendMsg(pCheck, zContext,
@@ -6171,7 +6176,7 @@ static int checkTreePage(
   /* Check out all the cells.
   */
   depth = 0;
-  for(i=0; i<pPage->nCell; i++){
+  for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
     u8 *pCell;
     int sz;
     CellInfo info;
@@ -6286,7 +6291,13 @@ static int checkTreePage(
 ** and a pointer to that error message is returned.  The calling function
 ** 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 nRef;
   IntegrityCk sCheck;
@@ -6299,6 +6310,9 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
   sCheck.pBt = pBt;
   sCheck.pPager = pBt->pPager;
   sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
+  sCheck.mxErr = mxErr;
+  sCheck.nErr = 0;
+  *pnErr = 0;
   if( sCheck.nPage==0 ){
     unlockBtreeIfUnused(pBt);
     return 0;
@@ -6306,6 +6320,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
   sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
   if( !sCheck.anRef ){
     unlockBtreeIfUnused(pBt);
+    *pnErr = 1;
     return sqlite3MPrintf("Unable to malloc %d bytes", 
         (sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
   }
@@ -6323,7 +6338,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
 
   /* Check all the tables.
   */
-  for(i=0; i<nRoot; i++){
+  for(i=0; i<nRoot && sCheck.mxErr; i++){
     if( aRoot[i]==0 ) continue;
 #ifndef SQLITE_OMIT_AUTOVACUUM
     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
   */
-  for(i=1; i<=sCheck.nPage; i++){
+  for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
 #ifdef SQLITE_OMIT_AUTOVACUUM
     if( sCheck.anRef[i]==0 ){
       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.
   */
   sqliteFree(sCheck.anRef);
+  *pnErr = sCheck.nErr;
   return sCheck.zErrMsg;
 }
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
index ae24233859a26eb415203cb15651ffb13551ef32..8a05759ee97b2a226deccf2d18e03a18af93ecdf 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** 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_
 #define _BTREE_H_
@@ -131,7 +131,7 @@ const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
 int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
 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*);
 
 
index 2474fa7a456c398812c9e80c446a5d1729473379..26bdba224c848d699e9900b2a096f46713373ce4 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** 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 "os.h"
@@ -640,9 +640,13 @@ void sqlite3Pragma(
     }
   }else
 
+#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
+# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
+#endif
+
 #ifndef SQLITE_OMIT_INTEGRITY_CHECK
   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
     ** messages have been generated, output OK.  Otherwise output the
@@ -660,7 +664,16 @@ void sqlite3Pragma(
     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
     sqlite3VdbeSetNumCols(v, 1);
     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 */
     for(i=0; i<db->nDb; i++){
@@ -671,6 +684,9 @@ void sqlite3Pragma(
       if( OMIT_TEMPDB && i==1 ) continue;
 
       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
       */
@@ -685,28 +701,28 @@ void sqlite3Pragma(
           cnt++;
         }
       }
-      assert( cnt>0 );
-      sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
-      sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
-      addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
-      sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
+      if( cnt==0 ) continue;
+      sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
+      addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
       sqlite3VdbeOp3(v, OP_String8, 0, 0,
          sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
          P3_DYNAMIC);
       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_MemIncr, 1, 0);
+      sqlite3VdbeJumpHere(v, addr);
 
       /* Make sure all the indices are constructed correctly.
       */
-      sqlite3CodeVerifySchema(pParse, i);
       for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
         Table *pTab = sqliteHashData(x);
         Index *pIdx;
         int loopTop;
 
         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);
         sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
         loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
@@ -714,7 +730,7 @@ void sqlite3Pragma(
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           int jmp2;
           static const VdbeOpList idxErr[] = {
-            { OP_MemIncr,     1,  0,  0},
+            { OP_MemIncr,    -1,  0,  0},
             { OP_String8,     0,  0,  "rowid "},
             { OP_Rowid,       1,  0,  0},
             { OP_String8,     0,  0,  " missing from index "},
@@ -739,13 +755,16 @@ void sqlite3Pragma(
              { OP_MemLoad,      1,  0,  0},
              { OP_MemLoad,      2,  0,  0},
              { 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,  0},  /* 9 */
              { OP_Concat,       0,  0,  0},
              { OP_Callback,     1,  0,  0},
           };
           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);
           sqlite3VdbeChangeP1(v, addr+1, j+2);
           sqlite3VdbeChangeP2(v, addr+1, addr+4);
@@ -757,6 +776,7 @@ void sqlite3Pragma(
       } 
     }
     addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
+    sqlite3VdbeChangeP1(v, addr+1, mxErr);
     sqlite3VdbeJumpHere(v, addr+2);
   }else
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
index 4f42b5fbfd0aa6a55788a3d8aad0a6be1b756353..0f0184d0f43e42a100a02a6f0dec587abb030318 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** 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 "pager.h"
@@ -567,6 +567,7 @@ static int btree_integrity_check(
   int nRoot;
   int *aRoot;
   int i;
+  int nErr;
   char *zResult;
 
   if( argc<3 ){
@@ -581,7 +582,7 @@ static int btree_integrity_check(
     if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
   }
 #ifndef SQLITE_OMIT_INTEGRITY_CHECK
-  zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
+  zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
 #else
   zResult = 0;
 #endif
index 8d66b99c73db88bf3a1f71b2f3d96edb18d3d7fa..798228d53d65d0f11db43259eff2510ceab7c9c0 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** 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 "os.h"
@@ -4120,11 +4120,16 @@ case OP_DropTrigger: {        /* no-push */
 
 
 #ifndef SQLITE_OMIT_INTEGRITY_CHECK
-/* Opcode: IntegrityCk * P2 *
+/* Opcode: IntegrityCk P1 P2 *
 **
 ** Do an analysis of the currently open database.  Push onto the
 ** 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
 ** 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
 ** 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: {
   int nRoot;
   int *aRoot;
   int j;
+  int nErr;
   char *z;
+  Mem *pnErr;
 
   for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
     if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
@@ -4147,6 +4154,10 @@ case OP_IntegrityCk: {
   assert( nRoot>0 );
   aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
   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++){
     Mem *pMem = &pTos[-j];
     aRoot[j] = pMem->i;
@@ -4154,12 +4165,12 @@ case OP_IntegrityCk: {
   aRoot[j] = 0;
   popStack(&pTos, nRoot);
   pTos++;
-  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
-  if( z==0 || z[0]==0 ){
-    if( z ) sqliteFree(z);
-    pTos->z = "ok";
-    pTos->n = 2;
-    pTos->flags = MEM_Str | MEM_Static | MEM_Term;
+  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
+                                 pnErr->i, &nErr);
+  pnErr->i -= nErr;
+  if( nErr==0 ){
+    assert( z==0 );
+    pTos->flags = MEM_Null;
   }else{
     pTos->z = z;
     pTos->n = strlen(z);
index be253b086e0e0c8bd3846d46ac441b7816d94a04..ae8b2ec59405693dab3d4de024784f2e0b1913cc 100644 (file)
@@ -12,7 +12,7 @@
 #
 # 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]
 source $testdir/tester.tcl
@@ -259,12 +259,141 @@ if {![sqlite3 -has-codec] && $sqlite_options(integrityck)} {
     btree_close $db
     execsql {PRAGMA integrity_check}
   } {{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 {
-  execsql {
-    DROP INDEX i2;
-  } 
-} {}
+do_test pragma-3.99 {
+  file delete -force testerr.db testerr.db-journal
+  catchsql {DETACH t3}
+  catchsql {DETACH t2}
+  catchsql {DROP INDEX i2}
+} {0 {}}
 
 # Test modifying the cache_size of an attached database.
 ifcapable pager_pragmas {
index 4f92a6bddf8c0c77dde3f3faa8b4a3d6087084ed..a8dc2810962d260c7290544ff791c71f92cdcf0b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # 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
 header {Pragma statements supported by SQLite}
 
@@ -487,12 +487,16 @@ Section {Pragmas to debug the library} debug
 puts {
 <ul>
 <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
     looks for out-of-order records, missing pages, malformed records, and
     corrupt indices.
-    If any problems are found, then a single string is returned which is
-    a description of all problems.  If everything is in order, "ok" is
+    If any problems are found, then strings are returned (as multiple
+    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>
 
 <a name="pragma_parser_trace"></a>