]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3_preupdate_new() API, for retrieving the new.* values from within...
authordan <dan@noemail.net>
Wed, 16 Mar 2011 19:59:18 +0000 (19:59 +0000)
committerdan <dan@noemail.net>
Wed, 16 Mar 2011 19:59:18 +0000 (19:59 +0000)
FossilOrigin-Name: 526545c49f64d9063d1b888cfc14ece62fa3c13c

ext/session/sqlite3session.h
manifest
manifest.uuid
src/sqlite.h.in
src/tclsqlite.c
src/update.c
src/vdbe.c
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
test/hook.test

index c4053e3dbe1adbaaadf8a98b797291293dfadf74..573b2ff3fc750fe3191db41737d46da4206919f1 100644 (file)
@@ -15,8 +15,32 @@ typedef struct sqlite3_session sqlite3_session;
 typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
 
 /*
-** Create a session object. This session object will record changes to
-** database zDb attached to connection db.
+** Create a new session object attached to database handle db. If successful,
+** a pointer to the new object is written to *ppSession and SQLITE_OK is
+** returned. If an error occurs, *ppSession is set to NULL and an SQLite
+** error code (e.g. [SQLITE_NOMEM]) is returned.
+**
+** It is possible to create multiple session objects attached to a single
+** database handle.
+**
+** Session objects created using this function should be deleted using the
+** [sqlite3session_delete()] function before the database handle that they
+** are attached to is itself closed. If the database handle is closed before
+** the session object is deleted, then the results of calling any session
+** module function, including [sqlite3session_delete()] on the session object
+** are undefined.
+**
+** Because the session module uses the [sqlite3_preupdate_hook()] API, it
+** is not possible for an application to register a pre-update hook on a
+** database handle that has one or more session objects attached. Nor is
+** it possible to create a session object attached to a database handle for
+** which a pre-update hook is already defined. The results of attempting 
+** either of these things are undefined.
+**
+** The session object will be used to create changesets for tables in
+** database zDb, where zDb is either "main", or "temp", or the name of an
+** attached database. It is not an error if database zDb does not exist
+** to the database when the session object is created.
 */
 int sqlite3session_create(
   sqlite3 *db,                    /* Database handle */
@@ -24,6 +48,18 @@ int sqlite3session_create(
   sqlite3_session **ppSession     /* OUT: New session object */
 );
 
+/*
+** Delete a session object previously allocated using 
+** [sqlite3session_create()]. Once a session object has been deleted, the
+** results of attempting to use pSession with any other session module
+** function are undefined.
+**
+** Session objects must be deleted before the database handle to which they
+** are attached is closed. Refer to the documentation for 
+** [sqlite3session_create()] for details.
+*/
+void sqlite3session_delete(sqlite3_session *pSession);
+
 /*
 ** Enable or disable the recording of changes by a session object. When
 ** enabled, a session object records changes made to the database. When
@@ -52,11 +88,16 @@ int sqlite3session_attach(
 );
 
 /*
-** Obtain a changeset object containing all changes recorded by the 
-** session object passed as the first argument.
+** Obtain a changeset containing changes to the tables attached to the 
+** session object passed as the first argument. If successful, 
+** set *ppChangeset to point to a buffer containing the changeset 
+** and *pnChangeset to the size of the changeset in bytes before returning
+** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
+** zero and return an SQLite error code.
 **
-** It is the responsibility of the caller to eventually free the buffer 
-** using sqlite3_free().
+** Following a successful call to this function, it is the responsibility of
+** the caller to eventually free the buffer that *ppChangeset points to using
+** [sqlite3_free()].
 */
 int sqlite3session_changeset(
   sqlite3_session *pSession,      /* Session object */
@@ -64,11 +105,6 @@ int sqlite3session_changeset(
   void **ppChangeset              /* OUT: Buffer containing changeset */
 );
 
-/*
-** Delete a session object previously allocated using sqlite3session_create().
-*/
-void sqlite3session_delete(sqlite3_session *pSession);
-
 /*
 ** Create an iterator used to iterate through the contents of a changeset.
 */
index 4061dea4107d3da98dc2b5a294ce86cf27efc200..796df369be00cc9622b9369da56a011bf07ea866 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sthe\ssqlite3_transaction_hook()\sAPI.
-D 2011-03-16T09:49:15
+C Add\sthe\ssqlite3_preupdate_new()\sAPI,\sfor\sretrieving\sthe\snew.*\svalues\sfrom\swithin\sa\spre-update\scallback.
+D 2011-03-16T19:59:19
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -99,7 +99,7 @@ F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F ext/session/sqlite3session.c 9b8d123418c024f6851163375fca99042757772f
-F ext/session/sqlite3session.h 01aac9a1185b7db6716217f3aa3f7a835ab864b9
+F ext/session/sqlite3session.h 63045871564085669b5cb1fb92e6efc2e1b1120a
 F ext/session/test_session.c 2559ef68e421c7fb83e2c19ef08a17343b70d535
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
@@ -180,13 +180,13 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
 F src/select.c d24406c45dd2442eb2eeaac413439066b149c944
 F src/shell.c 649c51979812f77f97507024a4cea480c6862b8b
-F src/sqlite.h.in 8da2897e3c9b251b29aa48d11bfb1f30f1de0733
+F src/sqlite.h.in 992c54d9bd451a041fb0b74fb5cd3b14db98e544
 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
 F src/sqliteInt.h db209477de559911d7f14c1d208cbf2bc46e9224
 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
-F src/tclsqlite.c 0aa7e768b3bd72bf4c4b0312c9a84d6cdedb7638
+F src/tclsqlite.c fc0321c62a3c3929b9b0659b94b7d37bac84e769
 F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290
 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
@@ -228,15 +228,15 @@ F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
 F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852
-F src/update.c 1b9a82ede7df15e76ed86c6a3cbe4ce0f21eaa9b
+F src/update.c 18a862e3e08377a5afb26d6f16182a8f700a1ca7
 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
 F src/util.c ab1c92426494f499f42b9e307537b03e923d75c1
 F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
-F src/vdbe.c 117644088f89c40b01c917d06f7b2ed706ca125f
+F src/vdbe.c fbf11bd681fd2313aaf59fb2fd7f02cd8324a88a
 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
-F src/vdbeInt.h 9dd04435bd5a68e30cd07e7a91c17b062bf1c23d
-F src/vdbeapi.c 256029b0a2ed2373ebbcce7a497b3a702a52689b
-F src/vdbeaux.c f789da7d55231d779c26deaf5a1e6ccb3e550c09
+F src/vdbeInt.h 20d13da932eed0667a2e2383a9cb0f80099a5fd3
+F src/vdbeapi.c 3066456f64fb10c9c5151c684b5f5e8d67a5f4f2
+F src/vdbeaux.c 896844f9bf663202b3afa8c139e2caddcf855765
 F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
 F src/vdbemem.c 0fa2ed786cd207d5b988afef3562a8e663a75b50
 F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
@@ -474,7 +474,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
 F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
-F test/hook.test 85059721ef537317af679aca5435f94ab316d074
+F test/hook.test d0a277022888caf75ae1d4ec79917668f2f0f2e6
 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
 F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d
 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
@@ -913,7 +913,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P f2930840e4af3d7d9cb199d316502932fcbbb867
-R fadac1472cdeb40a0e5c985ec43cbe17
+P b0015a1cfe63c924ee5f250aa08460522882009b
+R 4b62a15aa3feb03b0e54e624839e53a1
 U dan
-Z 22d8aae45d188380f4801c8d2b2db4e1
+Z 0b4af75dcf5347bcbba47251e978ee95
index 2664939330f15149c58d606058597dc7a07f05e6..69c525548648f0ba51245c77782ed1439887a115 100644 (file)
@@ -1 +1 @@
-b0015a1cfe63c924ee5f250aa08460522882009b
\ No newline at end of file
+526545c49f64d9063d1b888cfc14ece62fa3c13c
\ No newline at end of file
index d3c9ac5f24ad45bb90e6000b6e5923638c28a5e6..0f920bd6dd6d4e87b2da3e20d26fe6d851ab784e 100644 (file)
@@ -6366,8 +6366,8 @@ SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
   void*
 );
 SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
-SQLITE_EXPERIMENTAL int sqlite3_preupdate_modified(sqlite3 *, int, int *);
 SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
+SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
 
 /*
 ** Undo the hack that converts floating point types to integer for
index b5ac5faf88c8a3217de71ca87cb7e86f2e634711..b3f98126c04d28d8ed2c1e577256443c3400d0d7 100644 (file)
@@ -2846,9 +2846,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   }
 
   case DB_PREUPDATE: {
-    static const char *azSub[] = {"count", "hook", "modified", "old", 0};
+    static const char *azSub[] = {"count", "hook", "new", "old", 0};
     enum DbPreupdateSubCmd {
-      PRE_COUNT, PRE_HOOK, PRE_MODIFIED, PRE_OLD
+      PRE_COUNT, PRE_HOOK, PRE_NEW, PRE_OLD
     };
     int iSub;
 
@@ -2875,9 +2875,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
         break;
       }
 
-      case PRE_MODIFIED:
+      case PRE_NEW:
       case PRE_OLD: {
         int iIdx;
+        sqlite3_value *pValue;
         if( objc!=4 ){
           Tcl_WrongNumArgs(interp, 3, objv, "INDEX");
           return TCL_ERROR;
@@ -2886,21 +2887,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
           return TCL_ERROR;
         }
 
-        if( iSub==PRE_MODIFIED ){
-          int iRes;
-          rc = sqlite3_preupdate_modified(pDb->db, iIdx, &iRes);
-          if( rc==SQLITE_OK ) Tcl_SetObjResult(interp, Tcl_NewIntObj(iRes));
-        }else{
-          sqlite3_value *pValue;
-          assert( iSub==PRE_OLD );
+        if( iSub==PRE_OLD ){
           rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue);
-          if( rc==SQLITE_OK ){
-            Tcl_Obj *pObj = Tcl_NewStringObj(sqlite3_value_text(pValue), -1);
-            Tcl_SetObjResult(interp, pObj);
-          }
+        }else{
+          assert( iSub==PRE_NEW );
+          rc = sqlite3_preupdate_new(pDb->db, iIdx, &pValue);
         }
 
-        if( rc!=SQLITE_OK ){
+        if( rc==SQLITE_OK ){
+          Tcl_Obj *pObj = Tcl_NewStringObj(sqlite3_value_text(pValue), -1);
+          Tcl_SetObjResult(interp, pObj);
+        }else{
           Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
           return TCL_ERROR;
         }
index ea8f95ad566e864db7583fb2b846d824df72f2f0..4bf4a880b128479fd046016d597a79581490ddca 100644 (file)
@@ -493,7 +493,13 @@ void sqlite3Update(
     /* If changing the rowid value, or if there are foreign key constraints
     ** to process, delete the old record. Otherwise, add a noop OP_Delete
     ** to invoke the pre-update hook.
+    **
+    ** That (regNew==regnewRowid+1) is true is also important for the 
+    ** pre-update hook. If hte caller invokes preupdate_new(), the returned
+    ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
+    ** is the column index supplied by the user.
     */
+    assert( regNew==regNewRowid+1 );
     sqlite3VdbeAddOp3(v, OP_Delete, iCur,
         OPFLAG_ISUPDATE | ((hasFK || chngRowid) ? 0 : OPFLAG_ISNOOP),
         regNewRowid
index 041e93025b9e4f2a8d40cf8428f336d8607b05d9..1ef59d0a39ca90e839514daae63fa6b0691d9a76 100644 (file)
@@ -3881,9 +3881,7 @@ case OP_InsertInt: {
    && pOp->p4.z 
    && (!(pOp->p5 & OPFLAG_ISUPDATE) || pC->rowidIsValid==0)
   ){
-    sqlite3VdbePreUpdateHook(p, pC,
-      pC->rowidIsValid ? op : SQLITE_INSERT, zDb, zTbl, iKey, iKey
-    );
+    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, zTbl, iKey, pOp->p2);
   }
 
   if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
@@ -3985,7 +3983,7 @@ case OP_Delete: {
     sqlite3VdbePreUpdateHook(p, pC,
         (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
         zDb, zTbl, iKey,
-        (opflags & OPFLAG_ISUPDATE) ? aMem[pOp->p3].u.i : iKey
+        pOp->p3
     );
   }
 
index 0b4178aacdeae306e896754d1f8bf9ff4985a7c1..447e025e945e358401855efff1042b3d53e7fba4 100644 (file)
@@ -336,11 +336,15 @@ struct Vdbe {
 ** sqlite3_preupdate_*() API functions.
 */
 struct PreUpdate {
+  Vdbe *v;
   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 */
 };
 
 /*
@@ -400,7 +404,7 @@ void sqlite3VdbeFrameDelete(VdbeFrame*);
 int sqlite3VdbeFrameRestore(VdbeFrame *);
 void sqlite3VdbeMemStoreType(Mem *pMem);
 void sqlite3VdbePreUpdateHook(
-    Vdbe *, VdbeCursor *, int, const char*, const char*, i64, i64);
+    Vdbe *, VdbeCursor *, int, const char*, const char*, i64, int);
 
 #ifdef SQLITE_DEBUG
 void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
index 0d5fd940212914a7ae7c3881d0abb5bcaa3f263b..66f8c0857f77817b2df7b1fcc59128500a7a523f 100644 (file)
@@ -1329,10 +1329,16 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
   return v;
 }
 
+/*
+** This function is called from within a pre-update callback to retrieve
+** a field of the row currently being updated or deleted.
+*/
 int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
   PreUpdate *p = db->pPreUpdate;
   int rc = SQLITE_OK;
 
+  /* Test that this call is being made from within an SQLITE_DELETE or
+  ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
   if( !p || p->op==SQLITE_INSERT ){
     rc = SQLITE_MISUSE_BKPT;
     goto preupdate_old_out;
@@ -1342,6 +1348,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
     goto preupdate_old_out;
   }
 
+  /* If the old.* record has not yet been loaded into memory, do so now. */
   if( p->pUnpacked==0 ){
     u32 nRecord;
     u8 *aRecord;
@@ -1372,26 +1379,78 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
   return sqlite3ApiExit(db, rc);
 }
 
+/*
+** This function is called from within a pre-update callback to retrieve
+** the number of columns in the row being updated, deleted or inserted.
+*/
 int sqlite3_preupdate_count(sqlite3 *db){
   PreUpdate *p = db->pPreUpdate;
   return (p ? p->pCsr->nField : 0);
 }
 
-int sqlite3_preupdate_modified(sqlite3 *db, int iIdx, int *pbMod){
+/*
+** This function is called from within a pre-update callback to retrieve
+** a field of the row currently being updated or inserted.
+*/
+int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
   PreUpdate *p = db->pPreUpdate;
   int rc = SQLITE_OK;
+  Mem *pMem;
 
-  if( !p || p->op!=SQLITE_UPDATE ){
+  if( !p || p->op==SQLITE_DELETE ){
     rc = SQLITE_MISUSE_BKPT;
-    goto preupdate_mod_out;
+    goto preupdate_new_out;
   }
   if( iIdx>=p->pCsr->nField || iIdx<0 ){
     rc = SQLITE_RANGE;
-    goto preupdate_mod_out;
+    goto preupdate_new_out;
+  }
+
+  if( p->op==SQLITE_INSERT ){
+    /* For an INSERT, memory cell p->iNewReg contains the serialized record
+    ** that is being inserted. Deserialize it. */
+    UnpackedRecord *pUnpack = p->pNewUnpacked;
+    if( !pUnpack ){
+      Mem *pData = &p->v->aMem[p->iNewReg];
+      rc = sqlite3VdbeMemExpandBlob(pData);
+      if( rc!=SQLITE_OK ) goto preupdate_new_out;
+      pUnpack = sqlite3VdbeRecordUnpack(&p->keyinfo, pData->n, pData->z, 0, 0);
+      if( !pUnpack ){
+        rc = SQLITE_NOMEM;
+        goto preupdate_new_out;
+      }
+      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.
+    */
+    assert( p->op==SQLITE_UPDATE );
+    if( !p->aNew ){
+      p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
+      if( !p->aNew ){
+        rc = SQLITE_NOMEM;
+        goto preupdate_new_out;
+      }
+    }
+    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);
+    }
   }
-  *pbMod = 1;
+  *ppValue = pMem;
 
- preupdate_mod_out:
+ preupdate_new_out:
   sqlite3Error(db, rc, 0);
   return sqlite3ApiExit(db, rc);
 }
index 1c870c24043cf2fc5709bd377bec6c2aec722af1..974925158582872c900a58b84d79389c4c683d50 100644 (file)
@@ -3176,15 +3176,24 @@ void sqlite3VdbePreUpdateHook(
   const char *zDb,                /* Database name */
   const char *zTbl,               /* Table name */
   i64 iKey1,                      /* Initial key value */
-  i64 iKey2                       /* Final key value */
+  int iReg                        /* Register for new.* record */
 ){
   sqlite3 *db = v->db;
+  i64 iKey2;
 
   PreUpdate preupdate;
   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;
@@ -3195,5 +3204,15 @@ void sqlite3VdbePreUpdateHook(
   if( preupdate.pUnpacked ){
     sqlite3VdbeDeleteUnpackedRecord(preupdate.pUnpacked);
   }
+  if( preupdate.pNewUnpacked ){
+    sqlite3VdbeDeleteUnpackedRecord(preupdate.pNewUnpacked);
+  }
+  if( preupdate.aNew ){
+    int i;
+    for(i=0; i<pCsr->nField; i++){
+      sqlite3VdbeMemRelease(&preupdate.aNew[i]);
+    }
+    sqlite3_free(preupdate.aNew);
+  }
 }
 
index 0ba4b19e40dd207dd1e422cfd52f746a009cd7dd..001e8ddf4a36e86e63dda536a582259ba3549264 100644 (file)
@@ -405,11 +405,17 @@ proc do_preupdate_test {tn sql x} {
 proc preupdate_hook {args} {
   set type [lindex $args 0]
   eval lappend ::preupdate $args
-  if {$type != "SQLITE_INSERT"} {
+  if {$type != "INSERT"} {
     for {set i 0} {$i < [db preupdate count]} {incr i} {
       lappend ::preupdate [db preupdate old $i]
     }
   }
+  if {$type != "DELETE"} {
+    for {set i 0} {$i < [db preupdate count]} {incr i} {
+      set rc [catch { db preupdate new $i } v]
+      lappend ::preupdate $v
+    }
+  }
 }
 
 db close
@@ -433,28 +439,28 @@ do_execsql_test 7.0 {
 
 do_preupdate_test 7.1.1 {
   INSERT INTO t1 VALUES('x', 'y')
-} {INSERT main t1 1 1}
+} {INSERT main t1 1 1  x y}
 
 # 7.1.2.1 does not use the xfer optimization. 7.1.2.2 does.
 do_preupdate_test 7.1.2.1 {
   INSERT INTO t1 SELECT y, x FROM t2;
-} {INSERT main t1 2 2 INSERT main t1 3 3}
+} {INSERT main t1 2 2 b a   INSERT main t1 3 3 d c}
 do_preupdate_test 7.1.2.2 {
   INSERT INTO t1 SELECT * FROM t2;
-} {INSERT main t1 4 4 INSERT main t1 5 5}
+} {INSERT main t1 4 4 a b   INSERT main t1 5 5 c d}
 
 do_preupdate_test 7.1.3 {
   REPLACE INTO t1(rowid, a, b) VALUES(1, 1, 1);
 } {
   DELETE main t1 1 1   x y
-  INSERT main t1 1 1
+  INSERT main t1 1 1   1 1
 }
 
 do_preupdate_test 7.1.4 {
   REPLACE INTO t3 VALUES(4, NULL);
 } {
   DELETE main t3 1 1   4 16
-  INSERT main t3 4 4
+  INSERT main t3 4 4   4 {}
 }
 
 do_preupdate_test 7.1.5 {
@@ -462,7 +468,7 @@ do_preupdate_test 7.1.5 {
 } {
   DELETE main t3 2 2  5 25
   DELETE main t3 3 3  6 36
-  INSERT main t3 2 2
+  INSERT main t3 2 2  6 {}
 }
 
 do_execsql_test 7.2.0 { SELECT rowid FROM t1 } {1 2 3 4 5}
@@ -497,29 +503,29 @@ do_execsql_test 7.3.0 {
 do_preupdate_test 7.3.1 {
   UPDATE t2 SET y = y||y;
 } {
-  UPDATE main t2 1 1   a b
-  UPDATE main t2 2 2   c d
+  UPDATE main t2 1 1   a b  a bb
+  UPDATE main t2 2 2   c d  c dd
 }
 
 do_preupdate_test 7.3.2 {
   UPDATE t2 SET rowid = rowid-1;
 } {
-  UPDATE main t2 1 0   a bb
-  UPDATE main t2 2 1   c dd
+  UPDATE main t2 1 0   a bb  a bb
+  UPDATE main t2 2 1   c dd  c dd
 }
 
 do_preupdate_test 7.3.3 {
   UPDATE OR REPLACE t2 SET rowid = 1 WHERE x = 'a'
 } {
   DELETE main t2 1 1   c dd
-  UPDATE main t2 0 1   a bb
+  UPDATE main t2 0 1   a bb  a bb
 }
 
 do_preupdate_test 7.3.4.1 {
   UPDATE OR REPLACE t3 SET i = 5 WHERE i = 6
 } {
   DELETE main t3 2 2   5 25
-  UPDATE main t3 3 3   6 36
+  UPDATE main t3 3 3   6 36  5 36
 }
 
 do_execsql_test 7.3.4.2 {
@@ -532,7 +538,7 @@ do_preupdate_test 7.3.5 {
 } {
   DELETE main t3 1 1    4  16
   DELETE main t3 3 3    5  36
-  UPDATE main t3 4 1   10 100
+  UPDATE main t3 4 1   10 100  5 100
 }
 
 do_execsql_test 7.4.1.0 {
@@ -577,7 +583,7 @@ do_preupdate_test 7.4.2.1 {
   UPDATE t5 SET b = 4 WHERE a = 'c'
 } {
   DELETE main t5 1 1   a 1
-  UPDATE main t5 3 3   c 3
+  UPDATE main t5 3 3   c 3  c 4
 }
 
 do_execsql_test 7.4.2.2 {
@@ -606,7 +612,7 @@ do_preupdate_test 7.5.1.1 {
 do_preupdate_test 7.5.1.2 {
   UPDATE t7 SET b = 'five'
 } {
-  UPDATE main t7 2 2   three four {}
+  UPDATE main t7 2 2   three four {}  three five {}
 }
 
 do_execsql_test 7.5.2.0 {
@@ -628,7 +634,7 @@ do_preupdate_test 7.5.2.1 {
 do_preupdate_test 7.5.2.2 {
   UPDATE t8 SET b = 'five'
 } {
-  UPDATE main t8 2 2   three four xxx
+  UPDATE main t8 2 2   three four xxx  three five xxx
 }
 
 finish_test