/ Check-in [0978bac6]
Login

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

Overview
Comment:Make sure the update hook is not invoked for WITHOUT ROWID tables, as the documentation specifies. This bug was found while adding requirements marks, so a few extraneous requirements marks are included in this check-in.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0978bac6b8aee229d7a0d148546f50d380d06a06
User & Date: drh 2013-11-26 23:27:07
Context
2013-11-27
00:45
Add additional test cases and requirements evidence marks for WITHOUT ROWID. check-in: b408d788 user: drh tags: trunk
2013-11-26
23:27
Make sure the update hook is not invoked for WITHOUT ROWID tables, as the documentation specifies. This bug was found while adding requirements marks, so a few extraneous requirements marks are included in this check-in. check-in: 0978bac6 user: drh tags: trunk
22:46
Add requirements test cases for determining when an expression is true and when it is false. check-in: 838654e5 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/resolve.c.

   348    348               if( iCol==pTab->iPKey ){
   349    349                 iCol = -1;
   350    350               }
   351    351               break;
   352    352             }
   353    353           }
   354    354           if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
   355         -          iCol = -1;        /* IMP: R-44911-55124 */
          355  +          /* IMP: R-24309-18625 */
          356  +          /* IMP: R-44911-55124 */
          357  +          iCol = -1;
   356    358           }
   357    359           if( iCol<pTab->nCol ){
   358    360             cnt++;
   359    361             if( iCol<0 ){
   360    362               pExpr->affinity = SQLITE_AFF_INTEGER;
   361    363             }else if( pExpr->iTable==0 ){
   362    364               testcase( iCol==31 );

Changes to src/vdbe.c.

  4105   4105   ** If P4 is not NULL then the P1 cursor must have been positioned
  4106   4106   ** using OP_NotFound prior to invoking this opcode.
  4107   4107   */
  4108   4108   case OP_Delete: {
  4109   4109     i64 iKey;
  4110   4110     VdbeCursor *pC;
  4111   4111   
  4112         -  iKey = 0;
  4113   4112     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4114   4113     pC = p->apCsr[pOp->p1];
  4115   4114     assert( pC!=0 );
  4116   4115     assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
  4117         -
  4118         -  /* If the update-hook will be invoked, set iKey to the rowid of the
  4119         -  ** row being deleted.
  4120         -  */
  4121         -  if( db->xUpdateCallback && pOp->p4.z ){
  4122         -    assert( pC->isTable );
  4123         -    assert( pC->rowidIsValid );  /* lastRowid set by previous OP_NotFound */
  4124         -    iKey = pC->lastRowid;
  4125         -  }
         4116  +  iKey = pC->lastRowid;      /* Only used for the update hook */
  4126   4117   
  4127   4118     /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
  4128   4119     ** OP_Column on the same table without any intervening operations that
  4129   4120     ** might move or invalidate the cursor.  Hence cursor pC is always pointing
  4130   4121     ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
  4131   4122     ** below is always a no-op and cannot fail.  We will run it anyhow, though,
  4132   4123     ** to guard against future changes to the code generator.
................................................................................
  4136   4127     if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
  4137   4128   
  4138   4129     sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
  4139   4130     rc = sqlite3BtreeDelete(pC->pCursor);
  4140   4131     pC->cacheStatus = CACHE_STALE;
  4141   4132   
  4142   4133     /* Invoke the update-hook if required. */
  4143         -  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
         4134  +  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
  4144   4135       const char *zDb = db->aDb[pC->iDb].zName;
  4145   4136       const char *zTbl = pOp->p4.z;
  4146   4137       db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
  4147   4138       assert( pC->iDb>=0 );
  4148   4139     }
  4149   4140     if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
  4150   4141     break;

Changes to test/e_createtable.test.

  1650   1650   # Tests for INTEGER PRIMARY KEY and rowid related statements.
  1651   1651   #
  1652   1652   
  1653   1653   # EVIDENCE-OF: R-52584-04009 The rowid value can be accessed using one
  1654   1654   # of the special case-independent names "rowid", "oid", or "_rowid_" in
  1655   1655   # place of a column name.
  1656   1656   #
         1657  +# EVIDENCE-OF: R-06726-07466 A column name can be any of the names
         1658  +# defined in the CREATE TABLE statement or one of the following special
         1659  +# identifiers: "ROWID", "OID", or "_ROWID_".
         1660  +#
  1657   1661   drop_all_tables
  1658   1662   do_execsql_test 5.1.0 {
  1659   1663     CREATE TABLE t1(x, y);
  1660   1664     INSERT INTO t1 VALUES('one', 'first');
  1661   1665     INSERT INTO t1 VALUES('two', 'second');
  1662   1666     INSERT INTO t1 VALUES('three', 'third');
  1663   1667   }
................................................................................
  1673   1677     9   "SELECT _RoWiD_ FROM t1"      {1 2 3}
  1674   1678   }
  1675   1679   
  1676   1680   # EVIDENCE-OF: R-26501-17306 If a table contains a user defined column
  1677   1681   # named "rowid", "oid" or "_rowid_", then that name always refers the
  1678   1682   # explicitly declared column and cannot be used to retrieve the integer
  1679   1683   # rowid value.
         1684  +#
         1685  +# EVIDENCE-OF: R-44615-33286 The special identifiers only refer to the
         1686  +# row key if the CREATE TABLE statement does not define a real column
         1687  +# with the same name.
  1680   1688   #
  1681   1689   do_execsql_test 5.2.0 {
  1682   1690     CREATE TABLE t2(oid, b);
  1683   1691     CREATE TABLE t3(a, _rowid_);
  1684   1692     CREATE TABLE t4(a, b, rowid);
  1685   1693   
  1686   1694     INSERT INTO t2 VALUES('one', 'two');

Changes to test/hook.test.

   131    131   # Simple tests
   132    132   do_test hook-4.1.1 {
   133    133     catchsql {
   134    134       DROP TABLE t1;
   135    135     }
   136    136     execsql {
   137    137       CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
          138  +    CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID;
   138    139       INSERT INTO t1 VALUES(1, 'one');
   139    140       INSERT INTO t1 VALUES(2, 'two');
   140    141       INSERT INTO t1 VALUES(3, 'three');
          142  +    INSERT INTO t1w SELECT * FROM t1;
   141    143     }
   142    144     db update_hook [list lappend ::update_hook]
   143    145   } {}
   144    146   do_test hook-4.1.2 {
   145    147     execsql {
   146    148       INSERT INTO t1 VALUES(4, 'four');
   147    149       DELETE FROM t1 WHERE b = 'two';
................................................................................
   154    156       DELETE main t1 2 \
   155    157       UPDATE main t1 1 \
   156    158       UPDATE main t1 3 \
   157    159       DELETE main t1 1 \
   158    160       DELETE main t1 3 \
   159    161       DELETE main t1 4 \
   160    162   ]
          163  +
          164  +# EVIDENCE-OF: R-61808-14344 The sqlite3_update_hook() interface does
          165  +# not fire callbacks for changes to a WITHOUT ROWID table.
          166  +#
          167  +do_test hook-4.1.2w {
          168  +  set ::update_hook {}
          169  +  execsql {
          170  +    INSERT INTO t1w VALUES(4, 'four');
          171  +    DELETE FROM t1w WHERE b = 'two';
          172  +    UPDATE t1w SET b = '' WHERE a = 1 OR a = 3;
          173  +    DELETE FROM t1w WHERE 1; -- Avoid the truncate optimization (for now)
          174  +  }
          175  +  set ::update_hook
          176  +} {}
   161    177   
   162    178   ifcapable trigger {
   163    179     # Update hook is not invoked for changes to sqlite_master
   164    180     #
   165    181     do_test hook-4.1.3 {
   166    182       set ::update_hook {}
   167    183       execsql {