]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge latest changes from the trunk into the sessions branch.
authordan <dan@noemail.net>
Wed, 14 Sep 2011 19:41:44 +0000 (19:41 +0000)
committerdan <dan@noemail.net>
Wed, 14 Sep 2011 19:41:44 +0000 (19:41 +0000)
FossilOrigin-Name: c00e45ede7cbf71a3a6d1ccad0b9275010ca8493

1  2 
main.mk
manifest
manifest.uuid
src/sqliteInt.h
src/vdbe.c
src/vdbe.h
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c

diff --cc main.mk
Simple merge
diff --cc manifest
index 3f34ca057c76d7b80862eb10366757263b6ff082,bccc5fe4dcb967717e3a55880827fd44c3410cbb..883ad2f5811dc0031168d7c600495013ea156d13
+++ b/manifest
@@@ -1,10 -1,10 +1,10 @@@
- 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
@@@ -102,21 -102,9 +102,21 @@@ F ext/rtree/rtree_util.tcl 06aab2ed5b82
  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
@@@ -136,16 -124,16 +136,16 @@@ F src/auth.c 523da7fb4979469955d822ff92
  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
@@@ -191,16 -179,16 +191,16 @@@ F src/printf.c 585a36b6a963df832cfb6950
  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
@@@ -250,14 -238,14 +250,14 @@@ F src/update.c 2d67e24d5a44d8b1c0839bf2
  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
@@@ -673,8 -661,7 +673,8 @@@ F test/select9.test 74c0fb2c6eecb0219cb
  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
@@@ -712,10 -699,10 +712,10 @@@ F test/tclsqlite.test d5298750115768bca
  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
@@@ -971,10 -958,10 +971,10 @@@ F tool/speedtest8.c 2902c46588c40b55661
  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
diff --cc manifest.uuid
index 8f69556b5d97af493a3e2e5bd90b6f3229f391a7,c741eb7da4ec483905d513b4c4b182eb90e78994..39610efda7fc6c617ad4ac13e73adffc2742b11f
@@@ -1,1 -1,1 +1,1 @@@
- eb036d6f81e15bac013316bf5b1b2ba3e0bd4605
 -3035dc1c7398791d550f4c02774ef7f961b4bb02
++c00e45ede7cbf71a3a6d1ccad0b9275010ca8493
diff --cc src/sqliteInt.h
Simple merge
diff --cc src/vdbe.c
Simple merge
diff --cc src/vdbe.h
index d0333d82f7a54139d33c7fdeae99113dc13b1487,f4691c0e8fa4b3ac757b63c0c4a2fea246a028a0..9332b9851d9e593465f03cf725995833a683d769
@@@ -61,7 -61,7 +61,8 @@@ struct VdbeOp 
      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 */
@@@ -117,7 -117,7 +118,8 @@@ typedef struct VdbeOpList VdbeOpList
  #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
diff --cc src/vdbeInt.h
Simple merge
diff --cc src/vdbeapi.c
index dfe8f87a151ddfab05a6a60c0e836e4a905e8d7b,678f0d91e7a37f333527e24d0866e445f7af0ff5..775a541f838687ef0549154110fbad584b00c783
@@@ -1324,166 -1304,3 +1324,186 @@@ int sqlite3_stmt_status(sqlite3_stmt *p
    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 */
diff --cc src/vdbeaux.c
index 8b86e073fba6d99a97bdd7aedddbfa012d7f51bf,b00768477eab99aafe6d3bb1c95d3b18a8810b55..b7239bb6840a375c9bc5c2037e497a59e718d74a
@@@ -3243,67 -3239,3 +3241,83 @@@ void sqlite3VdbeSetVarmask(Vdbe *v, in
      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 */