/ Check-in [24d4d5dd]
Login

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

Overview
Comment:Fix a problem with INTEGER PRIMARY KEY columns and the pre-update hook.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1:24d4d5dd007197a141555bcca6f2ac9ab47cde80
User & Date: dan 2011-03-19 08:38:50
Context
2011-03-19
15:37
Fix some bugs in sqlite3changeset_apply(). check-in: 7250318d user: dan tags: sessions
08:38
Fix a problem with INTEGER PRIMARY KEY columns and the pre-update hook. check-in: 24d4d5dd user: dan tags: sessions
02:37
Merge the fix to ticket [f7b4edece25c99485] into the sessions branch. check-in: 1b736ac2 user: drh tags: sessions
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

install-sh became a regular file.

Changes to src/delete.c.

538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  ** be invoked unless table pTab is a system table. The difference is that
  ** the update-hook is not invoked for rows removed by REPLACE, but the 
  ** pre-update-hook is.
  */ 
  if( pTab->pSelect==0 ){
    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
    sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
    sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
  }

  /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
  ** handle rows (possibly in other tables) that refer via a foreign key
  ** to the row just deleted. */ 
  sqlite3FkActions(pParse, pTab, 0, iOld);








|







538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  ** be invoked unless table pTab is a system table. The difference is that
  ** the update-hook is not invoked for rows removed by REPLACE, but the 
  ** pre-update-hook is.
  */ 
  if( pTab->pSelect==0 ){
    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
    sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
    sqlite3VdbeChangeP4(v, -1, pTab, P4_TABLE);
  }

  /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
  ** handle rows (possibly in other tables) that refer via a foreign key
  ** to the row just deleted. */ 
  sqlite3FkActions(pParse, pTab, 0, iOld);

Changes to src/insert.c.

1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
....
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
....
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
          );
        }else{
          /* This OP_Delete opcode fires the pre-update-hook only. It does
          ** not modify the b-tree. It is more efficient to let the coming
          ** OP_Insert replace the existing entry than it is to delete the
          ** existing entry and then insert a new one. */
          sqlite3VdbeAddOp2(v, OP_Delete, baseCur, OPFLAG_ISNOOP);
          sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
          if( pTab->pIndex ){
            sqlite3MultiWrite(pParse);
            sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
          }
        }
        seenReplace = 1;
        break;
................................................................................
    pik_flags |= OPFLAG_APPEND;
  }
  if( useSeekResult ){
    pik_flags |= OPFLAG_USESEEKRESULT;
  }
  sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
  if( !pParse->nested ){
    sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
  }
  sqlite3VdbeChangeP5(v, pik_flags);
}

/*
** Generate code that will open cursors for a table and for all
** indices of that table.  The "baseCur" parameter is the cursor number used
................................................................................
  }else{
    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
    assert( (pDest->tabFlags & TF_Autoincrement)==0 );
  }
  sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
  sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
  sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
  sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
  sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
  for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
    for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
      if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
    }
    assert( pSrcIdx );
    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);







|







 







|







 







|







1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
....
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
....
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
          );
        }else{
          /* This OP_Delete opcode fires the pre-update-hook only. It does
          ** not modify the b-tree. It is more efficient to let the coming
          ** OP_Insert replace the existing entry than it is to delete the
          ** existing entry and then insert a new one. */
          sqlite3VdbeAddOp2(v, OP_Delete, baseCur, OPFLAG_ISNOOP);
          sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
          if( pTab->pIndex ){
            sqlite3MultiWrite(pParse);
            sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
          }
        }
        seenReplace = 1;
        break;
................................................................................
    pik_flags |= OPFLAG_APPEND;
  }
  if( useSeekResult ){
    pik_flags |= OPFLAG_USESEEKRESULT;
  }
  sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
  if( !pParse->nested ){
    sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
  }
  sqlite3VdbeChangeP5(v, pik_flags);
}

/*
** Generate code that will open cursors for a table and for all
** indices of that table.  The "baseCur" parameter is the cursor number used
................................................................................
  }else{
    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
    assert( (pDest->tabFlags & TF_Autoincrement)==0 );
  }
  sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
  sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
  sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
  sqlite3VdbeChangeP4(v, -1, (char *)pDest, P4_TABLE);
  sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
  for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
    for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
      if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
    }
    assert( pSrcIdx );
    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);

Changes to src/update.c.

499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
    */
    assert( regNew==regNewRowid+1 );
    sqlite3VdbeAddOp3(v, OP_Delete, iCur,
        OPFLAG_ISUPDATE | ((hasFK || chngRowid) ? 0 : OPFLAG_ISNOOP),
        regNewRowid
    );
    if( !pParse->nested ){
      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
    }
    sqlite3VdbeJumpHere(v, j1);

    if( hasFK ){
      sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
    }
  







|







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
    */
    assert( regNew==regNewRowid+1 );
    sqlite3VdbeAddOp3(v, OP_Delete, iCur,
        OPFLAG_ISUPDATE | ((hasFK || chngRowid) ? 0 : OPFLAG_ISNOOP),
        regNewRowid
    );
    if( !pParse->nested ){
      sqlite3VdbeChangeP4(v, -1, pTab, P4_TABLE);
    }
    sqlite3VdbeJumpHere(v, j1);

    if( hasFK ){
      sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
    }
  

Changes to src/vdbe.c.

3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
....
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878

3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
....
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
....
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976

3977
3978
3979
3980
3981
3982
3983
....
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
....
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
** that boosts performance by avoiding redundant seeks.
**
** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
** UPDATE operation.  Otherwise (if the flag is clear) then this opcode
** is part of an INSERT operation.  The difference is only important to
** the update hook.
**
** Parameter P4 may point to a string containing the table-name, or
** may be NULL. If it is not NULL, then the update-hook 
** (sqlite3.xUpdateCallback) is invoked following a successful insert.
**
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
** allocated, then ownership of P2 is transferred to the pseudo-cursor
** and register P2 becomes ephemeral.  If the cursor is changed, the
** value of register P2 will then change.  Make sure this does not
** cause any problems.)
**
................................................................................
  Mem *pData;       /* MEM cell holding data for the record to be inserted */
  Mem *pKey;        /* MEM cell holding key  for the record */
  i64 iKey;         /* The integer ROWID or key for the record to be inserted */
  VdbeCursor *pC;   /* Cursor to table into which insert is written */
  int nZero;        /* Number of zero-bytes to append */
  int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
  const char *zDb;  /* database name - used by the update hook */
  const char *zTbl; /* Table name - used by the opdate hook */
  int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */

  pData = &aMem[pOp->p2];
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( memIsValid(pData) );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );
  assert( pC->pseudoTableReg==0 );
  assert( pC->isTable );

  REGISTER_TRACE(pOp->p2, pData);

  if( pOp->opcode==OP_Insert ){
    pKey = &aMem[pOp->p3];
    assert( pKey->flags & MEM_Int );
    assert( memIsValid(pKey) );
    REGISTER_TRACE(pOp->p3, pKey);
    iKey = pKey->u.i;
  }else{
    assert( pOp->opcode==OP_InsertInt );
    iKey = pOp->p3;
  }

  if( pOp->p4.z && (db->xPreUpdateCallback || db->xUpdateCallback) ){
    assert( pC->isTable );
    assert( pC->iDb>=0 );
    zDb = db->aDb[pC->iDb].zName;
    zTbl = pOp->p4.z;
    op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
  }

  /* Invoke the pre-update hook, if any */
  if( db->xPreUpdateCallback 
   && pOp->p4.z 
   && (!(pOp->p5 & OPFLAG_ISUPDATE) || pC->rowidIsValid==0)
  ){
    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, zTbl, iKey, pOp->p2);
  }

  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey;
  if( pData->flags & MEM_Null ){
    pData->z = 0;
    pData->n = 0;
................................................................................
  );
  pC->rowidIsValid = 0;
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
    db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
  }
  break;
}

/* Opcode: Delete P1 P2 P3 P4 *
**
** Delete the record at which the P1 cursor is currently pointing.
................................................................................
**
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not).
**
** P1 must not be pseudo-table.  It has to be a real table with
** multiple rows.
**
** If P4 is not NULL then, either the update or pre-update hook, or both,
** may be invoked. The P1 cursor must have been positioned using OP_NotFound 
** prior to invoking this opcode in this case. Specifically, if one is 
** configured, the pre-update hook is invoked if P4 is not NULL. The 
** update-hook is invoked if one is configured, P4 is not NULL, and the 
** OPFLAG_NCHANGE flag is set in P2.
**
** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
** of the memory cell that contains the value that the rowid of the row will
** be set to by the update.
*/
case OP_Delete: {
  i64 iKey;
  VdbeCursor *pC;
  const char *zDb;
  const char *zTbl;
  int opflags;

  opflags = pOp->p2;
  iKey = 0;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */


  /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
  ** OP_Column on the same table without any intervening operations that
  ** might move or invalidate the cursor.  Hence cursor pC is always pointing
  ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
  ** below is always a no-op and cannot fail.  We will run it anyhow, though,
  ** to guard against future changes to the code generator.
................................................................................
  */
  if( pOp->p4.z && (db->xPreUpdateCallback || db->xUpdateCallback) ){
    assert( pC->iDb>=0 );
    assert( pC->isTable );
    assert( pC->rowidIsValid );  /* lastRowid set by previous OP_NotFound */
    iKey = pC->lastRowid;
    zDb = db->aDb[pC->iDb].zName;
    zTbl = pOp->p4.z;
  }

  /* Invoke the pre-update-hook if required. */
  if( db->xPreUpdateCallback && pOp->p4.z ){
    assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
    sqlite3VdbePreUpdateHook(p, pC,
        (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
        zDb, zTbl, iKey,
        pOp->p3
    );
  }

  if( opflags & OPFLAG_ISNOOP ) break;

  sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
................................................................................
  pC->cacheStatus = CACHE_STALE;

  /* Update the change-counter and invoke the update-hook if required. */
  if( opflags & OPFLAG_NCHANGE ){
    p->nChange++;
    assert( pOp->p4.z );
    if( rc==SQLITE_OK && db->xUpdateCallback ){
      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
    }
  }
  break;
}
/* Opcode: ResetCount * * * * *
**
** The value of the change counter is copied to the database handle







|
|
|







 







|










>













|



|





|


|







 







|







 







|
|
|
|
|
|









|








>







 







|







|







 







|







3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
....
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
....
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
....
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
....
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
....
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
** that boosts performance by avoiding redundant seeks.
**
** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
** UPDATE operation.  Otherwise (if the flag is clear) then this opcode
** is part of an INSERT operation.  The difference is only important to
** the update hook.
**
** Parameter P4 may point to a Table structure, or may be NULL. If it is 
** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked 
** following a successful insert.
**
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
** allocated, then ownership of P2 is transferred to the pseudo-cursor
** and register P2 becomes ephemeral.  If the cursor is changed, the
** value of register P2 will then change.  Make sure this does not
** cause any problems.)
**
................................................................................
  Mem *pData;       /* MEM cell holding data for the record to be inserted */
  Mem *pKey;        /* MEM cell holding key  for the record */
  i64 iKey;         /* The integer ROWID or key for the record to be inserted */
  VdbeCursor *pC;   /* Cursor to table into which insert is written */
  int nZero;        /* Number of zero-bytes to append */
  int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
  const char *zDb;  /* database name - used by the update hook */
  Table *pTab;      /* Table structure - used by update and pre-update hooks */
  int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */

  pData = &aMem[pOp->p2];
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( memIsValid(pData) );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );
  assert( pC->pseudoTableReg==0 );
  assert( pC->isTable );
  assert( pOp->p4type==P4_TABLE || pOp->p4type==P4_NOTUSED );
  REGISTER_TRACE(pOp->p2, pData);

  if( pOp->opcode==OP_Insert ){
    pKey = &aMem[pOp->p3];
    assert( pKey->flags & MEM_Int );
    assert( memIsValid(pKey) );
    REGISTER_TRACE(pOp->p3, pKey);
    iKey = pKey->u.i;
  }else{
    assert( pOp->opcode==OP_InsertInt );
    iKey = pOp->p3;
  }

  if( pOp->p4type==P4_TABLE && (db->xPreUpdateCallback||db->xUpdateCallback) ){
    assert( pC->isTable );
    assert( pC->iDb>=0 );
    zDb = db->aDb[pC->iDb].zName;
    pTab = pOp->p4.pTab;
    op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
  }

  /* Invoke the pre-update hook, if any */
  if( db->xPreUpdateCallback 
   && pOp->p4type==P4_TABLE
   && (!(pOp->p5 & OPFLAG_ISUPDATE) || pC->rowidIsValid==0)
  ){
    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, iKey, pOp->p2);
  }

  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey;
  if( pData->flags & MEM_Null ){
    pData->z = 0;
    pData->n = 0;
................................................................................
  );
  pC->rowidIsValid = 0;
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
    db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, iKey);
  }
  break;
}

