/ Check-in [5264844b]
Login

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

Overview
Comment:Fix integrity_check so that it verifies NOT NULL constraints even for tables that have no indexes. Enhance quick_check so that it verifies NOT NULL and CHECK constraints.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | integrity-check-improvements
Files: files | file ages | folders
SHA1: 5264844b069cdc20f456acee9f5b2b97c986120d
User & Date: drh 2017-02-22 15:11:36
Context
2017-02-22
18:04
Cleanup and simplification of the output row count limit control of PRAGMA integrity_check. Closed-Leaf check-in: 5af7d72e user: drh tags: integrity-check-improvements
15:11
Fix integrity_check so that it verifies NOT NULL constraints even for tables that have no indexes. Enhance quick_check so that it verifies NOT NULL and CHECK constraints. check-in: 5264844b user: drh tags: integrity-check-improvements
14:15
Enhance "PRAGMA integrity_check" so that it verifies CHECK constraints. check-in: 549bae08 user: drh tags: integrity-check-improvements
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

1111
1112
1113
1114
1115
1116
1117

1118
1119
1120
1121
1122
1123
1124
** the column currently under construction.
*/
void sqlite3AddNotNull(Parse *pParse, int onError){
  Table *p;
  p = pParse->pNewTable;
  if( p==0 || NEVER(p->nCol<1) ) return;
  p->aCol[p->nCol-1].notNull = (u8)onError;

}

/*
** Scan the column type name zType (length nType) and return the
** associated affinity type.
**
** This routine does a case-independent search of zType for the 







>







1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
** the column currently under construction.
*/
void sqlite3AddNotNull(Parse *pParse, int onError){
  Table *p;
  p = pParse->pNewTable;
  if( p==0 || NEVER(p->nCol<1) ) return;
  p->aCol[p->nCol-1].notNull = (u8)onError;
  p->tabFlags |= TF_HasNotNull;
}

/*
** Scan the column type name zType (length nType) and return the
** associated affinity type.
**
** This routine does a case-independent search of zType for the 

Changes to src/pragma.c.

1373
1374
1375
1376
1377
1378
1379







1380
1381
1382


1383
1384
1385
1386
1387
1388
1389
....
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484





1485
1486
1487
1488
1489
1490
1491
....
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
....
1591
1592
1593
1594
1595
1596
1597

1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610

1611
1612
1613
1614
1615
1616
1617
  break;

#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif

#ifndef SQLITE_OMIT_INTEGRITY_CHECK







  /* Pragma "quick_check" is reduced version of 
  ** integrity_check designed to detect most database corruption
  ** without most of the overhead of a full integrity-check.


  */
  case PragTyp_INTEGRITY_CHECK: {
    int i, j, addr, mxErr;

    int isQuick = (sqlite3Tolower(zLeft[0])=='q');

    /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
................................................................................
      sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
      sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
      sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
      sqlite3VdbeJumpHere(v, addr);

      /* Make sure all the indices are constructed correctly.
      */
      for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx, *pPk;
        Index *pPrior = 0;
        int loopTop;
        int iDataCur, iIdxCur;
        int r1 = -1;

        if( pTab->pIndex==0 && pTab->pCheck==0 ) continue;





        pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
        VdbeCoverage(v);
        sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
        sqlite3VdbeJumpHere(v, addr);
        sqlite3ExprCacheClear(pParse);
        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
................................................................................
          sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
          sqlite3VdbeAddOp2(v, OP_IfPos, 1, addrCkOk); VdbeCoverage(v);
          sqlite3VdbeAddOp0(v, OP_Halt);
          sqlite3VdbeResolveLabel(v, addrCkOk);
          sqlite3ExprCachePop(pParse);
        }
        /* Validate index entries for the current row */
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          int jmp2, jmp3, jmp4, jmp5;
          int ckUniq = sqlite3VdbeMakeLabel(v);
          if( pPk==pIdx ) continue;
          r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
                                       pPrior, r1);
          pPrior = pIdx;
          sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);  /* increment entry count */
................................................................................
          }
          sqlite3VdbeJumpHere(v, jmp4);
          sqlite3ResolvePartIdxLabel(pParse, jmp3);
        }
        sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
        sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT

        sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          if( pPk==pIdx ) continue;
          addr = sqlite3VdbeCurrentAddr(v);
          sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
          sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
          sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
          sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
          sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
          sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
          sqlite3VdbeLoadString(v, 3, pIdx->zName);
          sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
          sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);

        }
#endif /* SQLITE_OMIT_BTREECOUNT */
      } 
    }
    {
      static const int iLn = VDBE_OFFSET_LINENO(2);
      static const VdbeOpList endCode[] = {







>
>
>
>
>
>
>
|

<
>
>







 







|







|
>
>
>
>
>







 







|







 







>
|
|
|
|
|
|
|
|
|
|
|
|
|
>







1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388

1389
1390
1391
1392
1393
1394
1395
1396
1397
....
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
....
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
....
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
  break;

#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif

#ifndef SQLITE_OMIT_INTEGRITY_CHECK
  /*    PRAGMA integrity_check
  **    PRAGMA integrity_check(N)
  **    PRAGMA quick_check
  **    PRAGMA quick_check(N)
  **
  ** Verify the integrity of the database.
  **
  ** The "quick_check" is reduced version of 
  ** integrity_check designed to detect most database corruption

  ** without the overhead of cross-checking indexes.  Quick_check
  ** is linear time wherease integrity_check is O(NlogN).
  */
  case PragTyp_INTEGRITY_CHECK: {
    int i, j, addr, mxErr;

    int isQuick = (sqlite3Tolower(zLeft[0])=='q');

    /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
................................................................................
      sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
      sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
      sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
      sqlite3VdbeJumpHere(v, addr);

      /* Make sure all the indices are constructed correctly.
      */
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx, *pPk;
        Index *pPrior = 0;
        int loopTop;
        int iDataCur, iIdxCur;
        int r1 = -1;

        if( pTab->pCheck==0
         && (pTab->tabFlags & TF_HasNotNull)==0
         && (pTab->pIndex==0 || isQuick)
        ){
          continue;  /* No additional checks needed for this table */
        }
        pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
        VdbeCoverage(v);
        sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
        sqlite3VdbeJumpHere(v, addr);
        sqlite3ExprCacheClear(pParse);
        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
................................................................................
          sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
          sqlite3VdbeAddOp2(v, OP_IfPos, 1, addrCkOk); VdbeCoverage(v);
          sqlite3VdbeAddOp0(v, OP_Halt);
          sqlite3VdbeResolveLabel(v, addrCkOk);
          sqlite3ExprCachePop(pParse);
        }
        /* Validate index entries for the current row */
        for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
          int jmp2, jmp3, jmp4, jmp5;
          int ckUniq = sqlite3VdbeMakeLabel(v);
          if( pPk==pIdx ) continue;
          r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
                                       pPrior, r1);
          pPrior = pIdx;
          sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);  /* increment entry count */
................................................................................
          }
          sqlite3VdbeJumpHere(v, jmp4);
          sqlite3ResolvePartIdxLabel(pParse, jmp3);
        }
        sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
        sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
        if( !isQuick ){
          sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
          for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
            if( pPk==pIdx ) continue;
            addr = sqlite3VdbeCurrentAddr(v);
            sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
            sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
            sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
            sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
            sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
            sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
            sqlite3VdbeLoadString(v, 3, pIdx->zName);
            sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
            sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
          }
        }
#endif /* SQLITE_OMIT_BTREECOUNT */
      } 
    }
    {
      static const int iLn = VDBE_OFFSET_LINENO(2);
      static const VdbeOpList endCode[] = {

Changes to src/sqliteInt.h.

1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889

1890
1891
1892
1893
1894
1895
1896
**
** TF_OOOHidden applies to tables or view that have hidden columns that are
** followed by non-hidden columns.  Example:  "CREATE VIRTUAL TABLE x USING
** vtab1(a HIDDEN, b);".  Since "b" is a non-hidden column but "a" is hidden,
** the TF_OOOHidden attribute would apply in this case.  Such tables require
** special handling during INSERT processing.
*/
#define TF_Readonly        0x01    /* Read-only system table */
#define TF_Ephemeral       0x02    /* An ephemeral table */
#define TF_HasPrimaryKey   0x04    /* Table has a primary key */
#define TF_Autoincrement   0x08    /* Integer primary key is autoincrement */
/* available for reuse:    0x10    */
#define TF_WithoutRowid    0x20    /* No rowid.  PRIMARY KEY is the key */
#define TF_NoVisibleRowid  0x40    /* No user-visible "rowid" column */
#define TF_OOOHidden       0x80    /* Out-of-Order hidden columns */



/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/







|
|
|
|
|
|
|
|
>







1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
**
** TF_OOOHidden applies to tables or view that have hidden columns that are
** followed by non-hidden columns.  Example:  "CREATE VIRTUAL TABLE x USING
** vtab1(a HIDDEN, b);".  Since "b" is a non-hidden column but "a" is hidden,
** the TF_OOOHidden attribute would apply in this case.  Such tables require
** special handling during INSERT processing.
*/
#define TF_Readonly        0x0001    /* Read-only system table */
#define TF_Ephemeral       0x0002    /* An ephemeral table */
#define TF_HasPrimaryKey   0x0004    /* Table has a primary key */
#define TF_Autoincrement   0x0008    /* Integer primary key is autoincrement */
/* available for reuse:    0x0010    */
#define TF_WithoutRowid    0x0020    /* No rowid.  PRIMARY KEY is the key */
#define TF_NoVisibleRowid  0x0040    /* No user-visible "rowid" column */
#define TF_OOOHidden       0x0080    /* Out-of-Order hidden columns */
#define TF_HasNotNull      0x0100    /* Contains NOT NULL constraints */


/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/