/ Check-in [0d4fea74]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Continue working to get UPDATE operational for WITHOUT ROWID tables. Fix PRAGMA integrity_check so that it works on WITHOUT ROWID tables.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | omit-rowid
Files: files | file ages | folders
SHA1: 0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54
User & Date: drh 2013-10-30 20:22:55
Context
2013-10-31
11:15
Refactor the INSERT, DELETE, and UPDATE code generators to distinguish between the "data cursor" and the "first index cursor", which are no longer consecutive in the case of a WITHOUT ROWID table. check-in: 1adfca60 user: drh tags: omit-rowid
2013-10-30
20:22
Continue working to get UPDATE operational for WITHOUT ROWID tables. Fix PRAGMA integrity_check so that it works on WITHOUT ROWID tables. check-in: 0d4fea74 user: drh tags: omit-rowid
15:52
Make sure KeyInfo objects on multi-column indices of WITHOUT ROWID tables have the correct nField and nXField values. Also, add the SQLITE_ENABLE_MODULE_COMMENT compile-time option and the VdbeModuleComment() macro and use it to label entry and exit points of some key routines. check-in: 6d9af606 user: drh tags: omit-rowid
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/delete.c.

600
601
602
603
604
605
606



607
608
609
610
611
612
613
614
615
    sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
  }

  /* Delete the index and table entries. Skip this step if pTab is really
  ** a view (in which case the only effect of the DELETE statement is to
  ** fire the INSTEAD OF triggers).  */ 
  if( pTab->pSelect==0 ){



    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
    sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
    if( count ){
      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
    }
  }

  /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
  ** handle rows (possibly in other tables) that refer via a foreign key







>
>
>
|
|







600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
    sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
  }

  /* Delete the index and table entries. Skip this step if pTab is really
  ** a view (in which case the only effect of the DELETE statement is to
  ** fire the INSTEAD OF triggers).  */ 
  if( pTab->pSelect==0 ){
    Index *pPk;
    int iMainCur;
    sqlite3PrincipleBtree(pTab, iCur, &pPk, &iMainCur);
    sqlite3GenerateRowIndexDelete(pParse, pTab, iMainCur, 0);
    sqlite3VdbeAddOp2(v, OP_Delete, iMainCur, (count?OPFLAG_NCHANGE:0));
    if( count ){
      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
    }
  }

  /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
  ** handle rows (possibly in other tables) that refer via a foreign key

Changes to src/insert.c.

1155
1156
1157
1158
1159
1160
1161


































1162
1163
1164
1165
1166
1167
1168
....
1259
1260
1261
1262
1263
1264
1265

1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
....
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
....
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
....
1506
1507
1508
1509
1510
1511
1512

1513
1514
1515
1516
1517
1518
1519

1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
....
1571
1572
1573
1574
1575
1576
1577
1578



1579
1580


1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
....
1675
1676
1677
1678
1679
1680
1681

1682



1683
1684
1685
1686
1687
1688
1689
  for(i=0; i<nKeyCol; i++){
    int x = pPk->aiColumn[i];
    sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, regFirst+x, regPk+i);
  }
  return regPk;
}




































/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE.
**
** The input is a range of consecutive registers as follows:
**
**    1.  The rowid of the row after the update, or NULL
................................................................................
  Index *pIdx;         /* Pointer to one of the indices */
  Index *pPk = 0;      /* The PRIMARY KEY index */
  sqlite3 *db;         /* Database connection */
  int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
  int regOldPk;        /* Previous rowid or PRIMARY KEY value */
  int regNewPk = 0;    /* New PRIMARY KEY value */
  int pkCur = 0;       /* Cursor used by the PRIMARY KEY */


  regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
  db = pParse->db;
  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;
  regData = regRowid + 1;
  VdbeModuleComment((v, "BEGIN: GenerateConstraintChecks(%d,%d,%d)",
                     baseCur, regRowid, pkChng));

  /* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
  ** number for the PRIMARY KEY index */
  if( !HasRowid(pTab) ){
    assert( pkChng==0 || isUpdate!=0 );
    pkCur = baseCur+1;
    pPk = pTab->pIndex;
    while( ALWAYS(pPk) && pPk->autoIndex!=2 ){
      pPk=pPk->pNext;
      pkCur++;
    }
  }

  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      continue;
    }
................................................................................

  /* If there is an INTEGER PRIMARY KEY, make sure the primary key
  ** of the new record does not previously exist.  Except, if this
  ** is an UPDATE and the primary key is not changing, that is OK.
  **
  ** This block only runs for tables that have a rowid.
  */
  if( pkChng && pkCur==0 ){
    int addrRowidOk = sqlite3VdbeMakeLabel(v);

    onError = pTab->keyConf;
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
................................................................................
    }
    if( seenReplace ){
      if( onError==OE_Ignore ) onError = OE_Replace;
      else if( onError==OE_Fail ) onError = OE_Abort;
    }
    
    /* Check to see if the new index entry will be unique */
    regR = sqlite3GetTempReg(pParse);
    sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk,
                         regIdx, pIdx->nKeyCol);
#if 0
    if( !isUpdate ){
      /* A pre-existing row is always a conflict on an insert */
    }else
#endif
................................................................................
      sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR);
      sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
    }else if( pIdx->autoIndex==2 ){
      /* For PRIMARY KEY index on a WITHOUT ROWID table, conflict only
      ** if the PRIMARY KEY has changed.  If the PRIMARY KEY is unchanged,
      ** then the matching entry is just the original row that is being
      ** modified. */

      int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
      for(i=0; i<pPk->nKeyCol-1; i++){
        sqlite3VdbeAddOp3(v, OP_Ne,
                          regOldPk+pPk->aiColumn[i], addrPkConflict, regIdx+i);
      }
      sqlite3VdbeAddOp3(v, OP_Eq,
                        regOldPk+pPk->aiColumn[i], addrUniqueOk, regIdx+i);

    }else{
      /* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
      ** PRIMARY KEY value of the match is different from the old PRIMARY KEY
      ** value from before the update. */
      int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol*2;
      assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
      for(i=0; i<pPk->nKeyCol-1; i++){
        sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR);
        sqlite3VdbeAddOp3(v, OP_Ne,
                          regOldPk+pPk->aiColumn[i], addrConflict, regR);
      }
      sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR);
      sqlite3VdbeAddOp3(v, OP_Eq,
                        regOldPk+pPk->aiColumn[i], addrUniqueOk, regR);
    }
    sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);

    /* Generate code that executes if the new index entry is not unique */
    assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
        || onError==OE_Ignore || onError==OE_Replace );
    switch( onError ){
................................................................................
      default: {
        Trigger *pTrigger = 0;
        assert( onError==OE_Replace );
        sqlite3MultiWrite(pParse);
        if( db->flags&SQLITE_RecTriggers ){
          pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
        }
        sqlite3GenerateRowDelete(



            pParse, pTab, pTrigger, baseCur, regR, 0, 0, OE_Replace
        );


        seenReplace = 1;
        break;
      }
    }
    sqlite3VdbeResolveLabel(v, addrUniqueOk);
    sqlite3ReleaseTempReg(pParse, regR);
  }
  
  if( pbMayReplace ){
    *pbMayReplace = seenReplace;
  }
  VdbeModuleComment((v, "END: GenerateConstraintChecks()"));
}

/*
** This routine generates code to finish the INSERT or UPDATE operation
** that was started by a prior call to sqlite3GenerateConstraintChecks.
** A consecutive range of registers starting at regRowid contains the
** rowid and the content to be inserted.
................................................................................
  Index *pIdx;
  Vdbe *v;

  if( IsVirtual(pTab) ) return 0;
  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );

  sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);



  for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
    int iCur = (pkCur>=0 && pIdx->autoIndex==2) ? pkCur : i+baseCur;
    assert( pIdx->pSchema==pTab->pSchema );
    sqlite3VdbeAddOp4(v, op, iCur, pIdx->tnum, iDb,
                      (char*)pKey, P4_KEYINFO_HANDOFF);
    VdbeComment((v, "%s", pIdx->zName));







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>








<
<



|
|
|
|
|
|
<
<
<







 







|







 







|







 







>
|
|
|
|
|
|
|
>







|

|

|

|







 







|
>
>
>
|
<
>
>











|







 







>
|
>
>
>







1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
....
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308


1309
1310
1311
1312
1313
1314
1315
1316
1317



1318
1319
1320
1321
1322
1323
1324
....
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
....
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
....
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
....
1603
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
1633
1634
1635
....
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
  for(i=0; i<nKeyCol; i++){
    int x = pPk->aiColumn[i];
    sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, regFirst+x, regPk+i);
  }
  return regPk;
}

/*
** Locate the "principle btree" for a table.  This is the table itself for
** ordinary tables, but for WITHOUT ROWID tables, the principle btree is the
** PRIMARY KEY index.
**
** Inputs are pTab and baseCur.  The *ppPk is written with a pointer to the
** PRIMARY KEY index for WITHOUT ROWID tables or with NULL for ordinary
** tables.  The *piPkCur is written with the cursor to use, assuming that the
** table cursor is baseCur and that index cursors are consecutively numbered
** thereafter.
*/
void sqlite3PrincipleBtree(
  Table *pTab,        /* The main Table object */
  int baseCur,        /* VDBE cursor for main table. */
  Index **ppPk,       /* Write PRIMARY KEY index of WITHOUT ROWID tables here */
  int *piPkCur        /* Either baseCur or the cursor for *ppPk */
){
  int pkCur;
  Index *pPk;
  if( !HasRowid(pTab) ){
    pkCur = baseCur+1;
    pPk = pTab->pIndex;
    while( ALWAYS(pPk) && pPk->autoIndex!=2 ){
      pPk=pPk->pNext;
      pkCur++;
    }
  }else{
    pkCur = baseCur;
    pPk = 0;
  }
  *ppPk = pPk;
  *piPkCur = pkCur;
}


/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE.
**
** The input is a range of consecutive registers as follows:
**
**    1.  The rowid of the row after the update, or NULL
................................................................................
  Index *pIdx;         /* Pointer to one of the indices */
  Index *pPk = 0;      /* The PRIMARY KEY index */
  sqlite3 *db;         /* Database connection */
  int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
  int regOldPk;        /* Previous rowid or PRIMARY KEY value */
  int regNewPk = 0;    /* New PRIMARY KEY value */
  int pkCur = 0;       /* Cursor used by the PRIMARY KEY */
  int nPkField;        /* Number of fields in PRIMARY KEY. 1 for ROWID tables */

  regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
  db = pParse->db;
  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;
  regData = regRowid + 1;



  /* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
  ** number for the PRIMARY KEY index */
  sqlite3PrincipleBtree(pTab, baseCur, &pPk, &pkCur);
  nPkField = pPk ? pPk->nKeyCol : 1;

  /* Record that this module has started */
  VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
                     baseCur, regRowid, pkChng, regOldPk, pkCur));




  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      continue;
    }
................................................................................

  /* If there is an INTEGER PRIMARY KEY, make sure the primary key
  ** of the new record does not previously exist.  Except, if this
  ** is an UPDATE and the primary key is not changing, that is OK.
  **
  ** This block only runs for tables that have a rowid.
  */
  if( pkChng && pPk==0 ){
    int addrRowidOk = sqlite3VdbeMakeLabel(v);

    onError = pTab->keyConf;
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
................................................................................
    }
    if( seenReplace ){
      if( onError==OE_Ignore ) onError = OE_Replace;
      else if( onError==OE_Fail ) onError = OE_Abort;
    }
    
    /* Check to see if the new index entry will be unique */
    regR = sqlite3GetTempRange(pParse, nPkField);
    sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk,
                         regIdx, pIdx->nKeyCol);
#if 0
    if( !isUpdate ){
      /* A pre-existing row is always a conflict on an insert */
    }else
#endif
................................................................................
      sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR);
      sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
    }else if( pIdx->autoIndex==2 ){
      /* For PRIMARY KEY index on a WITHOUT ROWID table, conflict only
      ** if the PRIMARY KEY has changed.  If the PRIMARY KEY is unchanged,
      ** then the matching entry is just the original row that is being
      ** modified. */
      if( onError!=OE_Replace ){
        int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
        for(i=0; i<pPk->nKeyCol-1; i++){
          sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1,
                            addrPkConflict, regIdx+i);
        }
        sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
                          addrUniqueOk, regIdx+i);
      }
    }else{
      /* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
      ** PRIMARY KEY value of the match is different from the old PRIMARY KEY
      ** value from before the update. */
      int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol*2;
      assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
      for(i=0; i<pPk->nKeyCol-1; i++){
        sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
        sqlite3VdbeAddOp3(v, OP_Ne,
                          regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
      }
      sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
      sqlite3VdbeAddOp3(v, OP_Eq,
                        regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
    }
    sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);

    /* Generate code that executes if the new index entry is not unique */
    assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
        || onError==OE_Ignore || onError==OE_Replace );
    switch( onError ){
................................................................................
      default: {
        Trigger *pTrigger = 0;
        assert( onError==OE_Replace );
        sqlite3MultiWrite(pParse);
        if( db->flags&SQLITE_RecTriggers ){
          pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
        }
        if( pIdx==pPk ){
          /*sqlite3VdbeAddOp3(v, OP_IdxDelete, pkCur, regIdx, pIdx->nColumn);*/
          sqlite3VdbeAddOp1(v, OP_Delete, pkCur);
        }else{
          sqlite3GenerateRowDelete(pParse, pTab, pTrigger, baseCur, 

                                   regR, nPkField, 0, OE_Replace);
        }
        seenReplace = 1;
        break;
      }
    }
    sqlite3VdbeResolveLabel(v, addrUniqueOk);
    sqlite3ReleaseTempReg(pParse, regR);
  }
  
  if( pbMayReplace ){
    *pbMayReplace = seenReplace;
  }
  VdbeModuleComment((v, "END: GenCnstCks()"));
}

/*
** This routine generates code to finish the INSERT or UPDATE operation
** that was started by a prior call to sqlite3GenerateConstraintChecks.
** A consecutive range of registers starting at regRowid contains the
** rowid and the content to be inserted.
................................................................................
  Index *pIdx;
  Vdbe *v;

  if( IsVirtual(pTab) ) return 0;
  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  if( pkCur<0 ){
    sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
  }else{
    sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
  }
  for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
    int iCur = (pkCur>=0 && pIdx->autoIndex==2) ? pkCur : i+baseCur;
    assert( pIdx->pSchema==pTab->pSchema );
    sqlite3VdbeAddOp4(v, op, iCur, pIdx->tnum, iDb,
                      (char*)pKey, P4_KEYINFO_HANDOFF);
    VdbeComment((v, "%s", pIdx->zName));

Changes to src/pragma.c.

1842
1843
1844
1845
1846
1847
1848

1849
1850

1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
....
1869
1870
1871
1872
1873
1874
1875
1876
1877

1878
1879


1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922

1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
      ** for all tables and indices in the database.
      */
      assert( sqlite3SchemaMutexHeld(db, i, 0) );
      pTbls = &db->aDb[i].pSchema->tblHash;
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx;

        sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
        cnt++;

        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
          cnt++;
        }
      }

      /* Make sure sufficient number of registers have been allocated */
      pParse->nMem = MAX( pParse->nMem, cnt+7 );

      /* Do the b-tree integrity checks */
      sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
      sqlite3VdbeChangeP5(v, (u8)i);
      addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
      sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
................................................................................
      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;
        int loopTop;


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


        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
        sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
        sqlite3VdbeJumpHere(v, addr);
        sqlite3ExprCacheClear(pParse);
        sqlite3OpenTableAndIndices(pParse, pTab, 1, -1, OP_OpenRead);
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          sqlite3VdbeAddOp2(v, OP_Integer, 0, 7+j); /* index entries counter */
        }
        pParse->nMem = MAX(pParse->nMem, 7+j);
        loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0) + 1;
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          int jmp2, jmp3;
          int r1;
          static const VdbeOpList idxErr[] = {
            { OP_AddImm,      1, -1,  0},
            { OP_String8,     0,  3,  0},    /* 1 */
            { OP_Rowid,       1,  4,  0},
            { OP_String8,     0,  5,  0},    /* 3 */
            { OP_String8,     0,  6,  0},    /* 4 */
            { OP_Concat,      4,  3,  3},
            { OP_Concat,      5,  3,  3},
            { OP_Concat,      6,  3,  3},
            { OP_ResultRow,   3,  1,  0},
            { OP_IfPos,       1,  0,  0},    /* 9 */
            { OP_Halt,        0,  0,  0},
          };
          r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 0, 0, &jmp3);
          sqlite3VdbeAddOp2(v, OP_AddImm, 7+j, 1);  /* increment entry count */
          jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nKeyCol+1);
          addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
          sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
          sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
          sqlite3VdbeChangeP4(v, addr+4, pIdx->zName, P4_TRANSIENT);
          sqlite3VdbeJumpHere(v, addr+9);
          sqlite3VdbeJumpHere(v, jmp2);
          sqlite3VdbeResolveLabel(v, jmp3);
        }
        sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop);
        sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, 
                     "wrong # of entries in index ", P4_STATIC);
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){

          addr = sqlite3VdbeCurrentAddr(v);
          sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2);
          sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
          sqlite3VdbeAddOp2(v, OP_Count, j+2, 3);
          sqlite3VdbeAddOp3(v, OP_Eq, 7+j, addr+8, 3);
          sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
          sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
          sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
        }
#endif /* SQLITE_OMIT_BTREECOUNT */
      } 







>
|
|
>







|







 







|

>


>
>




|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<









>




|







1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
....
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915



1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
      ** for all tables and indices in the database.
      */
      assert( sqlite3SchemaMutexHeld(db, i, 0) );
      pTbls = &db->aDb[i].pSchema->tblHash;
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx;
        if( HasRowid(pTab) ){
          sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
          cnt++;
        }
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
          cnt++;
        }
      }

      /* Make sure sufficient number of registers have been allocated */
      pParse->nMem = MAX( pParse->nMem, cnt+8 );

      /* Do the b-tree integrity checks */
      sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
      sqlite3VdbeChangeP5(v, (u8)i);
      addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
      sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
         sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
................................................................................
      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;
        int loopTop;
        int pkCur;

        if( pTab->pIndex==0 ) continue;
        sqlite3PrincipleBtree(pTab, 1, &pPk, &pkCur);
        pkCur = (pPk==0) ? -1 : 1;
        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
        sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
        sqlite3VdbeJumpHere(v, addr);
        sqlite3ExprCacheClear(pParse);
        sqlite3OpenTableAndIndices(pParse, pTab, 1, pkCur, OP_OpenRead);
        sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
        }
        pParse->nMem = MAX(pParse->nMem, 8+j);
        sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
        loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          int jmp2, jmp3, jmp4;
          int r1;
          if( pPk==pIdx ) continue;
          r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 0, 0, &jmp3);
          sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);  /* increment entry count */
          jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nKeyCol+1);
          sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
          sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ",
                            P4_STATIC);
          sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT);
          sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
          sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
          jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
          sqlite3VdbeAddOp0(v, OP_Halt);
          sqlite3VdbeJumpHere(v, jmp4);



          sqlite3VdbeJumpHere(v, jmp2);
          sqlite3VdbeResolveLabel(v, jmp3);
        }
        sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop);
        sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, 
                     "wrong # of entries in index ", P4_STATIC);
        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);
          sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
          sqlite3VdbeAddOp2(v, OP_Count, j+2, 3);
          sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3);
          sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
          sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
          sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
        }
#endif /* SQLITE_OMIT_BTREECOUNT */
      } 

Changes to src/sqliteInt.h.

1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
....
2918
2919
2920
2921
2922
2923
2924

2925
2926
2927
2928
2929
2930
2931
** are nField slots for the columns of an index then one extra slot
** for the rowid at the end.
*/
struct KeyInfo {
  sqlite3 *db;        /* The database connection */
  u8 enc;             /* Text encoding - one of the SQLITE_UTF* values */
  u16 nField;         /* Number of key columns in the index */
  u16 nXField;         /* Number of columns beyond the key columns */
  u8 *aSortOrder;     /* Sort order for each column. */
  CollSeq *aColl[1];  /* Collating sequence for each term of the key */
};

/*
** An instance of the following structure holds information about a
** single index record that has already been parsed out into individual
................................................................................
int sqlite3ExprCanBeNull(const Expr*);
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
int sqlite3IsRowid(const char*);
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,i16,u8,u8);
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);

void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
                                     int*,int,int,int,int,int*);
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
void sqlite3MultiWrite(Parse*);
void sqlite3MayAbort(Parse*);







|







 







>







1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
....
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
** are nField slots for the columns of an index then one extra slot
** for the rowid at the end.
*/
struct KeyInfo {
  sqlite3 *db;        /* The database connection */
  u8 enc;             /* Text encoding - one of the SQLITE_UTF* values */
  u16 nField;         /* Number of key columns in the index */
  u16 nXField;        /* Number of columns beyond the key columns */
  u8 *aSortOrder;     /* Sort order for each column. */
  CollSeq *aColl[1];  /* Collating sequence for each term of the key */
};

/*
** An instance of the following structure holds information about a
** single index record that has already been parsed out into individual
................................................................................
int sqlite3ExprCanBeNull(const Expr*);
void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
int sqlite3IsRowid(const char*);
void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,i16,u8,u8);
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
void sqlite3PrincipleBtree(Table*,int,Index**,int*);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
                                     int*,int,int,int,int,int*);
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
void sqlite3MultiWrite(Parse*);
void sqlite3MayAbort(Parse*);

Changes to src/update.c.

98
99
100
101
102
103
104

105
106
107
108
109
110
111
...
181
182
183
184
185
186
187
188




189
190
191
192
193
194
195
...
527
528
529
530
531
532
533



534
535

536
537
538
539
540
541
542
  int addr = 0;          /* VDBE instruction address of the start of the loop */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Vdbe *v;               /* The virtual database engine */
  Index *pIdx;           /* For looping over indices */
  Index *pPk;            /* The PRIMARY KEY index for WITHOUT ROWID tables */
  int nIdx;              /* Number of indices that need updating */
  int iCur;              /* VDBE Cursor number of pTab */

  sqlite3 *db;           /* The database structure */
  int *aRegIdx = 0;      /* One register assigned to each index to be updated */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRowid;         /* True if the record number is being changed */
  int chngPk;            /* The PRIMARY KEY of a WITHOUT ROWID table changed */
................................................................................
  ** need to occur right after the database cursor.  So go ahead and
  ** allocate enough space, just in case.
  */
  pTabList->a[0].iCursor = iCur = pParse->nTab++;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }
  pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);





  /* Initialize the name-context */
  memset(&sNC, 0, sizeof(sNC));
  sNC.pParse = pParse;
  sNC.pSrcList = pTabList;

  /* Resolve the column names in all the expressions of the
................................................................................

    /* Do FK constraint checks. */
    if( hasFK ){
      sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngRowid);
    }

    /* Delete the index entries associated with the current record.  */



    j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);

  
    /* If changing the record number, delete the old record.  */
    if( hasFK || chngRowid ){
      sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
    }
    sqlite3VdbeJumpHere(v, j1);








>







 







<
>
>
>
>







 







>
>
>
|
|
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196
197
198
199
...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  int addr = 0;          /* VDBE instruction address of the start of the loop */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Vdbe *v;               /* The virtual database engine */
  Index *pIdx;           /* For looping over indices */
  Index *pPk;            /* The PRIMARY KEY index for WITHOUT ROWID tables */
  int nIdx;              /* Number of indices that need updating */
  int iCur;              /* VDBE Cursor number of pTab */
  int pkCur;             /* VDBE Cursor for the pPk index */
  sqlite3 *db;           /* The database structure */
  int *aRegIdx = 0;      /* One register assigned to each index to be updated */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRowid;         /* True if the record number is being changed */
  int chngPk;            /* The PRIMARY KEY of a WITHOUT ROWID table changed */
................................................................................
  ** need to occur right after the database cursor.  So go ahead and
  ** allocate enough space, just in case.
  */
  pTabList->a[0].iCursor = iCur = pParse->nTab++;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }


  /* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
  ** number for the PRIMARY KEY index */
  sqlite3PrincipleBtree(pTab, iCur, &pPk, &pkCur);

  /* Initialize the name-context */
  memset(&sNC, 0, sizeof(sNC));
  sNC.pParse = pParse;
  sNC.pSrcList = pTabList;

  /* Resolve the column names in all the expressions of the
................................................................................

    /* Do FK constraint checks. */
    if( hasFK ){
      sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngRowid);
    }

    /* Delete the index entries associated with the current record.  */
    if( pPk ){
      /*j1 = sqlite3VdbeAddOp3(v, OP_NotFound, pkCur, */
    }else{
      j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
      sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
    }
  
    /* If changing the record number, delete the old record.  */
    if( hasFK || chngRowid ){
      sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
    }
    sqlite3VdbeJumpHere(v, j1);

Changes to src/vdbe.c.

3730
3731
3732
3733
3734
3735
3736



3737



3738
3739
3740
3741
3742
3743
3744

    assert( pC->isTable==0 );
    if( pOp->p4.i>0 ){
      r.pKeyInfo = pC->pKeyInfo;
      r.nField = (u16)pOp->p4.i;
      r.aMem = pIn3;
#ifdef SQLITE_DEBUG



      { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }



#endif
      r.flags = UNPACKED_PREFIX_MATCH;
      pIdxKey = &r;
    }else{
      pIdxKey = sqlite3VdbeAllocUnpackedRecord(
          pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
      ); 







>
>
>
|
>
>
>







3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750

    assert( pC->isTable==0 );
    if( pOp->p4.i>0 ){
      r.pKeyInfo = pC->pKeyInfo;
      r.nField = (u16)pOp->p4.i;
      r.aMem = pIn3;
#ifdef SQLITE_DEBUG
      {
        int i;
        for(i=0; i<r.nField; i++){
          assert( memIsValid(&r.aMem[i]) );
          if( i ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
        }
      }
#endif
      r.flags = UNPACKED_PREFIX_MATCH;
      pIdxKey = &r;
    }else{
      pIdxKey = sqlite3VdbeAllocUnpackedRecord(
          pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
      ); 

Changes to test/e_reindex.test.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
} {}

db close
sqlite3 db test.db
do_execsql_test e_reindex-1.3 {
  PRAGMA integrity_check;
} [list \
  {rowid 4 missing from index i2} \
  {rowid 4 missing from index i1} \
  {rowid 5 missing from index i2} \
  {rowid 5 missing from index i1} \
  {wrong # of entries in index i2} \
  {wrong # of entries in index i1}
]

do_execsql_test e_reindex-1.4 {
  REINDEX;
  PRAGMA integrity_check;







|
|
|
|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
} {}

db close
sqlite3 db test.db
do_execsql_test e_reindex-1.3 {
  PRAGMA integrity_check;
} [list \
  {row 3 missing from index i2} \
  {row 3 missing from index i1} \
  {row 4 missing from index i2} \
  {row 4 missing from index i1} \
  {wrong # of entries in index i2} \
  {wrong # of entries in index i1}
]

do_execsql_test e_reindex-1.4 {
  REINDEX;
  PRAGMA integrity_check;

Changes to test/pragma.test.

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
      # make the index appear to be empty.
      #
      set offset [expr {$pgsz*($rootpage-1)}]
      hexio_write test.db $offset 0a00000000040000000000
      db close
      sqlite3 db test.db
      execsql {PRAGMA integrity_check}
    } {{rowid 1 missing from index i2} {rowid 2 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} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {rowid 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.5 {
      execsql {
        PRAGMA integrity_check=4
      }
    } {{rowid 1 missing from index i2} {rowid 2 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} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {rowid 2 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} {rowid 2 missing from index i2} {wrong # of entries in index i2} {rowid 1 missing from index i2} {rowid 2 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}
      forcedelete testerr.db testerr.db-journal
................................................................................
      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} {rowid 2 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} {rowid 2 missing from 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
................................................................................
      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} {rowid 2 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} {rowid 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.16 {
      execsql {
        PRAGMA integrity_check(10)
      }
    } {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 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=8
      }
    } {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {rowid 1 missing from index i2} {rowid 2 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.19 {
    catch {db close}
    forcedelete test.db test.db-journal
    sqlite3 db test.db
    db eval {PRAGMA integrity_check}
  } {ok}







|


|





|




|




|




|







 







|













|







|







 







|


|







|


|







|









|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
      # make the index appear to be empty.
      #
      set offset [expr {$pgsz*($rootpage-1)}]
      hexio_write test.db $offset 0a00000000040000000000
      db close
      sqlite3 db test.db
      execsql {PRAGMA integrity_check}
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.3 {
      execsql {PRAGMA integrity_check=1}
    } {{row 1 missing from index i2}}
    do_test pragma-3.4 {
      execsql {
        ATTACH DATABASE 'test.db' AS t2;
        PRAGMA integrity_check
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.5 {
      execsql {
        PRAGMA integrity_check=4
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}}
    do_test pragma-3.6 {
      execsql {
        PRAGMA integrity_check=xyz
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.7 {
      execsql {
        PRAGMA integrity_check=0
      }
    } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 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}
      forcedelete testerr.db testerr.db-journal
................................................................................
      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} {row 1 missing from index i2} {row 2 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} {row 1 missing from index i2} {row 2 missing from 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} {row 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
................................................................................
      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} {row 1 missing from index i2} {row 2 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} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
    do_test pragma-3.16 {
      execsql {
        PRAGMA integrity_check(10)
      }
    } {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {row 1 missing from index i2} {row 2 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} {row 1 missing from index i2}}
    do_test pragma-3.17 {
      execsql {
        PRAGMA integrity_check=8
      }
    } {{*** in database t2 ***
Page 4 is never used
Page 5 is never used
Page 6 is never used} {row 1 missing from index i2} {row 2 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} {row 1 missing from index i2}}
  }
  do_test pragma-3.19 {
    catch {db close}
    forcedelete test.db test.db-journal
    sqlite3 db test.db
    db eval {PRAGMA integrity_check}
  } {ok}

Added test/without_rowid1.test.





































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 2013-10-30
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements regression tests for SQLite library.  The
# focus of this file is testing WITHOUT ROWID tables.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create and query a WITHOUT ROWID table.
#
do_execsql_test without_rowid1-1.0 {
  CREATE TABLE t1(a,b,c,d, PRIMARY KEY(c,a)) WITHOUT ROWID;
  CREATE INDEX t1bd ON t1(b, d);
  INSERT INTO t1 VALUES('journal','sherman','ammonia','helena');
  INSERT INTO t1 VALUES('dynamic','juliet','flipper','command');
  INSERT INTO t1 VALUES('journal','sherman','gamma','patriot');
  INSERT INTO t1 VALUES('arctic','sleep','ammonia','helena');
  SELECT *, '|' FROM t1 ORDER BY c, a;
} {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |}

integrity_check without_rowid1-1.0ic

do_execsql_test without_rowid1-1.1 {
  SELECT *, '|' FROM t1 ORDER BY +c, a;
} {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |}

do_execsql_test without_rowid1-1.2 {
  SELECT *, '|' FROM t1 ORDER BY c DESC, a DESC;
} {journal sherman gamma patriot | dynamic juliet flipper command | journal sherman ammonia helena | arctic sleep ammonia helena |}

do_execsql_test without_rowid1-1.11 {
  SELECT *, '|' FROM t1 ORDER BY b, d;
} {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |}

do_execsql_test without_rowid1-1.12 {
  SELECT *, '|' FROM t1 ORDER BY +b, d;
} {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |}

if 0 {
# Trying to insert a duplicate PRIMARY KEY fails.
#
do_test without_rowid1-1.21 {
  catchsql {
    INSERT INTO t1 VALUES('dynamic','phone','flipper','harvard');
  }
} {1 {columns c, a are not unique}}

# REPLACE INTO works, however.
#
do_execsql_test without_rowid1-1.22 {
  REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
  SELECT *, '|' FROM t1 ORDER BY c, a;
} {}
}

finish_test