/* Opcode: Delete P1 P2 P3 P4 *
**
** Delete the record at which the P1 cursor is currently pointing.
................................................................................
**
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not).
**
** P1 must not be pseudo-table.  It has to be a real table with
** multiple rows.
**
** If P4 is not NULL then it points to a Table struture. In this case either 
** the update or pre-update hook, or both, may be invoked. The P1 cursor must
** have been positioned using OP_NotFound prior to invoking this opcode in 
** this case. Specifically, if one is configured, the pre-update hook is 
** invoked if P4 is not NULL. The update-hook is invoked if one is configured, 
** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
**
** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
** of the memory cell that contains the value that the rowid of the row will
** be set to by the update.
*/
case OP_Delete: {
  i64 iKey;
  VdbeCursor *pC;
  const char *zDb;
  Table *pTab;
  int opflags;

  opflags = pOp->p2;
  iKey = 0;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
  assert( pOp->p4type==P4_TABLE || pOp->p4type==P4_NOTUSED );

  /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
  ** OP_Column on the same table without any intervening operations that
  ** might move or invalidate the cursor.  Hence cursor pC is always pointing
  ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
  ** below is always a no-op and cannot fail.  We will run it anyhow, though,
  ** to guard against future changes to the code generator.
................................................................................
  */
  if( pOp->p4.z && (db->xPreUpdateCallback || db->xUpdateCallback) ){
    assert( pC->iDb>=0 );
    assert( pC->isTable );
    assert( pC->rowidIsValid );  /* lastRowid set by previous OP_NotFound */
    iKey = pC->lastRowid;
    zDb = db->aDb[pC->iDb].zName;
    pTab = pOp->p4.pTab;
  }

  /* Invoke the pre-update-hook if required. */
  if( db->xPreUpdateCallback && pOp->p4.z ){
    assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
    sqlite3VdbePreUpdateHook(p, pC,
        (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
        zDb, pTab, iKey,
        pOp->p3
    );
  }

  if( opflags & OPFLAG_ISNOOP ) break;

  sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
................................................................................
  pC->cacheStatus = CACHE_STALE;

  /* Update the change-counter and invoke the update-hook if required. */
  if( opflags & OPFLAG_NCHANGE ){
    p->nChange++;
    assert( pOp->p4.z );
    if( rc==SQLITE_OK && db->xUpdateCallback ){
      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,iKey);
    }
  }
  break;
}
/* Opcode: ResetCount * * * * *
**
** The value of the change counter is copied to the database handle

Changes to src/vdbe.h.

57
58
59
60
61
62
63

64
65
66
67
68
69
70
...
112
113
114
115
116
117
118

119
120
121
122
123
124
125
    VdbeFunc *pVdbeFunc;   /* Used when p4type is P4_VDBEFUNC */
    CollSeq *pColl;        /* Used when p4type is P4_COLLSEQ */
    Mem *pMem;             /* Used when p4type is P4_MEM */
    VTable *pVtab;         /* Used when p4type is P4_VTAB */
    KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    int *ai;               /* Used when p4type is P4_INTARRAY */
    SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */

  } p4;
#ifdef SQLITE_DEBUG
  char *zComment;          /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
  int cnt;                 /* Number of times this instruction was executed */
  u64 cycles;              /* Total time spent executing this instruction */
................................................................................
#define P4_VTAB     (-10) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_MPRINTF  (-11) /* P4 is a string obtained from sqlite3_mprintf() */
#define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
#define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */


/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made.  That copy is freed when the Vdbe is finalized.  But if the
** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used.  It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc().  But no copy is made and the calling
** function should *not* try to free the KeyInfo.







>







 







>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    VdbeFunc *pVdbeFunc;   /* Used when p4type is P4_VDBEFUNC */
    CollSeq *pColl;        /* Used when p4type is P4_COLLSEQ */
    Mem *pMem;             /* Used when p4type is P4_MEM */
    VTable *pVtab;         /* Used when p4type is P4_VTAB */
    KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    int *ai;               /* Used when p4type is P4_INTARRAY */
    SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
    Table *pTab;           /* Used when p4type is P4_TABLE */
  } p4;
#ifdef SQLITE_DEBUG
  char *zComment;          /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
  int cnt;                 /* Number of times this instruction was executed */
  u64 cycles;              /* Total time spent executing this instruction */
................................................................................
#define P4_VTAB     (-10) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_MPRINTF  (-11) /* P4 is a string obtained from sqlite3_mprintf() */
#define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
#define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
#define P4_TABLE    (-19) /* P4 is a pointer to a Table structure */

/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made.  That copy is freed when the Vdbe is finalized.  But if the
** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used.  It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc().  But no copy is made and the calling
** function should *not* try to free the KeyInfo.

Changes to src/vdbeInt.h.

340
341
342
343
344
345
346



347
348
349
350
351
352
353
...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  VdbeCursor *pCsr;               /* Cursor to read old values from */
  int op;                         /* One of SQLITE_INSERT, UPDATE, DELETE */
  u8 *aRecord;                    /* old.* database record */
  KeyInfo keyinfo;
  UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
  UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
  int iNewReg;                    /* Register for new.* values */



  Mem *aNew;                      /* Array of new.* values */
};

/*
** Function prototypes
*/
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
................................................................................
const char *sqlite3OpcodeName(int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
int sqlite3VdbeCloseStatement(Vdbe *, int);
void sqlite3VdbeFrameDelete(VdbeFrame*);
int sqlite3VdbeFrameRestore(VdbeFrame *);
void sqlite3VdbeMemStoreType(Mem *pMem);
void sqlite3VdbePreUpdateHook(
    Vdbe *, VdbeCursor *, int, const char*, const char*, i64, int);

#ifdef SQLITE_DEBUG
void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
#endif

#ifndef SQLITE_OMIT_FOREIGN_KEY
int sqlite3VdbeCheckFk(Vdbe *, int);







>
>
>







 







|







340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
...
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  VdbeCursor *pCsr;               /* Cursor to read old values from */
  int op;                         /* One of SQLITE_INSERT, UPDATE, DELETE */
  u8 *aRecord;                    /* old.* database record */
  KeyInfo keyinfo;
  UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
  UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
  int iNewReg;                    /* Register for new.* values */
  i64 iKey1;                      /* First key value passed to hook */
  i64 iKey2;                      /* Second key value passed to hook */
  int iPKey;                      /* If not negative index of IPK column */
  Mem *aNew;                      /* Array of new.* values */
};

/*
** Function prototypes
*/
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
................................................................................
const char *sqlite3OpcodeName(int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
int sqlite3VdbeCloseStatement(Vdbe *, int);
void sqlite3VdbeFrameDelete(VdbeFrame*);
int sqlite3VdbeFrameRestore(VdbeFrame *);
void sqlite3VdbeMemStoreType(Mem *pMem);
void sqlite3VdbePreUpdateHook(
    Vdbe *, VdbeCursor *, int, const char*, Table *, i64, int);

#ifdef SQLITE_DEBUG
void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
#endif

#ifndef SQLITE_OMIT_FOREIGN_KEY
int sqlite3VdbeCheckFk(Vdbe *, int);

Changes to src/vdbeapi.c.

1365
1366
1367
1368
1369
1370
1371



1372
1373
1374
1375
1376
1377
1378
....
1419
1420
1421
1422
1423
1424
1425



1426
1427
1428
1429
1430
1431
1432
....
1438
1439
1440
1441
1442
1443
1444



1445
1446

1447
1448
1449
1450
1451
1452
1453
1454
1455
    p->aRecord = aRecord;
  }

  if( iIdx>=p->pUnpacked->nField ){
    *ppValue = (sqlite3_value *)columnNullValue();
  }else{
    *ppValue = &p->pUnpacked->aMem[iIdx];



    sqlite3VdbeMemStoreType(*ppValue);
  }

 preupdate_old_out:
  sqlite3Error(db, rc, 0);
  return sqlite3ApiExit(db, rc);
}
................................................................................
      }
      p->pNewUnpacked = pUnpack;
    }
    if( iIdx>=pUnpack->nField ){
      pMem = (sqlite3_value *)columnNullValue();
    }else{
      pMem = &pUnpack->aMem[iIdx];



      sqlite3VdbeMemStoreType(pMem);
    }
  }else{
    /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
    ** value. Make a copy of the cell contents and return a pointer to it.
    ** It is not safe to return a pointer to the memory cell itself as the
    ** caller may modify the value text encoding.
................................................................................
        rc = SQLITE_NOMEM;
        goto preupdate_new_out;
      }
    }
    assert( iIdx>=0 && iIdx<p->pCsr->nField );
    pMem = &p->aNew[iIdx];
    if( pMem->flags==0 ){



      rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
      if( rc!=SQLITE_OK ) goto preupdate_new_out;

      sqlite3VdbeMemStoreType(pMem);
    }
  }
  *ppValue = pMem;

 preupdate_new_out:
  sqlite3Error(db, rc, 0);
  return sqlite3ApiExit(db, rc);
}







>
>
>







 







>
>
>







 







>
>
>
|
|
>









1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
....
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
....
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
    p->aRecord = aRecord;
  }

  if( iIdx>=p->pUnpacked->nField ){
    *ppValue = (sqlite3_value *)columnNullValue();
  }else{
    *ppValue = &p->pUnpacked->aMem[iIdx];
    if( iIdx==p->iPKey ){
      sqlite3VdbeMemSetInt64(*ppValue, p->iKey1);
    }
    sqlite3VdbeMemStoreType(*ppValue);
  }

 preupdate_old_out:
  sqlite3Error(db, rc, 0);
  return sqlite3ApiExit(db, rc);
}
................................................................................
      }
      p->pNewUnpacked = pUnpack;
    }
    if( iIdx>=pUnpack->nField ){
      pMem = (sqlite3_value *)columnNullValue();
    }else{
      pMem = &pUnpack->aMem[iIdx];
      if( iIdx==p->iPKey ){
        sqlite3VdbeMemSetInt64(pMem, p->iKey2);
      }
      sqlite3VdbeMemStoreType(pMem);
    }
  }else{
    /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
    ** value. Make a copy of the cell contents and return a pointer to it.
    ** It is not safe to return a pointer to the memory cell itself as the
    ** caller may modify the value text encoding.
................................................................................
        rc = SQLITE_NOMEM;
        goto preupdate_new_out;
      }
    }
    assert( iIdx>=0 && iIdx<p->pCsr->nField );
    pMem = &p->aNew[iIdx];
    if( pMem->flags==0 ){
      if( iIdx==p->iPKey ){
        sqlite3VdbeMemSetInt64(pMem, p->iKey2);
      }else{
        rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
        if( rc!=SQLITE_OK ) goto preupdate_new_out;
      }
      sqlite3VdbeMemStoreType(pMem);
    }
  }
  *ppValue = pMem;

 preupdate_new_out:
  sqlite3Error(db, rc, 0);
  return sqlite3ApiExit(db, rc);
}

Changes to src/vdbeaux.c.

3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191

3192
3193
3194
3195
3196
3197
3198
....
3201
3202
3203
3204
3205
3206
3207




