/ Check-in [526545c4]
Login

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

Overview
Comment:Add the sqlite3_preupdate_new() API, for retrieving the new.* values from within a pre-update callback.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 526545c49f64d9063d1b888cfc14ece62fa3c13c
User & Date: dan 2011-03-16 19:59:19
Context
2011-03-17
19:20
Change to the session module to use user-defined primary keys instead of rowids when collecting changes. check-in: 6614cfcb user: dan tags: sessions
2011-03-16
19:59
Add the sqlite3_preupdate_new() API, for retrieving the new.* values from within a pre-update callback. check-in: 526545c4 user: dan tags: sessions
09:49
Remove the sqlite3_transaction_hook() API. check-in: b0015a1c user: dan tags: sessions
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/session/sqlite3session.h.

    11     11   
    12     12   #include "sqlite3.h"
    13     13   
    14     14   typedef struct sqlite3_session sqlite3_session;
    15     15   typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
    16     16   
    17     17   /*
    18         -** Create a session object. This session object will record changes to
    19         -** database zDb attached to connection db.
           18  +** Create a new session object attached to database handle db. If successful,
           19  +** a pointer to the new object is written to *ppSession and SQLITE_OK is
           20  +** returned. If an error occurs, *ppSession is set to NULL and an SQLite
           21  +** error code (e.g. [SQLITE_NOMEM]) is returned.
           22  +**
           23  +** It is possible to create multiple session objects attached to a single
           24  +** database handle.
           25  +**
           26  +** Session objects created using this function should be deleted using the
           27  +** [sqlite3session_delete()] function before the database handle that they
           28  +** are attached to is itself closed. If the database handle is closed before
           29  +** the session object is deleted, then the results of calling any session
           30  +** module function, including [sqlite3session_delete()] on the session object
           31  +** are undefined.
           32  +**
           33  +** Because the session module uses the [sqlite3_preupdate_hook()] API, it
           34  +** is not possible for an application to register a pre-update hook on a
           35  +** database handle that has one or more session objects attached. Nor is
           36  +** it possible to create a session object attached to a database handle for
           37  +** which a pre-update hook is already defined. The results of attempting 
           38  +** either of these things are undefined.
           39  +**
           40  +** The session object will be used to create changesets for tables in
           41  +** database zDb, where zDb is either "main", or "temp", or the name of an
           42  +** attached database. It is not an error if database zDb does not exist
           43  +** to the database when the session object is created.
    20     44   */
    21     45   int sqlite3session_create(
    22     46     sqlite3 *db,                    /* Database handle */
    23     47     const char *zDb,                /* Name of db (e.g. "main") */
    24     48     sqlite3_session **ppSession     /* OUT: New session object */
    25     49   );
    26     50   
           51  +/*
           52  +** Delete a session object previously allocated using 
           53  +** [sqlite3session_create()]. Once a session object has been deleted, the
           54  +** results of attempting to use pSession with any other session module
           55  +** function are undefined.
           56  +**
           57  +** Session objects must be deleted before the database handle to which they
           58  +** are attached is closed. Refer to the documentation for 
           59  +** [sqlite3session_create()] for details.
           60  +*/
           61  +void sqlite3session_delete(sqlite3_session *pSession);
           62  +
    27     63   /*
    28     64   ** Enable or disable the recording of changes by a session object. When
    29     65   ** enabled, a session object records changes made to the database. When
    30     66   ** disabled - it does not. A newly created session object is enabled.
    31     67   **
    32     68   ** Passing zero to this function disables the session. Passing a value
    33     69   ** greater than zero enables it. Passing a value less than zero is a 
................................................................................
    48     84   */
    49     85   int sqlite3session_attach(
    50     86     sqlite3_session *pSession,      /* Session object */
    51     87     const char *zTab                /* Table name */
    52     88   );
    53     89   
    54     90   /*
    55         -** Obtain a changeset object containing all changes recorded by the 
    56         -** session object passed as the first argument.
           91  +** Obtain a changeset containing changes to the tables attached to the 
           92  +** session object passed as the first argument. If successful, 
           93  +** set *ppChangeset to point to a buffer containing the changeset 
           94  +** and *pnChangeset to the size of the changeset in bytes before returning
           95  +** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
           96  +** zero and return an SQLite error code.
    57     97   **
    58         -** It is the responsibility of the caller to eventually free the buffer 
    59         -** using sqlite3_free().
           98  +** Following a successful call to this function, it is the responsibility of
           99  +** the caller to eventually free the buffer that *ppChangeset points to using
          100  +** [sqlite3_free()].
    60    101   */
    61    102   int sqlite3session_changeset(
    62    103     sqlite3_session *pSession,      /* Session object */
    63    104     int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
    64    105     void **ppChangeset              /* OUT: Buffer containing changeset */
    65    106   );
    66    107   
    67         -/*
    68         -** Delete a session object previously allocated using sqlite3session_create().
    69         -*/
    70         -void sqlite3session_delete(sqlite3_session *pSession);
    71         -
    72    108   /*
    73    109   ** Create an iterator used to iterate through the contents of a changeset.
    74    110   */
    75    111   int sqlite3changeset_start(
    76    112     sqlite3_changeset_iter **ppIter,
    77    113     int nChangeset, 
    78    114     void *pChangeset

Changes to src/sqlite.h.in.

  6362   6362       char const *zName,            /* Table name */
  6363   6363       sqlite3_int64 iKey1,          /* Rowid of row about to be deleted/updated */
  6364   6364       sqlite3_int64 iKey2           /* New rowid value (for a rowid UPDATE) */
  6365   6365     ),
  6366   6366     void*
  6367   6367   );
  6368   6368   SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
  6369         -SQLITE_EXPERIMENTAL int sqlite3_preupdate_modified(sqlite3 *, int, int *);
  6370   6369   SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
         6370  +SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
  6371   6371   
  6372   6372   /*
  6373   6373   ** Undo the hack that converts floating point types to integer for
  6374   6374   ** builds on processors without floating point support.
  6375   6375   */
  6376   6376   #ifdef SQLITE_OMIT_FLOATING_POINT
  6377   6377   # undef double
  6378   6378   #endif
  6379   6379   
  6380   6380   #ifdef __cplusplus
  6381   6381   }  /* End of the 'extern "C"' block */
  6382   6382   #endif
  6383   6383   #endif

Changes to src/tclsqlite.c.

  2842   2842         }
  2843   2843       }
  2844   2844   #endif
  2845   2845       break;
  2846   2846     }
  2847   2847   
  2848   2848     case DB_PREUPDATE: {
  2849         -    static const char *azSub[] = {"count", "hook", "modified", "old", 0};
         2849  +    static const char *azSub[] = {"count", "hook", "new", "old", 0};
  2850   2850       enum DbPreupdateSubCmd {
  2851         -      PRE_COUNT, PRE_HOOK, PRE_MODIFIED, PRE_OLD
         2851  +      PRE_COUNT, PRE_HOOK, PRE_NEW, PRE_OLD
  2852   2852       };
  2853   2853       int iSub;
  2854   2854   
  2855   2855       if( objc<3 ){
  2856   2856         Tcl_WrongNumArgs(interp, 2, objv, "SUB-COMMAND ?ARGS?");
  2857   2857       }
  2858   2858       if( Tcl_GetIndexFromObj(interp, objv[2], azSub, "sub-command", 0, &iSub) ){
................................................................................
  2871   2871             Tcl_WrongNumArgs(interp, 2, objv, "hook ?SCRIPT?");
  2872   2872             return TCL_ERROR;
  2873   2873           }
  2874   2874           DbHookCmd(interp, pDb, (objc==4 ? objv[3] : 0), &pDb->pPreUpdateHook);
  2875   2875           break;
  2876   2876         }
  2877   2877   
  2878         -      case PRE_MODIFIED:
         2878  +      case PRE_NEW:
  2879   2879         case PRE_OLD: {
  2880   2880           int iIdx;
         2881  +        sqlite3_value *pValue;
  2881   2882           if( objc!=4 ){
  2882   2883             Tcl_WrongNumArgs(interp, 3, objv, "INDEX");
  2883   2884             return TCL_ERROR;
  2884   2885           }
  2885   2886           if( Tcl_GetIntFromObj(interp, objv[3], &iIdx) ){
  2886   2887             return TCL_ERROR;
  2887   2888           }
  2888   2889   
  2889         -        if( iSub==PRE_MODIFIED ){
  2890         -          int iRes;
  2891         -          rc = sqlite3_preupdate_modified(pDb->db, iIdx, &iRes);
  2892         -          if( rc==SQLITE_OK ) Tcl_SetObjResult(interp, Tcl_NewIntObj(iRes));
         2890  +        if( iSub==PRE_OLD ){
         2891  +          rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue);
  2893   2892           }else{
  2894         -          sqlite3_value *pValue;
  2895         -          assert( iSub==PRE_OLD );
  2896         -          rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue);
  2897         -          if( rc==SQLITE_OK ){
  2898         -            Tcl_Obj *pObj = Tcl_NewStringObj(sqlite3_value_text(pValue), -1);
  2899         -            Tcl_SetObjResult(interp, pObj);
  2900         -          }
         2893  +          assert( iSub==PRE_NEW );
         2894  +          rc = sqlite3_preupdate_new(pDb->db, iIdx, &pValue);
  2901   2895           }
  2902   2896   
  2903         -        if( rc!=SQLITE_OK ){
         2897  +        if( rc==SQLITE_OK ){
         2898  +          Tcl_Obj *pObj = Tcl_NewStringObj(sqlite3_value_text(pValue), -1);
         2899  +          Tcl_SetObjResult(interp, pObj);
         2900  +        }else{
  2904   2901             Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
  2905   2902             return TCL_ERROR;
  2906   2903           }
  2907   2904         }
  2908   2905       }
  2909   2906   
  2910   2907       break;

Changes to src/update.c.

   489    489       /* Delete the index entries associated with the current record.  */
   490    490       j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
   491    491       sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
   492    492     
   493    493       /* If changing the rowid value, or if there are foreign key constraints
   494    494       ** to process, delete the old record. Otherwise, add a noop OP_Delete
   495    495       ** to invoke the pre-update hook.
          496  +    **
          497  +    ** That (regNew==regnewRowid+1) is true is also important for the 
          498  +    ** pre-update hook. If hte caller invokes preupdate_new(), the returned
          499  +    ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
          500  +    ** is the column index supplied by the user.
   496    501       */
          502  +    assert( regNew==regNewRowid+1 );
   497    503       sqlite3VdbeAddOp3(v, OP_Delete, iCur,
   498    504           OPFLAG_ISUPDATE | ((hasFK || chngRowid) ? 0 : OPFLAG_ISNOOP),
   499    505           regNewRowid
   500    506       );
   501    507       if( !pParse->nested ){
   502    508         sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
   503    509       }

Changes to src/vdbe.c.

  3877   3877     }
  3878   3878   
  3879   3879     /* Invoke the pre-update hook, if any */
  3880   3880     if( db->xPreUpdateCallback 
  3881   3881      && pOp->p4.z 
  3882   3882      && (!(pOp->p5 & OPFLAG_ISUPDATE) || pC->rowidIsValid==0)
  3883   3883     ){
  3884         -    sqlite3VdbePreUpdateHook(p, pC,
  3885         -      pC->rowidIsValid ? op : SQLITE_INSERT, zDb, zTbl, iKey, iKey
  3886         -    );
         3884  +    sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, zTbl, iKey, pOp->p2);
  3887   3885     }
  3888   3886   
  3889   3887     if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  3890   3888     if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey;
  3891   3889     if( pData->flags & MEM_Null ){
  3892   3890       pData->z = 0;
  3893   3891       pData->n = 0;
................................................................................
  3981   3979   
  3982   3980     /* Invoke the pre-update-hook if required. */
  3983   3981     if( db->xPreUpdateCallback && pOp->p4.z ){
  3984   3982       assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
  3985   3983       sqlite3VdbePreUpdateHook(p, pC,
  3986   3984           (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, 
  3987   3985           zDb, zTbl, iKey,
  3988         -        (opflags & OPFLAG_ISUPDATE) ? aMem[pOp->p3].u.i : iKey
         3986  +        pOp->p3
  3989   3987       );
  3990   3988     }
  3991   3989   
  3992   3990     if( opflags & OPFLAG_ISNOOP ) break;
  3993   3991   
  3994   3992     sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
  3995   3993     rc = sqlite3BtreeDelete(pC->pCursor);

Changes to src/vdbeInt.h.

   332    332   #define VDBE_MAGIC_DEAD     0xb606c3c8    /* The VDBE has been deallocated */
   333    333   
   334    334   /*
   335    335   ** Structure used to store the context required by the 
   336    336   ** sqlite3_preupdate_*() API functions.
   337    337   */
   338    338   struct PreUpdate {
          339  +  Vdbe *v;
   339    340     VdbeCursor *pCsr;               /* Cursor to read old values from */
   340    341     int op;                         /* One of SQLITE_INSERT, UPDATE, DELETE */
   341    342     u8 *aRecord;                    /* old.* database record */
   342    343     KeyInfo keyinfo;
   343    344     UnpackedRecord *pUnpacked;      /* Unpacked version of aRecord[] */
          345  +  UnpackedRecord *pNewUnpacked;   /* Unpacked version of new.* record */
          346  +  int iNewReg;                    /* Register for new.* values */
          347  +  Mem *aNew;                      /* Array of new.* values */
   344    348   };
   345    349   
   346    350   /*
   347    351   ** Function prototypes
   348    352   */
   349    353   void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
   350    354   void sqliteVdbePopStack(Vdbe*,int);
................................................................................
   396    400   const char *sqlite3OpcodeName(int);
   397    401   int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
   398    402   int sqlite3VdbeCloseStatement(Vdbe *, int);
   399    403   void sqlite3VdbeFrameDelete(VdbeFrame*);
   400    404   int sqlite3VdbeFrameRestore(VdbeFrame *);
   401    405   void sqlite3VdbeMemStoreType(Mem *pMem);
   402    406   void sqlite3VdbePreUpdateHook(
   403         -    Vdbe *, VdbeCursor *, int, const char*, const char*, i64, i64);
          407  +    Vdbe *, VdbeCursor *, int, const char*, const char*, i64, int);
   404    408   
   405    409   #ifdef SQLITE_DEBUG
   406    410   void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
   407    411   #endif
   408    412   
   409    413   #ifndef SQLITE_OMIT_FOREIGN_KEY
   410    414   int sqlite3VdbeCheckFk(Vdbe *, int);

Changes to src/vdbeapi.c.

  1325   1325   int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
  1326   1326     Vdbe *pVdbe = (Vdbe*)pStmt;
  1327   1327     int v = pVdbe->aCounter[op-1];
  1328   1328     if( resetFlag ) pVdbe->aCounter[op-1] = 0;
  1329   1329     return v;
  1330   1330   }
  1331   1331   
         1332  +/*
         1333  +** This function is called from within a pre-update callback to retrieve
         1334  +** a field of the row currently being updated or deleted.
         1335  +*/
  1332   1336   int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
  1333   1337     PreUpdate *p = db->pPreUpdate;
  1334   1338     int rc = SQLITE_OK;
  1335   1339   
         1340  +  /* Test that this call is being made from within an SQLITE_DELETE or
         1341  +  ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
  1336   1342     if( !p || p->op==SQLITE_INSERT ){
  1337   1343       rc = SQLITE_MISUSE_BKPT;
  1338   1344       goto preupdate_old_out;
  1339   1345     }
  1340   1346     if( iIdx>=p->pCsr->nField || iIdx<0 ){
  1341   1347       rc = SQLITE_RANGE;
  1342   1348       goto preupdate_old_out;
  1343   1349     }
  1344   1350   
         1351  +  /* If the old.* record has not yet been loaded into memory, do so now. */
  1345   1352     if( p->pUnpacked==0 ){
  1346   1353       u32 nRecord;
  1347   1354       u8 *aRecord;
  1348   1355   
  1349   1356       rc = sqlite3BtreeDataSize(p->pCsr->pCursor, &nRecord);
  1350   1357       if( rc!=SQLITE_OK ) goto preupdate_old_out;
  1351   1358       aRecord = sqlite3DbMallocRaw(db, nRecord);
................................................................................
  1368   1375     }
  1369   1376   
  1370   1377    preupdate_old_out:
  1371   1378     sqlite3Error(db, rc, 0);
  1372   1379     return sqlite3ApiExit(db, rc);
  1373   1380   }
  1374   1381   
         1382  +/*
         1383  +** This function is called from within a pre-update callback to retrieve
         1384  +** the number of columns in the row being updated, deleted or inserted.
         1385  +*/
  1375   1386   int sqlite3_preupdate_count(sqlite3 *db){
  1376   1387     PreUpdate *p = db->pPreUpdate;
  1377   1388     return (p ? p->pCsr->nField : 0);
  1378   1389   }
  1379   1390   
  1380         -int sqlite3_preupdate_modified(sqlite3 *db, int iIdx, int *pbMod){
         1391  +/*
         1392  +** This function is called from within a pre-update callback to retrieve
         1393  +** a field of the row currently being updated or inserted.
         1394  +*/
         1395  +int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
  1381   1396     PreUpdate *p = db->pPreUpdate;
  1382   1397     int rc = SQLITE_OK;
         1398  +  Mem *pMem;
  1383   1399   
  1384         -  if( !p || p->op!=SQLITE_UPDATE ){
         1400  +  if( !p || p->op==SQLITE_DELETE ){
  1385   1401       rc = SQLITE_MISUSE_BKPT;
  1386         -    goto preupdate_mod_out;
         1402  +    goto preupdate_new_out;
  1387   1403     }
  1388   1404     if( iIdx>=p->pCsr->nField || iIdx<0 ){
  1389   1405       rc = SQLITE_RANGE;
  1390         -    goto preupdate_mod_out;
         1406  +    goto preupdate_new_out;
         1407  +  }
         1408  +
         1409  +  if( p->op==SQLITE_INSERT ){
         1410  +    /* For an INSERT, memory cell p->iNewReg contains the serialized record
         1411  +    ** that is being inserted. Deserialize it. */
         1412  +    UnpackedRecord *pUnpack = p->pNewUnpacked;
         1413  +    if( !pUnpack ){
         1414  +      Mem *pData = &p->v->aMem[p->iNewReg];
         1415  +      rc = sqlite3VdbeMemExpandBlob(pData);
         1416  +      if( rc!=SQLITE_OK ) goto preupdate_new_out;
         1417  +      pUnpack = sqlite3VdbeRecordUnpack(&p->keyinfo, pData->n, pData->z, 0, 0);
         1418  +      if( !pUnpack ){
         1419  +        rc = SQLITE_NOMEM;
         1420  +        goto preupdate_new_out;
         1421  +      }
         1422  +      p->pNewUnpacked = pUnpack;
         1423  +    }
         1424  +    if( iIdx>=pUnpack->nField ){
         1425  +      pMem = (sqlite3_value *)columnNullValue();
         1426  +    }else{
         1427  +      pMem = &pUnpack->aMem[iIdx];
         1428  +      sqlite3VdbeMemStoreType(pMem);
         1429  +    }
         1430  +  }else{
         1431  +    /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
         1432  +    ** value. Make a copy of the cell contents and return a pointer to it.
         1433  +    ** It is not safe to return a pointer to the memory cell itself as the
         1434  +    ** caller may modify the value text encoding.
         1435  +    */
         1436  +    assert( p->op==SQLITE_UPDATE );
         1437  +    if( !p->aNew ){
         1438  +      p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
         1439  +      if( !p->aNew ){
         1440  +        rc = SQLITE_NOMEM;
         1441  +        goto preupdate_new_out;
         1442  +      }
         1443  +    }
         1444  +    pMem = &p->aNew[iIdx];
         1445  +    if( pMem->flags==0 ){
         1446  +      rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
         1447  +      if( rc!=SQLITE_OK ) goto preupdate_new_out;
         1448  +      sqlite3VdbeMemStoreType(pMem);
         1449  +    }
  1391   1450     }
  1392         -  *pbMod = 1;
         1451  +  *ppValue = pMem;
  1393   1452   
  1394         - preupdate_mod_out:
         1453  + preupdate_new_out:
  1395   1454     sqlite3Error(db, rc, 0);
  1396   1455     return sqlite3ApiExit(db, rc);
  1397   1456   }
  1398   1457   
  1399   1458   

Changes to src/vdbeaux.c.

  3172   3172   void sqlite3VdbePreUpdateHook(
  3173   3173     Vdbe *v,                        /* Vdbe pre-update hook is invoked by */
  3174   3174     VdbeCursor *pCsr,               /* Cursor to grab old.* values from */
  3175   3175     int op,                         /* SQLITE_INSERT, UPDATE or DELETE */
  3176   3176     const char *zDb,                /* Database name */
  3177   3177     const char *zTbl,               /* Table name */
  3178   3178     i64 iKey1,                      /* Initial key value */
  3179         -  i64 iKey2                       /* Final key value */
         3179  +  int iReg                        /* Register for new.* record */
  3180   3180   ){
  3181   3181     sqlite3 *db = v->db;
         3182  +  i64 iKey2;
  3182   3183   
  3183   3184     PreUpdate preupdate;
  3184   3185     memset(&preupdate, 0, sizeof(PreUpdate));
  3185   3186   
         3187  +  if( op==SQLITE_UPDATE ){
         3188  +    iKey2 = v->aMem[iReg].u.i;
         3189  +  }else{
         3190  +    iKey2 = iKey1;
         3191  +  }
         3192  +
         3193  +  preupdate.v = v;
  3186   3194     preupdate.pCsr = pCsr;
  3187   3195     preupdate.op = op;
         3196  +  preupdate.iNewReg = iReg;
  3188   3197     preupdate.keyinfo.db = db;
  3189   3198     preupdate.keyinfo.enc = ENC(db);
  3190   3199     preupdate.keyinfo.nField = pCsr->nField;
  3191   3200     db->pPreUpdate = &preupdate;
  3192   3201     db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
  3193   3202     db->pPreUpdate = 0;
  3194   3203     sqlite3DbFree(db, preupdate.aRecord);
  3195   3204     if( preupdate.pUnpacked ){
  3196   3205       sqlite3VdbeDeleteUnpackedRecord(preupdate.pUnpacked);
  3197   3206     }
         3207  +  if( preupdate.pNewUnpacked ){
         3208  +    sqlite3VdbeDeleteUnpackedRecord(preupdate.pNewUnpacked);
         3209  +  }
         3210  +  if( preupdate.aNew ){
         3211  +    int i;
         3212  +    for(i=0; i<pCsr->nField; i++){
         3213  +      sqlite3VdbeMemRelease(&preupdate.aNew[i]);
         3214  +    }
         3215  +    sqlite3_free(preupdate.aNew);
         3216  +  }
  3198   3217   }
  3199   3218   

Changes to test/hook.test.

   401    401       set ::preupdate
   402    402     "] [list $X]
   403    403   }
   404    404   
   405    405   proc preupdate_hook {args} {
   406    406     set type [lindex $args 0]
   407    407     eval lappend ::preupdate $args
   408         -  if {$type != "SQLITE_INSERT"} {
          408  +  if {$type != "INSERT"} {
   409    409       for {set i 0} {$i < [db preupdate count]} {incr i} {
   410    410         lappend ::preupdate [db preupdate old $i]
   411    411       }
          412  +  }
          413  +  if {$type != "DELETE"} {
          414  +    for {set i 0} {$i < [db preupdate count]} {incr i} {
          415  +      set rc [catch { db preupdate new $i } v]
          416  +      lappend ::preupdate $v
          417  +    }
   412    418     }
   413    419   }
   414    420   
   415    421   db close
   416    422   forcedelete test.db
   417    423   sqlite3 db test.db
   418    424   db preupdate hook preupdate_hook
................................................................................
   429    435     INSERT INTO t3 VALUES(4, 16);
   430    436     INSERT INTO t3 VALUES(5, 25);
   431    437     INSERT INTO t3 VALUES(6, 36);
   432    438   } 
   433    439   
   434    440   do_preupdate_test 7.1.1 {
   435    441     INSERT INTO t1 VALUES('x', 'y')
   436         -} {INSERT main t1 1 1}
          442  +} {INSERT main t1 1 1  x y}
   437    443   
   438    444   # 7.1.2.1 does not use the xfer optimization. 7.1.2.2 does.
   439    445   do_preupdate_test 7.1.2.1 {
   440    446     INSERT INTO t1 SELECT y, x FROM t2;
   441         -} {INSERT main t1 2 2 INSERT main t1 3 3}
          447  +} {INSERT main t1 2 2 b a   INSERT main t1 3 3 d c}
   442    448   do_preupdate_test 7.1.2.2 {
   443    449     INSERT INTO t1 SELECT * FROM t2;
   444         -} {INSERT main t1 4 4 INSERT main t1 5 5}
          450  +} {INSERT main t1 4 4 a b   INSERT main t1 5 5 c d}
   445    451   
   446    452   do_preupdate_test 7.1.3 {
   447    453     REPLACE INTO t1(rowid, a, b) VALUES(1, 1, 1);
   448    454   } {
   449    455     DELETE main t1 1 1   x y
   450         -  INSERT main t1 1 1
          456  +  INSERT main t1 1 1   1 1
   451    457   }
   452    458   
   453    459   do_preupdate_test 7.1.4 {
   454    460     REPLACE INTO t3 VALUES(4, NULL);
   455    461   } {
   456    462     DELETE main t3 1 1   4 16
   457         -  INSERT main t3 4 4
          463  +  INSERT main t3 4 4   4 {}
   458    464   }
   459    465   
   460    466   do_preupdate_test 7.1.5 {
   461    467     REPLACE INTO t3(rowid, i, j) VALUES(2, 6, NULL);
   462    468   } {
   463    469     DELETE main t3 2 2  5 25
   464    470     DELETE main t3 3 3  6 36
   465         -  INSERT main t3 2 2
          471  +  INSERT main t3 2 2  6 {}
   466    472   }
   467    473   
   468    474   do_execsql_test 7.2.0 { SELECT rowid FROM t1 } {1 2 3 4 5}
   469    475   
   470    476   do_preupdate_test 7.2.1 {
   471    477     DELETE FROM t1 WHERE rowid = 3
   472    478   } {
................................................................................
   493    499     INSERT INTO t3 VALUES(5, 25);
   494    500     INSERT INTO t3 VALUES(6, 36);
   495    501   }
   496    502   
   497    503   do_preupdate_test 7.3.1 {
   498    504     UPDATE t2 SET y = y||y;
   499    505   } {
   500         -  UPDATE main t2 1 1   a b
   501         -  UPDATE main t2 2 2   c d
          506  +  UPDATE main t2 1 1   a b  a bb
          507  +  UPDATE main t2 2 2   c d  c dd
   502    508   }
   503    509   
   504    510   do_preupdate_test 7.3.2 {
   505    511     UPDATE t2 SET rowid = rowid-1;
   506    512   } {
   507         -  UPDATE main t2 1 0   a bb
   508         -  UPDATE main t2 2 1   c dd
          513  +  UPDATE main t2 1 0   a bb  a bb
          514  +  UPDATE main t2 2 1   c dd  c dd
   509    515   }
   510    516   
   511    517   do_preupdate_test 7.3.3 {
   512    518     UPDATE OR REPLACE t2 SET rowid = 1 WHERE x = 'a'
   513    519   } {
   514    520     DELETE main t2 1 1   c dd
   515         -  UPDATE main t2 0 1   a bb
          521  +  UPDATE main t2 0 1   a bb  a bb
   516    522   }
   517    523   
   518    524   do_preupdate_test 7.3.4.1 {
   519    525     UPDATE OR REPLACE t3 SET i = 5 WHERE i = 6
   520    526   } {
   521    527     DELETE main t3 2 2   5 25
   522         -  UPDATE main t3 3 3   6 36
          528  +  UPDATE main t3 3 3   6 36  5 36
   523    529   }
   524    530   
   525    531   do_execsql_test 7.3.4.2 {
   526    532     INSERT INTO t3 VALUES(10, 100);
   527    533     SELECT rowid, * FROM t3;
   528    534   } {1 4 16   3 5 36   4 10 100}
   529    535   
   530    536   do_preupdate_test 7.3.5 {
   531    537     UPDATE OR REPLACE t3 SET rowid = 1, i = 5 WHERE j = 100;
   532    538   } {
   533    539     DELETE main t3 1 1    4  16
   534    540     DELETE main t3 3 3    5  36
   535         -  UPDATE main t3 4 1   10 100
          541  +  UPDATE main t3 4 1   10 100  5 100
   536    542   }
   537    543   
   538    544   do_execsql_test 7.4.1.0 {
   539    545     CREATE TABLE t4(a, b);
   540    546     INSERT INTO t4 VALUES('a', 1);
   541    547     INSERT INTO t4 VALUES('b', 2);
   542    548     INSERT INTO t4 VALUES('c', 3);
................................................................................
   573    579       DELETE FROM t5 WHERE b = 1;
   574    580     END;
   575    581   }
   576    582   do_preupdate_test 7.4.2.1 {
   577    583     UPDATE t5 SET b = 4 WHERE a = 'c'
   578    584   } {
   579    585     DELETE main t5 1 1   a 1
   580         -  UPDATE main t5 3 3   c 3
          586  +  UPDATE main t5 3 3   c 3  c 4
   581    587   }
   582    588   
   583    589   do_execsql_test 7.4.2.2 {
   584    590     INSERT INTO t5(rowid, a, b) VALUES(1, 'a', 1);
   585    591   }
   586    592   
   587    593   do_preupdate_test 7.4.2.3 {
................................................................................
   602    608   } {
   603    609     DELETE main t7 1 1   one two {}
   604    610   }
   605    611   
   606    612   do_preupdate_test 7.5.1.2 {
   607    613     UPDATE t7 SET b = 'five'
   608    614   } {
   609         -  UPDATE main t7 2 2   three four {}
          615  +  UPDATE main t7 2 2   three four {}  three five {}
   610    616   }
   611    617   
   612    618   do_execsql_test 7.5.2.0 {
   613    619     CREATE TABLE t8(a, b);
   614    620     INSERT INTO t8 VALUES('one', 'two');
   615    621     INSERT INTO t8 VALUES('three', 'four');
   616    622     ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx';
................................................................................
   624    630     DELETE FROM t8 WHERE a = 'one'
   625    631   } {
   626    632     DELETE main t8 1 1   one two xxx
   627    633   }
   628    634   do_preupdate_test 7.5.2.2 {
   629    635     UPDATE t8 SET b = 'five'
   630    636   } {
   631         -  UPDATE main t8 2 2   three four xxx
          637  +  UPDATE main t8 2 2   three four xxx  three five xxx
   632    638   }
   633    639   
   634    640   finish_test
   635    641