/ Check-in [d564a039]
Login

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

Overview
Comment: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)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:d564a039f27be2bb2c3973e79dc99b25869139da
User & Date: drh 2007-01-27 02:24:55
Context
2007-01-27
02:38
Parser changes to allow parenthesized numerical arguments to pragmas, in support of the integrity_check enhancement of check-in (3609) and ticket #2176. (CVS 3610) check-in: ab6322bf user: drh tags: trunk
02:24
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) check-in: d564a039 user: drh tags: trunk
2007-01-26
21:08
Make sure the vdbeInt.h file is not #included multiple times. Ticket #2194. (CVS 3608) check-in: 93edd3b0 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.333 2007/01/05 02:00:47 drh Exp $
           12  +** $Id: btree.c,v 1.334 2007/01/27 02:24:55 drh Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** For a detailed discussion of BTrees, refer to
    16     16   **
    17     17   **     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
    18     18   **     "Sorting And Searching", pages 473-480. Addison-Wesley
    19     19   **     Publishing Company, Reading, Massachusetts.
................................................................................
  5954   5954   /*
  5955   5955   ** This structure is passed around through all the sanity checking routines
  5956   5956   ** in order to keep track of some global state information.
  5957   5957   */
  5958   5958   typedef struct IntegrityCk IntegrityCk;
  5959   5959   struct IntegrityCk {
  5960   5960     BtShared *pBt;    /* The tree being checked out */
  5961         -  Pager *pPager; /* The associated pager.  Also accessible by pBt->pPager */
  5962         -  int nPage;     /* Number of pages in the database */
  5963         -  int *anRef;    /* Number of times each page is referenced */
  5964         -  char *zErrMsg; /* An error message.  NULL of no errors seen. */
         5961  +  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
         5962  +  int nPage;        /* Number of pages in the database */
         5963  +  int *anRef;       /* Number of times each page is referenced */
         5964  +  int mxErr;        /* Stop accumulating errors when this reaches zero */
         5965  +  char *zErrMsg;    /* An error message.  NULL if no errors seen. */
         5966  +  int nErr;         /* Number of messages written to zErrMsg so far */
  5965   5967   };
  5966   5968   
  5967   5969   #ifndef SQLITE_OMIT_INTEGRITY_CHECK
  5968   5970   /*
  5969   5971   ** Append a message to the error message string.
  5970   5972   */
  5971   5973   static void checkAppendMsg(
................................................................................
  5972   5974     IntegrityCk *pCheck,
  5973   5975     char *zMsg1,
  5974   5976     const char *zFormat,
  5975   5977     ...
  5976   5978   ){
  5977   5979     va_list ap;
  5978   5980     char *zMsg2;
         5981  +  if( !pCheck->mxErr ) return;
         5982  +  pCheck->mxErr--;
         5983  +  pCheck->nErr++;
  5979   5984     va_start(ap, zFormat);
  5980   5985     zMsg2 = sqlite3VMPrintf(zFormat, ap);
  5981   5986     va_end(ap);
  5982   5987     if( zMsg1==0 ) zMsg1 = "";
  5983   5988     if( pCheck->zErrMsg ){
  5984   5989       char *zOld = pCheck->zErrMsg;
  5985   5990       pCheck->zErrMsg = 0;
................................................................................
  6055   6060     int iPage,            /* Page number for first page in the list */
  6056   6061     int N,                /* Expected number of pages in the list */
  6057   6062     char *zContext        /* Context for error messages */
  6058   6063   ){
  6059   6064     int i;
  6060   6065     int expected = N;
  6061   6066     int iFirst = iPage;
  6062         -  while( N-- > 0 ){
         6067  +  while( N-- > 0 && pCheck->mxErr ){
  6063   6068       unsigned char *pOvfl;
  6064   6069       if( iPage<1 ){
  6065   6070         checkAppendMsg(pCheck, zContext,
  6066   6071            "%d of %d pages missing from overflow list starting at %d",
  6067   6072             N+1, expected, iFirst);
  6068   6073         break;
  6069   6074       }
................................................................................
  6167   6172       releasePage(pPage);
  6168   6173       return 0;
  6169   6174     }
  6170   6175   
  6171   6176     /* Check out all the cells.
  6172   6177     */
  6173   6178     depth = 0;
  6174         -  for(i=0; i<pPage->nCell; i++){
         6179  +  for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
  6175   6180       u8 *pCell;
  6176   6181       int sz;
  6177   6182       CellInfo info;
  6178   6183   
  6179   6184       /* Check payload overflow pages
  6180   6185       */
  6181   6186       sprintf(zContext, "On tree page %d cell %d: ", iPage, i);
................................................................................
  6282   6287   ** a table.  nRoot is the number of entries in aRoot.
  6283   6288   **
  6284   6289   ** If everything checks out, this routine returns NULL.  If something is
  6285   6290   ** amiss, an error message is written into memory obtained from malloc()
  6286   6291   ** and a pointer to that error message is returned.  The calling function
  6287   6292   ** is responsible for freeing the error message when it is done.
  6288   6293   */
  6289         -char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
         6294  +char *sqlite3BtreeIntegrityCheck(
         6295  +  Btree *p,     /* The btree to be checked */
         6296  +  int *aRoot,   /* An array of root pages numbers for individual trees */
         6297  +  int nRoot,    /* Number of entries in aRoot[] */
         6298  +  int mxErr,    /* Stop reporting errors after this many */
         6299  +  int *pnErr    /* Write number of errors seen to this variable */
         6300  +){
  6290   6301     int i;
  6291   6302     int nRef;
  6292   6303     IntegrityCk sCheck;
  6293   6304     BtShared *pBt = p->pBt;
  6294   6305   
  6295   6306     nRef = sqlite3pager_refcount(pBt->pPager);
  6296   6307     if( lockBtreeWithRetry(p)!=SQLITE_OK ){
  6297   6308       return sqliteStrDup("Unable to acquire a read lock on the database");
  6298   6309     }
  6299   6310     sCheck.pBt = pBt;
  6300   6311     sCheck.pPager = pBt->pPager;
  6301   6312     sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
         6313  +  sCheck.mxErr = mxErr;
         6314  +  sCheck.nErr = 0;
         6315  +  *pnErr = 0;
  6302   6316     if( sCheck.nPage==0 ){
  6303   6317       unlockBtreeIfUnused(pBt);
  6304   6318       return 0;
  6305   6319     }
  6306   6320     sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
  6307   6321     if( !sCheck.anRef ){
  6308   6322       unlockBtreeIfUnused(pBt);
         6323  +    *pnErr = 1;
  6309   6324       return sqlite3MPrintf("Unable to malloc %d bytes", 
  6310   6325           (sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
  6311   6326     }
  6312   6327     for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
  6313   6328     i = PENDING_BYTE_PAGE(pBt);
  6314   6329     if( i<=sCheck.nPage ){
  6315   6330       sCheck.anRef[i] = 1;
................................................................................
  6319   6334     /* Check the integrity of the freelist
  6320   6335     */
  6321   6336     checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
  6322   6337               get4byte(&pBt->pPage1->aData[36]), "Main freelist: ");
  6323   6338   
  6324   6339     /* Check all the tables.
  6325   6340     */
  6326         -  for(i=0; i<nRoot; i++){
         6341  +  for(i=0; i<nRoot && sCheck.mxErr; i++){
  6327   6342       if( aRoot[i]==0 ) continue;
  6328   6343   #ifndef SQLITE_OMIT_AUTOVACUUM
  6329   6344       if( pBt->autoVacuum && aRoot[i]>1 ){
  6330   6345         checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
  6331   6346       }
  6332   6347   #endif
  6333   6348       checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ");
  6334   6349     }
  6335   6350   
  6336   6351     /* Make sure every page in the file is referenced
  6337   6352     */
  6338         -  for(i=1; i<=sCheck.nPage; i++){
         6353  +  for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
  6339   6354   #ifdef SQLITE_OMIT_AUTOVACUUM
  6340   6355       if( sCheck.anRef[i]==0 ){
  6341   6356         checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
  6342   6357       }
  6343   6358   #else
  6344   6359       /* If the database supports auto-vacuum, make sure no tables contain
  6345   6360       ** references to pointer-map pages.
................................................................................
  6364   6379         nRef, sqlite3pager_refcount(pBt->pPager)
  6365   6380       );
  6366   6381     }
  6367   6382   
  6368   6383     /* Clean  up and report errors.
  6369   6384     */
  6370   6385     sqliteFree(sCheck.anRef);
         6386  +  *pnErr = sCheck.nErr;
  6371   6387     return sCheck.zErrMsg;
  6372   6388   }
  6373   6389   #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
  6374   6390   
  6375   6391   /*
  6376   6392   ** Return the full pathname of the underlying database file.
  6377   6393   */

Changes to src/btree.h.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This header file defines the interface that the sqlite B-Tree file
    13     13   ** subsystem.  See comments in the source code for a detailed description
    14     14   ** of what each interface routine does.
    15     15   **
    16         -** @(#) $Id: btree.h,v 1.71 2006/06/27 16:34:57 danielk1977 Exp $
           16  +** @(#) $Id: btree.h,v 1.72 2007/01/27 02:24:55 drh Exp $
    17     17   */
    18     18   #ifndef _BTREE_H_
    19     19   #define _BTREE_H_
    20     20   
    21     21   /* TODO: This definition is just included so other modules compile. It
    22     22   ** needs to be revisited.
    23     23   */
................................................................................
   127    127   int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
   128    128   int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
   129    129   const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
   130    130   const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
   131    131   int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
   132    132   int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
   133    133   
   134         -char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
          134  +char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
   135    135   struct Pager *sqlite3BtreePager(Btree*);
   136    136   
   137    137   
   138    138   #ifdef SQLITE_TEST
   139    139   int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
   140    140   void sqlite3BtreeCursorList(Btree*);
   141    141   #endif

Changes to src/pragma.c.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains code used to implement the PRAGMA command.
    13     13   **
    14         -** $Id: pragma.c,v 1.126 2007/01/04 22:13:42 drh Exp $
           14  +** $Id: pragma.c,v 1.127 2007/01/27 02:24:56 drh Exp $
    15     15   */
    16     16   #include "sqliteInt.h"
    17     17   #include "os.h"
    18     18   #include <ctype.h>
    19     19   
    20     20   /* Ignore this whole file if pragmas are disabled
    21     21   */
................................................................................
   635    635     ** used will be case sensitive or not depending on the RHS.
   636    636     */
   637    637     if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
   638    638       if( zRight ){
   639    639         sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
   640    640       }
   641    641     }else
          642  +
          643  +#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
          644  +# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
          645  +#endif
   642    646   
   643    647   #ifndef SQLITE_OMIT_INTEGRITY_CHECK
   644    648     if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
   645         -    int i, j, addr;
          649  +    int i, j, addr, mxErr;
   646    650   
   647    651       /* Code that appears at the end of the integrity check.  If no error
   648    652       ** messages have been generated, output OK.  Otherwise output the
   649    653       ** error message
   650    654       */
   651    655       static const VdbeOpList endCode[] = {
   652    656         { OP_MemLoad,     0, 0,        0},
................................................................................
   656    660         { OP_Callback,    1, 0,        0},
   657    661       };
   658    662   
   659    663       /* Initialize the VDBE program */
   660    664       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
   661    665       sqlite3VdbeSetNumCols(v, 1);
   662    666       sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
   663         -    sqlite3VdbeAddOp(v, OP_MemInt, 0, 0);  /* Initialize error count to 0 */
          667  +
          668  +    /* Set the maximum error count */
          669  +    mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
          670  +    if( zRight ){
          671  +      mxErr = atoi(zRight);
          672  +      if( mxErr<=0 ){
          673  +        mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
          674  +      }
          675  +    }
          676  +    sqlite3VdbeAddOp(v, OP_MemInt, mxErr, 0);
   664    677   
   665    678       /* Do an integrity check on each database file */
   666    679       for(i=0; i<db->nDb; i++){
   667    680         HashElem *x;
   668    681         Hash *pTbls;
   669    682         int cnt = 0;
   670    683   
   671    684         if( OMIT_TEMPDB && i==1 ) continue;
   672    685   
   673    686         sqlite3CodeVerifySchema(pParse, i);
          687  +      addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
          688  +      sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
          689  +      sqlite3VdbeJumpHere(v, addr);
   674    690   
   675    691         /* Do an integrity check of the B-Tree
   676    692         */
   677    693         pTbls = &db->aDb[i].pSchema->tblHash;
   678    694         for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
   679    695           Table *pTab = sqliteHashData(x);
   680    696           Index *pIdx;
................................................................................
   681    697           sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
   682    698           cnt++;
   683    699           for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
   684    700             sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
   685    701             cnt++;
   686    702           }
   687    703         }
   688         -      assert( cnt>0 );
   689         -      sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
   690         -      sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
   691         -      addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
   692         -      sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
          704  +      if( cnt==0 ) continue;
          705  +      sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
          706  +      addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
   693    707         sqlite3VdbeOp3(v, OP_String8, 0, 0,
   694    708            sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
   695    709            P3_DYNAMIC);
   696    710         sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
   697         -      sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
          711  +      sqlite3VdbeAddOp(v, OP_Concat, 0, 0);
   698    712         sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
   699         -      sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
          713  +      sqlite3VdbeJumpHere(v, addr);
   700    714   
   701    715         /* Make sure all the indices are constructed correctly.
   702    716         */
   703         -      sqlite3CodeVerifySchema(pParse, i);
   704    717         for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
   705    718           Table *pTab = sqliteHashData(x);
   706    719           Index *pIdx;
   707    720           int loopTop;
   708    721   
   709    722           if( pTab->pIndex==0 ) continue;
          723  +        addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
          724  +        sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
          725  +        sqlite3VdbeJumpHere(v, addr);
   710    726           sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
   711    727           sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
   712    728           loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
   713    729           sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
   714    730           for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
   715    731             int jmp2;
   716    732             static const VdbeOpList idxErr[] = {
   717         -            { OP_MemIncr,     1,  0,  0},
          733  +            { OP_MemIncr,    -1,  0,  0},
   718    734               { OP_String8,     0,  0,  "rowid "},
   719    735               { OP_Rowid,       1,  0,  0},
   720    736               { OP_String8,     0,  0,  " missing from index "},
   721    737               { OP_String8,     0,  0,  0},    /* 4 */
   722    738               { OP_Concat,      2,  0,  0},
   723    739               { OP_Callback,    1,  0,  0},
   724    740             };
................................................................................
   735    751                { OP_MemInt,       0,  2,  0},
   736    752                { OP_Rewind,       0,  0,  0},  /* 1 */
   737    753                { OP_MemIncr,      1,  2,  0},
   738    754                { OP_Next,         0,  0,  0},  /* 3 */
   739    755                { OP_MemLoad,      1,  0,  0},
   740    756                { OP_MemLoad,      2,  0,  0},
   741    757                { OP_Eq,           0,  0,  0},  /* 6 */
   742         -             { OP_MemIncr,      1,  0,  0},
          758  +             { OP_MemIncr,     -1,  0,  0},
   743    759                { OP_String8,      0,  0,  "wrong # of entries in index "},
   744    760                { OP_String8,      0,  0,  0},  /* 9 */
   745    761                { OP_Concat,       0,  0,  0},
   746    762                { OP_Callback,     1,  0,  0},
   747    763             };
   748    764             if( pIdx->tnum==0 ) continue;
          765  +          addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
          766  +          sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
          767  +          sqlite3VdbeJumpHere(v, addr);
   749    768             addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
   750    769             sqlite3VdbeChangeP1(v, addr+1, j+2);
   751    770             sqlite3VdbeChangeP2(v, addr+1, addr+4);
   752    771             sqlite3VdbeChangeP1(v, addr+3, j+2);
   753    772             sqlite3VdbeChangeP2(v, addr+3, addr+2);
   754    773             sqlite3VdbeJumpHere(v, addr+6);
   755    774             sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
   756    775           }
   757    776         } 
   758    777       }
   759    778       addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
          779  +    sqlite3VdbeChangeP1(v, addr+1, mxErr);
   760    780       sqlite3VdbeJumpHere(v, addr+2);
   761    781     }else
   762    782   #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
   763    783   
   764    784   #ifndef SQLITE_OMIT_UTF16
   765    785     /*
   766    786     **   PRAGMA encoding

Changes to src/test3.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Code for testing the btree.c module in SQLite.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   **
    16         -** $Id: test3.c,v 1.68 2007/01/03 23:37:28 drh Exp $
           16  +** $Id: test3.c,v 1.69 2007/01/27 02:24:56 drh Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   #include "pager.h"
    20     20   #include "btree.h"
    21     21   #include "tcl.h"
    22     22   #include <stdlib.h>
    23     23   #include <string.h>
................................................................................
   563    563     int argc,              /* Number of arguments */
   564    564     const char **argv      /* Text of each argument */
   565    565   ){
   566    566     Btree *pBt;
   567    567     int nRoot;
   568    568     int *aRoot;
   569    569     int i;
          570  +  int nErr;
   570    571     char *zResult;
   571    572   
   572    573     if( argc<3 ){
   573    574       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   574    575          " ID ROOT ...\"", 0);
   575    576       return TCL_ERROR;
   576    577     }
................................................................................
   577    578     pBt = sqlite3TextToPtr(argv[1]);
   578    579     nRoot = argc-2;
   579    580     aRoot = malloc( sizeof(int)*(argc-2) );
   580    581     for(i=0; i<argc-2; i++){
   581    582       if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
   582    583     }
   583    584   #ifndef SQLITE_OMIT_INTEGRITY_CHECK
   584         -  zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
          585  +  zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
   585    586   #else
   586    587     zResult = 0;
   587    588   #endif
   588    589     free(aRoot);
   589    590     if( zResult ){
   590    591       Tcl_AppendResult(interp, zResult, 0);
   591    592       sqliteFree(zResult); 

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.586 2007/01/12 23:43:43 drh Exp $
           46  +** $Id: vdbe.c,v 1.587 2007/01/27 02:24:56 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
  4116   4116   case OP_DropTrigger: {        /* no-push */
  4117   4117     sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3);
  4118   4118     break;
  4119   4119   }
  4120   4120   
  4121   4121   
  4122   4122   #ifndef SQLITE_OMIT_INTEGRITY_CHECK
  4123         -/* Opcode: IntegrityCk * P2 *
         4123  +/* Opcode: IntegrityCk P1 P2 *
  4124   4124   **
  4125   4125   ** Do an analysis of the currently open database.  Push onto the
  4126   4126   ** stack the text of an error message describing any problems.
  4127         -** If there are no errors, push a "ok" onto the stack.
         4127  +** If no problems are found, push a NULL onto the stack.
         4128  +**
         4129  +** P1 is the address of a memory cell that contains the maximum
         4130  +** number of allowed errors.  At most mem[P1] errors will be reported.
         4131  +** In other words, the analysis stops as soon as mem[P1] errors are 
         4132  +** seen.  Mem[P1] is updated with the number of errors remaining.
  4128   4133   **
  4129   4134   ** The root page numbers of all tables in the database are integer
  4130   4135   ** values on the stack.  This opcode pulls as many integers as it
  4131   4136   ** can off of the stack and uses those numbers as the root pages.
  4132   4137   **
  4133   4138   ** If P2 is not zero, the check is done on the auxiliary database
  4134   4139   ** file, not the main database file.
  4135   4140   **
  4136         -** This opcode is used for testing purposes only.
         4141  +** This opcode is used to implement the integrity_check pragma.
  4137   4142   */
  4138   4143   case OP_IntegrityCk: {
  4139   4144     int nRoot;
  4140   4145     int *aRoot;
  4141   4146     int j;
         4147  +  int nErr;
  4142   4148     char *z;
         4149  +  Mem *pnErr;
  4143   4150   
  4144   4151     for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
  4145   4152       if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
  4146   4153     }
  4147   4154     assert( nRoot>0 );
  4148   4155     aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
  4149   4156     if( aRoot==0 ) goto no_mem;
         4157  +  j = pOp->p1;
         4158  +  assert( j>=0 && j<p->nMem );
         4159  +  pnErr = &p->aMem[j];
         4160  +  assert( (pnErr->flags & MEM_Int)!=0 );
  4150   4161     for(j=0; j<nRoot; j++){
  4151   4162       Mem *pMem = &pTos[-j];
  4152   4163       aRoot[j] = pMem->i;
  4153   4164     }
  4154   4165     aRoot[j] = 0;
  4155   4166     popStack(&pTos, nRoot);
  4156   4167     pTos++;
  4157         -  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
  4158         -  if( z==0 || z[0]==0 ){
  4159         -    if( z ) sqliteFree(z);
  4160         -    pTos->z = "ok";
  4161         -    pTos->n = 2;
  4162         -    pTos->flags = MEM_Str | MEM_Static | MEM_Term;
         4168  +  z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
         4169  +                                 pnErr->i, &nErr);
         4170  +  pnErr->i -= nErr;
         4171  +  if( nErr==0 ){
         4172  +    assert( z==0 );
         4173  +    pTos->flags = MEM_Null;
  4163   4174     }else{
  4164   4175       pTos->z = z;
  4165   4176       pTos->n = strlen(z);
  4166   4177       pTos->flags = MEM_Str | MEM_Dyn | MEM_Term;
  4167   4178       pTos->xDel = 0;
  4168   4179     }
  4169   4180     pTos->enc = SQLITE_UTF8;

Changes to test/pragma.test.

     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.
    12     12   #
    13     13   # This file implements tests for the PRAGMA command.
    14     14   #
    15         -# $Id: pragma.test,v 1.47 2007/01/22 13:02:24 drh Exp $
           15  +# $Id: pragma.test,v 1.48 2007/01/27 02:24:56 drh Exp $
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   # Test organization:
    21     21   #
    22     22   # pragma-1.*: Test cache_size, default_cache_size and synchronous on main db.
................................................................................
   255    255       set c [btree_cursor $db $rootpage 1]
   256    256       btree_first $c
   257    257       btree_delete $c
   258    258       btree_commit $db
   259    259       btree_close $db
   260    260       execsql {PRAGMA integrity_check}
   261    261     } {{rowid 1 missing from index i2} {wrong # of entries in index i2}}
          262  +  do_test pragma-3.3 {
          263  +    execsql {PRAGMA integrity_check=1}
          264  +  } {{rowid 1 missing from index i2}}
          265  +  do_test pragma-3.4 {
          266  +    execsql {
          267  +      ATTACH DATABASE 'test.db' AS t2;
          268  +      PRAGMA integrity_check
          269  +    }
          270  +  } {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
          271  +  do_test pragma-3.5 {
          272  +    execsql {
          273  +      PRAGMA integrity_check=3
          274  +    }
          275  +  } {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2}}
          276  +  do_test pragma-3.6 {
          277  +    execsql {
          278  +      PRAGMA integrity_check=xyz
          279  +    }
          280  +  } {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
          281  +  do_test pragma-3.7 {
          282  +    execsql {
          283  +      PRAGMA integrity_check=0
          284  +    }
          285  +  } {{rowid 1 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
          286  +
          287  +  # Add additional corruption by appending unused pages to the end of
          288  +  # the database file testerr.db
          289  +  #
          290  +  do_test pragma-3.8 {
          291  +    execsql {DETACH t2}
          292  +    file delete -force testerr.db testerr.db-journal
          293  +    set out [open testerr.db wb]
          294  +    set in [open test.db rb]
          295  +    puts -nonewline $out [read $in]
          296  +    seek $in 0
          297  +    puts -nonewline $out [read $in]
          298  +    close $in
          299  +    close $out
          300  +    execsql {REINDEX t2}
          301  +    execsql {PRAGMA integrity_check}
          302  +  } {ok}
          303  +  do_test pragma-3.9 {
          304  +    execsql {
          305  +      ATTACH 'testerr.db' AS t2;
          306  +      PRAGMA integrity_check
          307  +    }
          308  +  } {{*** in database t2 ***
          309  +Page 4 is never used
          310  +Page 5 is never used
          311  +Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
          312  +  do_test pragma-3.10 {
          313  +    execsql {
          314  +      PRAGMA integrity_check=1
          315  +    }
          316  +  } {{*** in database t2 ***
          317  +Page 4 is never used}}
          318  +  do_test pragma-3.11 {
          319  +    execsql {
          320  +      PRAGMA integrity_check=5
          321  +    }
          322  +  } {{*** in database t2 ***
          323  +Page 4 is never used
          324  +Page 5 is never used
          325  +Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
          326  +  do_test pragma-3.12 {
          327  +    execsql {
          328  +      PRAGMA integrity_check=4
          329  +    }
          330  +  } {{*** in database t2 ***
          331  +Page 4 is never used
          332  +Page 5 is never used
          333  +Page 6 is never used} {rowid 1 missing from index i2}}
          334  +  do_test pragma-3.13 {
          335  +    execsql {
          336  +      PRAGMA integrity_check=3
          337  +    }
          338  +  } {{*** in database t2 ***
          339  +Page 4 is never used
          340  +Page 5 is never used
          341  +Page 6 is never used}}
          342  +  do_test pragma-3.14 {
          343  +    execsql {
          344  +      PRAGMA integrity_check(2)
          345  +    }
          346  +  } {{*** in database t2 ***
          347  +Page 4 is never used
          348  +Page 5 is never used}}
          349  +  do_test pragma-3.15 {
          350  +    execsql {
          351  +      ATTACH 'testerr.db' AS t3;
          352  +      PRAGMA integrity_check
          353  +    }
          354  +  } {{*** in database t2 ***
          355  +Page 4 is never used
          356  +Page 5 is never used
          357  +Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
          358  +Page 4 is never used
          359  +Page 5 is never used
          360  +Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2}}
          361  +  do_test pragma-3.16 {
          362  +    execsql {
          363  +      PRAGMA integrity_check(9)
          364  +    }
          365  +  } {{*** in database t2 ***
          366  +Page 4 is never used
          367  +Page 5 is never used
          368  +Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
          369  +Page 4 is never used
          370  +Page 5 is never used
          371  +Page 6 is never used} {rowid 1 missing from index i2}}
          372  +  do_test pragma-3.17 {
          373  +    execsql {
          374  +      PRAGMA integrity_check=7
          375  +    }
          376  +  } {{*** in database t2 ***
          377  +Page 4 is never used
          378  +Page 5 is never used
          379  +Page 6 is never used} {rowid 1 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
          380  +Page 4 is never used
          381  +Page 5 is never used}}
          382  +  do_test pragma-3.18 {
          383  +    execsql {
          384  +      PRAGMA integrity_check=4
          385  +    }
          386  +  } {{*** in database t2 ***
          387  +Page 4 is never used
          388  +Page 5 is never used
          389  +Page 6 is never used} {rowid 1 missing from index i2}}
   262    390   }
   263         -do_test pragma-3.3 {
   264         -  execsql {
   265         -    DROP INDEX i2;
   266         -  } 
   267         -} {}
          391  +do_test pragma-3.99 {
          392  +  file delete -force testerr.db testerr.db-journal
          393  +  catchsql {DETACH t3}
          394  +  catchsql {DETACH t2}
          395  +  catchsql {DROP INDEX i2}
          396  +} {0 {}}
   268    397   
   269    398   # Test modifying the cache_size of an attached database.
   270    399   ifcapable pager_pragmas {
   271    400   do_test pragma-4.1 {
   272    401     execsql {
   273    402       pragma aux.cache_size;
   274    403       pragma aux.default_cache_size;

Changes to www/pragma.tcl.

     1      1   #
     2      2   # Run this Tcl script to generate the pragma.html file.
     3      3   #
     4         -set rcsid {$Id: pragma.tcl,v 1.18 2006/06/20 00:22:38 drh Exp $}
            4  +set rcsid {$Id: pragma.tcl,v 1.19 2007/01/27 02:24:57 drh Exp $}
     5      5   source common.tcl
     6      6   header {Pragma statements supported by SQLite}
     7      7   
     8      8   proc Section {name {label {}}} {
     9      9     puts "\n<hr />"
    10     10     if {$label!=""} {
    11     11       puts "<a name=\"$label\"></a>"
................................................................................
   483    483   }
   484    484   
   485    485   Section {Pragmas to debug the library} debug
   486    486   
   487    487   puts {
   488    488   <ul>
   489    489   <a name="pragma_integrity_check"></a>
   490         -<li><p><b>PRAGMA integrity_check;</b></p>
          490  +<li><p><b>PRAGMA integrity_check;
          491  +    <br>PRAGMA integrity_check(</b><i>integer</i><b>)</b></p>
   491    492       <p>The command does an integrity check of the entire database.  It
   492    493       looks for out-of-order records, missing pages, malformed records, and
   493    494       corrupt indices.
   494         -    If any problems are found, then a single string is returned which is
   495         -    a description of all problems.  If everything is in order, "ok" is
          495  +    If any problems are found, then strings are returned (as multiple
          496  +    rows with a single column per row) which describe
          497  +    the problems.  At most <i>integer</i> errors will be reported
          498  +    before the analysis quits.  The default value for <i>integer</i>
          499  +    is 100.  If no errors are found, a single row with the value "ok" is
   496    500       returned.</p></li>
   497    501   
   498    502   <a name="pragma_parser_trace"></a>
   499    503   <li><p><b>PRAGMA parser_trace = ON; </b>(1)<b>
   500    504       <br>PRAGMA parser_trace = OFF;</b> (0)</p>
   501    505       <p>Turn tracing of the SQL parser inside of the
   502    506       SQLite library on and off.  This is used for debugging.