3208
3209
3210
3211
3212
3213
3214
** the required value will be read from the row the cursor points to.
*/
void sqlite3VdbePreUpdateHook(
  Vdbe *v,                        /* Vdbe pre-update hook is invoked by */
  VdbeCursor *pCsr,               /* Cursor to grab old.* values from */
  int op,                         /* SQLITE_INSERT, UPDATE or DELETE */
  const char *zDb,                /* Database name */
  const char *zTbl,               /* Table name */
  i64 iKey1,                      /* Initial key value */
  int iReg                        /* Register for new.* record */
){
  sqlite3 *db = v->db;
  i64 iKey2;
  PreUpdate preupdate;


  assert( db->pPreUpdate==0 );
  memset(&preupdate, 0, sizeof(PreUpdate));
  if( op==SQLITE_UPDATE ){
    iKey2 = v->aMem[iReg].u.i;
  }else{
    iKey2 = iKey1;
................................................................................
  preupdate.v = v;
  preupdate.pCsr = pCsr;
  preupdate.op = op;
  preupdate.iNewReg = iReg;
  preupdate.keyinfo.db = db;
  preupdate.keyinfo.enc = ENC(db);
  preupdate.keyinfo.nField = pCsr->nField;




  db->pPreUpdate = &preupdate;
  db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
  db->pPreUpdate = 0;
  sqlite3DbFree(db, preupdate.aRecord);
  if( preupdate.pUnpacked ){
    sqlite3VdbeDeleteUnpackedRecord(preupdate.pUnpacked);
  }







|






>







 







>
>
>
>







3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
....
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
** the required value will be read from the row the cursor points to.
*/
void sqlite3VdbePreUpdateHook(
  Vdbe *v,                        /* Vdbe pre-update hook is invoked by */
  VdbeCursor *pCsr,               /* Cursor to grab old.* values from */
  int op,                         /* SQLITE_INSERT, UPDATE or DELETE */
  const char *zDb,                /* Database name */
  Table *pTab,                    /* Modified table */
  i64 iKey1,                      /* Initial key value */
  int iReg                        /* Register for new.* record */
){
  sqlite3 *db = v->db;
  i64 iKey2;
  PreUpdate preupdate;
  const char *zTbl = pTab->zName;

  assert( db->pPreUpdate==0 );
  memset(&preupdate, 0, sizeof(PreUpdate));
  if( op==SQLITE_UPDATE ){
    iKey2 = v->aMem[iReg].u.i;
  }else{
    iKey2 = iKey1;
................................................................................
  preupdate.v = v;
  preupdate.pCsr = pCsr;
  preupdate.op = op;
  preupdate.iNewReg = iReg;
  preupdate.keyinfo.db = db;
  preupdate.keyinfo.enc = ENC(db);
  preupdate.keyinfo.nField = pCsr->nField;
  preupdate.iKey1 = iKey1;
  preupdate.iKey2 = iKey2;
  preupdate.iPKey = pTab->iPKey;

  db->pPreUpdate = &preupdate;
  db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
  db->pPreUpdate = 0;
  sqlite3DbFree(db, preupdate.aRecord);
  if( preupdate.pUnpacked ){
    sqlite3VdbeDeleteUnpackedRecord(preupdate.pUnpacked);
  }

Changes to test/hook.test.

618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638















639
640
641
do_execsql_test 7.5.2.0 {
  CREATE TABLE t8(a, b);
  INSERT INTO t8 VALUES('one', 'two');
  INSERT INTO t8 VALUES('three', 'four');
  ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx';
}

# At time of writing, these two are broken. They demonstraight that the
# sqlite3_preupdate_old() method does not handle the case where ALTER TABLE
# has been used to add a column with a default value other than NULL.
#
do_preupdate_test 7.5.2.1 {
  DELETE FROM t8 WHERE a = 'one'
} {
  DELETE main t8 1 1   one two xxx
}
do_preupdate_test 7.5.2.2 {
  UPDATE t8 SET b = 'five'
} {
  UPDATE main t8 2 2   three four xxx  three five xxx
}
















finish_test








|













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



618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
do_execsql_test 7.5.2.0 {
  CREATE TABLE t8(a, b);
  INSERT INTO t8 VALUES('one', 'two');
  INSERT INTO t8 VALUES('three', 'four');
  ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx';
}

# At time of writing, these two are broken. They demonstrate that the
# sqlite3_preupdate_old() method does not handle the case where ALTER TABLE
# has been used to add a column with a default value other than NULL.
#
do_preupdate_test 7.5.2.1 {
  DELETE FROM t8 WHERE a = 'one'
} {
  DELETE main t8 1 1   one two xxx
}
do_preupdate_test 7.5.2.2 {
  UPDATE t8 SET b = 'five'
} {
  UPDATE main t8 2 2   three four xxx  three five xxx
}

# This block of tests verifies that IPK values are correctly reported
# by the sqlite3_preupdate_old() and sqlite3_preupdate_new() functions.
#
do_execsql_test 7.6.1 { CREATE TABLE t9(a, b INTEGER PRIMARY KEY, c) }
do_preupdate_test 7.6.2 {
  INSERT INTO t9 VALUES(1, 2, 3);
  UPDATE t9 SET b = b+1, c = c+1;
  DELETE FROM t9 WHERE a = 1;
} {
  INSERT main t9 2 2   1 2 3
  UPDATE main t9 2 3   1 2 3   1 3 4
  DELETE main t9 3 3   1 3 4
}


finish_test

test/progress.test became executable.

tool/mkopts.tcl became executable.