- C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch.
- D 2011-08-26T19:20:47.301
-C Remove\s'const'\sfrom\sa\svariable\sthat\smight\sactually\sbe\swritten\swhen\san\sOOM\serror\soccurs.\sAlso,\sfix\sa\scouple\sMSVC/Win32\scompiler\swarnings.
-D 2011-09-14T18:19:08.529
++C Merge\slatest\schanges\sfrom\sthe\strunk\sinto\sthe\ssessions\sbranch.
++D 2011-09-14T19:41:44.795
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
- F Makefile.in 8c930e7b493d59099ea1304bd0f2aed152eb3315
+ F Makefile.in d314143fa6be24828021d3f583ad37d9afdce505
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
- F Makefile.msc 55fe94bf23b4c1ff035f19b0ae2ea486350f8d01
- F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
+ F Makefile.msc 25da409ce0c7799e57f48a729a8e153b23027adc
+ F Makefile.vxworks 1deb39c8bb047296c30161ffa10c1b5423e632f9
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION f724de7326e87b7f3b0a55f16ef4b4d993680d54
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
+F ext/session/session1.test 502086908e4144dfaccb1baa77bc29d75a9daace
+F ext/session/session2.test 99ca0da7ddb617d42bafd83adccf99f18ae0384b
+F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01
+F ext/session/session4.test a6ed685da7a5293c5d6f99855bcf41dbc352ca84
+F ext/session/session5.test 8fdfaf9dba28a2f1c6b89b06168bdab1fef2d478
+F ext/session/session6.test 443789bc2fca12e4f7075cf692c60b8a2bea1a26
+F ext/session/session8.test 7d35947ad329b8966f095d34f9617a9eff52dc65
+F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5
+F ext/session/sessionfault.test 891453e96630ee2915081487fc4b7226f0aa252f
+F ext/session/sqlite3session.c 57d04e1d6a3579e673e61dea29f214fb4e0fc505
+F ext/session/sqlite3session.h f374c9c4c96e08f67ac418871c29d423245c7673
+F ext/session/test_session.c ea4dc9b4a1895c8e6bddcbfe3838d7eb57df2d99
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
- F main.mk cb6055cd875d73dee78a7f88c04cd49457d8cc9a
-F main.mk 8744cb76517817170f7fd2c78fbf0006fabb93c1
++F main.mk ba82d040a497dc525b96103d007da17ce5baad6d
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
F src/backup.c 28a4fe55327ff708bfaf9d4326d02686f7a553c3
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
- F src/btree.c ed13fdefdbe671d5777773dcfb3a162ddb4623ae
- F src/btree.h 9ddf04226eac592d4cc3709c5a8b33b2351ff5f7
+ F src/btree.c 77b09c69d4849a90361e6fe5db36d167f20600c0
+ F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
- F src/build.c 2d5de52df616a3bf5a659cbca85211c46e2ba9bd
+ F src/build.c 851e81f26a75abbb98bd99a7c5f10e8670d867bb
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
- F src/ctime.c caf51429be3e0d4114056a8273b0fff812ff8ae9
+ F src/ctime.c e3132ec65240b2e2f3d50831021eac387f27584d
F src/date.c a3c6842bad7ae632281811de112a8ba63ff08ab3
-F src/delete.c ff68e5ef23aee08c0ff528f699a19397ed8bbed8
+F src/delete.c 614d6e012aa5b624e78f3b556243497825de196b
- F src/expr.c 4bbdfaf66bc614be9254ce0c26a17429067a3e07
+ F src/expr.c cbcd8c2f1588a9862291a081699854c5e1cb28ab
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 9f00ea98f6b360d477b5a78b5b59a1fbde82431c
F src/func.c 59bb046d7e3df1ab512ac339ccb0a6f996a17cb7
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
- F src/select.c d219c4b68d603cc734b6f9b1e2780fee12a1fa0d
+ F src/select.c bf7b7ea6befb483619da5f597b0864668b828c3c
F src/shell.c bbe7818ff5bc8614105ceb81ad67b8bdc0b671dd
-F src/sqlite.h.in 0a6c9c23337fd1352c5c75a613ff9533aa7d91cb
+F src/sqlite.h.in 355493ac9492746a0bbd17a4fd40911aa89b5a3a
F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
- F src/sqliteInt.h a6f805d591b7b71703eb33dd9cd60ced889b71c6
-F src/sqliteInt.h c7e37ee49b1a922ddcd18fa98dd750efa4d2db14
++F src/sqliteInt.h 68a33c1d88051fae92a9528f198fbcaf3ddb3b39
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
-F src/tclsqlite.c 3ef1dda2f1dc207c792eaadebf9d8adc44648581
+F src/tclsqlite.c be0e691e223a907aa032c7b3ed310dc0ff048109
- F src/test1.c 7439efb86c1022f19a39a8e61de2cbac23ffab03
+ F src/test1.c 0f41b7c67719207a5de24b009e172c4dcf189827
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
F src/utf.c c53eb7404b3eb5c1cbb5655c6a7a0e0ce6bd50f0
F src/util.c 06302ffd2b80408d4f6c7af71f7090e0cf8d8ff7
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
- F src/vdbe.c 9bc9b5f1231b9ea1bd35fecb775cce970fe47ac7
- F src/vdbe.h ee8ba0243ff76fae3af1d020c8d82d8368a2a744
- F src/vdbeInt.h 1b36e54662ef3ee5c9ce4a5933e122ffb8782b93
- F src/vdbeapi.c ddd061183e2c3015f676e53ee85fcaf306617e8e
- F src/vdbeaux.c 4b5f0e80af001976d61ecb1c1e44c03dd7cb3d16
-F src/vdbe.c 7008edbf8f608d82c035dcb1c56367ad85e68aaa
-F src/vdbe.h a10b360bf69474babc8aba8fcc64b824c5e97d38
-F src/vdbeInt.h 693d6ac6810298fc6b4c503cfbe3f99a240f40af
-F src/vdbeapi.c 11dc47987abacb76ad016dcf5abc0dc422482a98
-F src/vdbeaux.c ca8aa399e1be85fe82498b107128297a5d84e6a2
-F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3
++F src/vdbe.c f03941d4126e2484a52652081a73f2e2e4d4eda1
++F src/vdbe.h a3308e58577f1586e4b0afb5e08b1fb6ac743d0d
++F src/vdbeInt.h 1400515b37a4863cdda4601abc0f76eca846c9f5
++F src/vdbeapi.c c969d467817ca90f99f3d3b46d115fbec08aeb4c
++F src/vdbeaux.c b09cc16325b4faad109fb3e59d393019d1600e55
+F src/vdbeblob.c fde0374afb0c512614aed191ac2683f6772d2b8f
- F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
- F src/vdbesort.c 8a61a6d731cbe612217edf9eece6197f37c9489e
+ F src/vdbemem.c 5e6effb96dd53d233361cbfaa3f0a43b9af689e9
+ F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
F src/wal.c 3154756177d6219e233d84291d5b05f4e06ff5e9
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
F test/selectB.test 0d072c5846071b569766e6cd7f923f646a8b2bfa
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
- F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
+ F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
+F test/session.test c1a17c11ef7d01c24fe2b9f7871190d949a8e718
F test/shared.test 34945a516532b11182c3eb26e31247eee3c9ae48
F test/shared2.test 8f71d4eb4d5261280de92284df74172545c852cc
F test/shared3.test ebf77f023f4bdaa8f74f65822b559e86ce5c6257
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2
F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d
-F test/tester.tcl 0b2999b578964297663de4870babbbee29225622
+F test/tester.tcl 8db832ad03331dcae2f39b435feb2f789cd4e8d9
- F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
- F test/thread002.test 716631b06cccf33b368ab7f6dd3cad92907b8928
- F test/thread003.test 33d2d46e6a53ccb2ff8dc4d0c4e3b3aaee36dcd1
+ F test/thread001.test 7cc2ce08f9cde95964736d11e91f9ab610f82f91
+ F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
+ F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f
F test/thread005.test 50d10b5684399676174bd96c94ad4250b1a2c8b6
F test/thread1.test df115faa10a4ba1d456e9d4d9ec165016903eae4
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
- F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
+ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings.sh b7fdb2cc525f5ef4fa43c80e771636dd3690f9d2
- P c5709036087b6b4fb6391ab7e4b4b870aac87a31 1dada5158215d1816edb69ff2610f9d2259ce19d
- R a4d0f9879dd116c25d083f8cdc0d0501
- U drh
- Z 0ce927a650c1609d421fc43e47e08b7b
-P a1f3aeeb0988c848d40ce8f6da6e902935a997e2
-R 0af9d8f0b3f18e81a71e0aa10948427c
-U mistachkin
-Z d90e2842f2c20a0f3227a4c8a539b329
++P eb036d6f81e15bac013316bf5b1b2ba3e0bd4605 3035dc1c7398791d550f4c02774ef7f961b4bb02
++R 807d1da65636d94548ad55811c85e6a7
++U dan
++Z e140cc97ae2304f1c705299d75477c59
- eb036d6f81e15bac013316bf5b1b2ba3e0bd4605
-3035dc1c7398791d550f4c02774ef7f961b4bb02
++c00e45ede7cbf71a3a6d1ccad0b9275010ca8493
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 */
+ int (*xAdvance)(BtCursor *, int *);
} p4;
#ifdef SQLITE_DEBUG
char *zComment; /* Comment to improve readability */
#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 */
+ #define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
++#define P4_TABLE (-20) /* 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
if( resetFlag ) pVdbe->aCounter[op-1] = 0;
return v;
}
- p->pUnpacked = sqlite3VdbeRecordUnpack(&p->keyinfo, nRec, aRec, 0, 0);
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
++/*
++** Allocate and populate an UnpackedRecord structure based on the serialized
++** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure
++** if successful, or a NULL pointer if an OOM error is encountered.
++*/
++static UnpackedRecord *vdbeUnpackRecord(
++ KeyInfo *pKeyInfo,
++ int nKey,
++ const void *pKey
++){
++ char *dummy; /* Dummy argument for AllocUnpackedRecord() */
++ UnpackedRecord *pRet; /* Return value */
++
++ pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo, 0, 0, &dummy);
++ if( pRet ){
++ sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
++ }
++ return pRet;
++}
++
+/*
+** 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;
+ }
+ if( iIdx>=p->pCsr->nField || iIdx<0 ){
+ rc = SQLITE_RANGE;
+ goto preupdate_old_out;
+ }
+
+ /* If the old.* record has not yet been loaded into memory, do so now. */
+ if( p->pUnpacked==0 ){
+ u32 nRec;
+ u8 *aRec;
+
+ rc = sqlite3BtreeDataSize(p->pCsr->pCursor, &nRec);
+ if( rc!=SQLITE_OK ) goto preupdate_old_out;
+ aRec = sqlite3DbMallocRaw(db, nRec);
+ if( !aRec ) goto preupdate_old_out;
+ rc = sqlite3BtreeData(p->pCsr->pCursor, 0, nRec, aRec);
+ if( rc==SQLITE_OK ){
- pUnpack = sqlite3VdbeRecordUnpack(&p->keyinfo, pData->n, pData->z, 0, 0);
++ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
+ if( !p->pUnpacked ) rc = SQLITE_NOMEM;
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3DbFree(db, aRec);
+ goto preupdate_old_out;
+ }
+ p->aRecord = aRec;
+ }
+
+ 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);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** 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->keyinfo.nField : 0);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** This function is designed to be called from within a pre-update callback
+** only. It returns zero if the change that caused the callback was made
+** immediately by a user SQL statement. Or, if the change was made by a
+** trigger program, it returns the number of trigger programs currently
+** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
+** top-level trigger etc.).
+**
+** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
+** or SET DEFAULT action is considered a trigger.
+*/
+int sqlite3_preupdate_depth(sqlite3 *db){
+ PreUpdate *p = db->pPreUpdate;
+ return (p ? p->v->nFrame : 0);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** 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_DELETE ){
+ rc = SQLITE_MISUSE_BKPT;
+ goto preupdate_new_out;
+ }
+ if( iIdx>=p->pCsr->nField || iIdx<0 ){
+ rc = SQLITE_RANGE;
+ 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 = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
+ 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];
+ 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.
+ */
+ 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;
+ }
+ }
+ 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);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
v->expmask |= ((u32)1 << (iVar-1));
}
}
- if( preupdate.pUnpacked ){
- sqlite3VdbeDeleteUnpackedRecord(preupdate.pUnpacked);
- }
- if( preupdate.pNewUnpacked ){
- sqlite3VdbeDeleteUnpackedRecord(preupdate.pNewUnpacked);
- }
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
++
++/*
++** If the second argument is not NULL, release any allocations associated
++** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
++** structure itself, using sqlite3DbFree().
++**
++** This function is used to free UnpackedRecord structures allocated by
++** the vdbeUnpackRecord() function found in vdbeapi.c.
++*/
++static void vdbeFreeUnpacked(sqlite3 *db, UnpackedRecord *p){
++ if( p ){
++ int i;
++ for(i=0; i<p->nField; i++){
++ Mem *pMem = &p->aMem[i];
++ if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
++ }
++ sqlite3DbFree(db, p);
++ }
++}
++
+/*
+** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
+** then cursor passed as the second argument should point to the row about
+** to be update or deleted. If the application calls sqlite3_preupdate_old(),
+** 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;
+ }
+
+ assert( pCsr->nField==pTab->nCol
+ || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ );
+
+ preupdate.v = v;
+ preupdate.pCsr = pCsr;
+ preupdate.op = op;
+ preupdate.iNewReg = iReg;
+ preupdate.keyinfo.db = db;
+ preupdate.keyinfo.enc = ENC(db);
+ preupdate.keyinfo.nField = pTab->nCol;
+ 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);
++ vdbeFreeUnpacked(db, preupdate.pUnpacked);
++ vdbeFreeUnpacked(db, preupdate.pNewUnpacked);
+ if( preupdate.aNew ){
+ int i;
+ for(i=0; i<pCsr->nField; i++){
+ sqlite3VdbeMemRelease(&preupdate.aNew[i]);
+ }
+ sqlite3DbFree(db, preupdate.aNew);
+ }
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */