/ Check-in [99b9140c]
Login

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

Overview
Comment:Simplifications to the PRAGMA integrity_check code generator.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | improved-integrity-check
Files: files | file ages | folders
SHA3-256: 99b9140c795c0c17c4e9d2547477c9dac056edfd443f2b2bd70edecd43c49ab7
User & Date: drh 2017-09-10 01:06:05
Context
2017-09-13
00:13
PRAGMA integrity_check returns SQLITE_OK even if it encounters corruption while scanning indexes. Closed-Leaf check-in: 81f62e99 user: drh tags: improved-integrity-check
2017-09-10
01:06
Simplifications to the PRAGMA integrity_check code generator. check-in: 99b9140c user: drh tags: improved-integrity-check
2017-09-09
22:46
Simplification and performance improvement to sqlite3_reset(). check-in: b6425d01 user: drh tags: improved-integrity-check
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pragma.c.

   294    294     }
   295    295     return lwr>upr ? 0 : &aPragmaName[mid];
   296    296   }
   297    297   
   298    298   /*
   299    299   ** Helper subroutine for PRAGMA integrity_check:
   300    300   **
   301         -** Generate code to output a single-column result row with the result
   302         -** held in register regResult.  Decrement the result count and halt if
   303         -** the maximum number of result rows have been issued.
          301  +** Generate code to output a single-column result row with a value of the
          302  +** string held in register 3.  Decrement the result count in register 1
          303  +** and halt if the maximum number of result rows have been issued.
   304    304   */
   305         -static int integrityCheckResultRow(Vdbe *v, int regResult){
          305  +static int integrityCheckResultRow(Vdbe *v){
   306    306     int addr;
   307         -  sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1);
          307  +  sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
   308    308     addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
   309    309     VdbeCoverage(v);
   310         -  sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
          310  +  sqlite3VdbeAddOp0(v, OP_Halt);
   311    311     return addr;
   312    312   }
   313    313   
   314    314   /*
   315    315   ** Process a pragma statement.  
   316    316   **
   317    317   ** Pragmas are of this form:
................................................................................
  1480   1480           mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
  1481   1481         }
  1482   1482       }
  1483   1483       sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
  1484   1484   
  1485   1485       /* Do an integrity check on each database file */
  1486   1486       for(i=0; i<db->nDb; i++){
  1487         -      HashElem *x;
  1488         -      Hash *pTbls;
  1489         -      int *aRoot;
  1490         -      int cnt = 0;
  1491         -      int mxIdx = 0;
  1492         -      int nIdx;
         1487  +      HashElem *x;     /* For looping over tables in the schema */
         1488  +      Hash *pTbls;     /* Set of all tables in the schema */
         1489  +      int *aRoot;      /* Array of root page numbers of all btrees */
         1490  +      int cnt = 0;     /* Number of entries in aRoot[] */
         1491  +      int mxIdx = 0;   /* Maximum number of indexes for any table */
  1493   1492   
  1494   1493         if( OMIT_TEMPDB && i==1 ) continue;
  1495   1494         if( iDb>=0 && i!=iDb ) continue;
  1496   1495   
  1497   1496         sqlite3CodeVerifySchema(pParse, i);
  1498   1497   
  1499   1498         /* Do an integrity check of the B-Tree
................................................................................
  1500   1499         **
  1501   1500         ** Begin by finding the root pages numbers
  1502   1501         ** for all tables and indices in the database.
  1503   1502         */
  1504   1503         assert( sqlite3SchemaMutexHeld(db, i, 0) );
  1505   1504         pTbls = &db->aDb[i].pSchema->tblHash;
  1506   1505         for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
  1507         -        Table *pTab = sqliteHashData(x);
  1508         -        Index *pIdx;
         1506  +        Table *pTab = sqliteHashData(x);  /* Current table */
         1507  +        Index *pIdx;                      /* An index on pTab */
         1508  +        int nIdx;                         /* Number of indexes on pTab */
  1509   1509           if( HasRowid(pTab) ) cnt++;
  1510   1510           for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
  1511   1511           if( nIdx>mxIdx ) mxIdx = nIdx;
  1512   1512         }
  1513   1513         aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
  1514   1514         if( aRoot==0 ) break;
  1515   1515         for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
................................................................................
  1529   1529         /* Do the b-tree integrity checks */
  1530   1530         sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
  1531   1531         sqlite3VdbeChangeP5(v, (u8)i);
  1532   1532         addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
  1533   1533         sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
  1534   1534            sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
  1535   1535            P4_DYNAMIC);
  1536         -      sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
  1537         -      sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
  1538         -      integrityCheckResultRow(v, 2);
         1536  +      sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
         1537  +      integrityCheckResultRow(v);
  1539   1538         sqlite3VdbeJumpHere(v, addr);
  1540   1539   
  1541   1540         /* Make sure all the indices are constructed correctly.
  1542   1541         */
  1543   1542         for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
  1544   1543           Table *pTab = sqliteHashData(x);
  1545   1544           Index *pIdx, *pPk;
................................................................................
  1549   1548           int r1 = -1;
  1550   1549   
  1551   1550           if( pTab->tnum<1 ) continue;  /* Skip VIEWs or VIRTUAL TABLEs */
  1552   1551           pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
  1553   1552           sqlite3ExprCacheClear(pParse);
  1554   1553           sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
  1555   1554                                      1, 0, &iDataCur, &iIdxCur);
         1555  +        /* reg[7] counts the number of entries in the table.
         1556  +        ** reg[8+i] counts the number of entries in the i-th index 
         1557  +        */
  1556   1558           sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
  1557   1559           for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
  1558   1560             sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
  1559   1561           }
  1560   1562           assert( pParse->nMem>=8+j );
  1561   1563           assert( sqlite3NoTempsInRange(pParse,1,7+j) );
  1562   1564           sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
................................................................................
  1569   1571             if( pTab->aCol[j].notNull==0 ) continue;
  1570   1572             sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
  1571   1573             sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
  1572   1574             jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
  1573   1575             zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
  1574   1576                                 pTab->aCol[j].zName);
  1575   1577             sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
  1576         -          integrityCheckResultRow(v, 3);
         1578  +          integrityCheckResultRow(v);
  1577   1579             sqlite3VdbeJumpHere(v, jmp2);
  1578   1580           }
  1579   1581           /* Verify CHECK constraints */
  1580   1582           if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
  1581   1583             ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
  1582   1584             if( db->mallocFailed==0 ){
  1583   1585               int addrCkFault = sqlite3VdbeMakeLabel(v);
................................................................................
  1592   1594               sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, 
  1593   1595                   SQLITE_JUMPIFNULL);
  1594   1596               sqlite3VdbeResolveLabel(v, addrCkFault);
  1595   1597               pParse->iSelfTab = 0;
  1596   1598               zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
  1597   1599                   pTab->zName);
  1598   1600               sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
  1599         -            integrityCheckResultRow(v, 3);
         1601  +            integrityCheckResultRow(v);
  1600   1602               sqlite3VdbeResolveLabel(v, addrCkOk);
  1601   1603               sqlite3ExprCachePop(pParse);
  1602   1604             }
  1603   1605             sqlite3ExprListDelete(db, pCheck);
  1604   1606           }
  1605   1607           if( !isQuick ){ /* Omit the remaining tests for quick_check */
  1606   1608             /* Sanity check on record header decoding */
................................................................................
  1620   1622                                           pIdx->nColumn); VdbeCoverage(v);
  1621   1623               sqlite3VdbeLoadString(v, 3, "row ");
  1622   1624               sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
  1623   1625               sqlite3VdbeLoadString(v, 4, " missing from index ");
  1624   1626               sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
  1625   1627               jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
  1626   1628               sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
  1627         -            jmp4 = integrityCheckResultRow(v, 3);
         1629  +            jmp4 = integrityCheckResultRow(v);
  1628   1630               sqlite3VdbeJumpHere(v, jmp2);
  1629   1631               /* For UNIQUE indexes, verify that only one entry exists with the
  1630   1632               ** current key.  The entry is unique if (1) any column is NULL
  1631   1633               ** or (2) the next entry has a different key */
  1632   1634               if( IsUniqueIndex(pIdx) ){
  1633   1635                 int uniqOk = sqlite3VdbeMakeLabel(v);
  1634   1636                 int jmp6;
................................................................................
  1659   1661           if( !isQuick ){
  1660   1662             sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
  1661   1663             for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
  1662   1664               if( pPk==pIdx ) continue;
  1663   1665               sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
  1664   1666               addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
  1665   1667               sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
  1666         -            sqlite3VdbeLoadString(v, 3, pIdx->zName);
  1667         -            sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
  1668         -            integrityCheckResultRow(v, 7);
         1668  +            sqlite3VdbeLoadString(v, 4, pIdx->zName);
         1669  +            sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
         1670  +            integrityCheckResultRow(v);
  1669   1671               sqlite3VdbeJumpHere(v, addr);
  1670   1672             }
  1671   1673           }
  1672   1674   #endif /* SQLITE_OMIT_BTREECOUNT */
  1673   1675         } 
  1674   1676       }
  1675   1677       {