]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge recent trunk enhancements, including the read-after-ROLLBACK change
authordrh <drh@noemail.net>
Tue, 18 Nov 2014 21:20:57 +0000 (21:20 +0000)
committerdrh <drh@noemail.net>
Tue, 18 Nov 2014 21:20:57 +0000 (21:20 +0000)
and the addition of sqlite3_stmt_scanstatus() support, as well as various
minor bug fixes.

FossilOrigin-Name: f09055f3c4348264c7336f90646375f0d98b061e

17 files changed:
1  2 
Makefile.in
Makefile.msc
main.mk
manifest
manifest.uuid
src/main.c
src/shell.c
src/sqlite.h.in
src/sqliteInt.h
src/tclsqlite.c
src/test_config.c
src/vdbe.c
src/vdbe.h
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
src/vdbeblob.c

diff --cc Makefile.in
Simple merge
diff --cc Makefile.msc
Simple merge
diff --cc main.mk
Simple merge
diff --cc manifest
index 26da220ff3ac800e28f26ba6fe5365a2ea89d327,8a5349a2dde39e9185914f51df77471625b9b0b3..3bf03658d63ffba6280660e349473c72ae44e030
+++ b/manifest
@@@ -1,9 -1,9 +1,9 @@@
- C Merge\srecent\strunk\senhancements,\sand\sin\sparticular\sthe\simprovements\sto\nthe\sb-tree\sbalancing\slogic,\sinto\sthe\ssessions\sbranch.
- D 2014-10-31T14:53:32.379
 -C Merge\sin\sall\sthe\sother\sROLLBACK\sfixes\sfrom\sthe\sbranch-3.8.7\sbranch.\s\s\nI\sdon't\sknow\swhy\sI\swas\sdoing\sthem\sone-by-one.
 -D 2014-11-18T20:49:30.759
++C Merge\srecent\strunk\senhancements,\sincluding\sthe\sread-after-ROLLBACK\schange\nand\sthe\saddition\sof\ssqlite3_stmt_scanstatus()\ssupport,\sas\swell\sas\svarious\nminor\sbug\sfixes.
++D 2014-11-18T21:20:57.012
  F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
- F Makefile.in dd5f245aa8c741bc65845747203c8ce2f3fb6c83
 -F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb
++F Makefile.in e2007fafb7b679a39800a1d636dcc6662a840530
  F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
- F Makefile.msc 35808af7f8d999176ed5b38fb482a87a129ee3e1
 -F Makefile.msc 788f1288633a0c3c3cbbe0f3e4827d033f7ba530
++F Makefile.msc 64f7ba446298db653fc195ad7699e4b06863d9c4
  F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0
  F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
  F VERSION d846487aff892625eb8e75960234e7285f0462fe
@@@ -168,7 -152,7 +169,7 @@@ F ext/userauth/userauth.c 5fa3bdb492f48
  F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
  F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
  F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
- F main.mk 7711bc77822814799b853271ee19ac79e98bfb4b
 -F main.mk 084976077a4aa3bd985154b5423e7aed88e4a2e9
++F main.mk 112ccda703db78f10e0b386723acab2044fd97ed
  F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
  F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
  F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@@ -196,9 -180,9 +197,9 @@@ F src/build.c 67bb05b1077e0cdaccb2e36bf
  F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
  F src/complete.c c4ba6e0626bb94bc77a0861735f3382fcf7cc818
  F src/ctime.c df19848891c8a553c80e6f5a035e768280952d1a
- F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036
+ F src/date.c 93594514aae68de117ca4a2a0d6cc63eddf26744
 -F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417
 +F src/delete.c 20a360262b62051afacb44122b3593a8bd9be131
- F src/expr.c 0391a657df4959eaf2a2fd7d77de5ebe750686ee
+ F src/expr.c a3ff05db5709d628c23890db862e30f3dd9dc428
  F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
  F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
  F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee
@@@ -211,8 -195,8 +212,8 @@@ F src/journal.c b4124532212b6952f42eb2c
  F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
  F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
  F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994
- F src/main.c 7a3d124561f3fd0555dbefe492f5db0a4ba9f8d8
- F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec
 -F src/main.c d3310d5ed56e246bf1589e47eeaca8be582bd4b8
++F src/main.c 46e2f592797c6167fb6964a7fa953c480ec766d8
+ F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
  F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
  F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f
  F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
@@@ -245,16 -229,16 +246,16 @@@ F src/random.c ba2679f80ec82c4190062d75
  F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952
  F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
  F src/select.c 428165951748151e87a15295b7357221433e311b
- F src/shell.c e3a0e5d94d58fbaf9a4a0a4bb2db19ed2e64be6d
- F src/sqlite.h.in 322c7813901be3038a7df08cdb456ad76e880f60
 -F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd
 -F src/sqlite.h.in 0c5c0df7e4e436dfc5592511325bf4a96f6a638d
++F src/shell.c a67b1304a7d93f26ec611de7b4650307f8e074a7
++F src/sqlite.h.in 6a51d3ab98e02777b894f361a81766eb9cee7413
  F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
  F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
- F src/sqliteInt.h 339f3f8bf633452d271a3c9c593c4a0faaa171f8
 -F src/sqliteInt.h 71b0bf1a7fc55b5cb374f7579fd140e730a6e0f4
++F src/sqliteInt.h 29e71a7464bdec315a269976b817b7add6d4edbc
  F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
  F src/status.c 81712116e826b0089bb221b018929536b2b5406f
  F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc
- F src/tclsqlite.c 684c317b85f4729de12909bfad80d3f5500357cf
- F src/test1.c 63d4b1707c4052cf9c05c1cbb4a62666d70a0b48
 -F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228
++F src/tclsqlite.c 05be57620509060e85064b9495256c05d56e76b0
+ F src/test1.c 6b0469b8e06c77b1de1d3e4a3834cf26edea9cc7
  F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
  F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
  F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@@ -266,8 -250,9 +267,9 @@@ F src/test9.c bea1e8cf52aa93695487baded
  F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
  F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
  F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
+ F src/test_blob.c 1f2e3e25255b731c4fcf15ee7990d06347cb6c09
  F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
- F src/test_config.c 6ff73defc3db475059a9d7ca8023f05f99242c8e
 -F src/test_config.c 035c17a173937d019b8dfc1d524f9d3fc8123504
++F src/test_config.c d0d671ce14e41abd487036ef8c4422585157d49a
  F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
  F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
  F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
@@@ -302,25 -287,25 +304,25 @@@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f
  F src/threads.c 6de09362b657f19ba83e5fa521ee715787ce9fee
  F src/tokenize.c cc9016e5007fc5e76789079616d2f26741bcc689
  F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
 -F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
 +F src/update.c d207deb7a031f698104bee879de0632b611e72dd
  F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
  F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73
- F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
- F src/vdbe.c 407f16f5991c5bb27978e00bf74e64dd0dabd692
- F src/vdbe.h d61daeffed696e21630759de9e135ee298ad9573
- F src/vdbeInt.h 18756149efd3a931803381074dccc4ce161c7063
- F src/vdbeapi.c 1a5c9248249f3e17bd0707da799d4c613970ffe1
- F src/vdbeaux.c d53c188cde088b58bd2733144c4c803e32bf2bba
- F src/vdbeblob.c d83b1f9e8f3c0359adc8404b8673b7994739daf7
+ F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c
 -F src/vdbe.c 5563459c06c434bc43131044fcf8164654008ebd
 -F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
 -F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78
 -F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83
 -F src/vdbeaux.c 9b0a251b6dfab349dd6c6efb40062eb7386b26f5
 -F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778
 -F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
++F src/vdbe.c ef0d4a46d2aa7f6aedb2c4c29c66e1e33d4c7168
++F src/vdbe.h b434bb75fbec973d18d49225a59833ae39ee2afc
++F src/vdbeInt.h dc69f0351bef56456fdba3e09d3387ba4f1b1520
++F src/vdbeapi.c 3d4d2a2b24055ce2cb029fa73067c56616264b51
++F src/vdbeaux.c 19ecf5fc0524346e46c31fa035c57adb90ffa49e
++F src/vdbeblob.c cb7359c2d99df92c35cdaedc12af6d4f83854cb7
 +F src/vdbemem.c 96e41193b4affd9ebc0eea2fa628879dac88c744
- F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438
+ F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a
  F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
  F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793
- F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
+ F src/wal.c fa090966140602f03a621f87d82ee69e66ca63b5
  F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
  F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
- F src/where.c 5665df88cbd2b38eb72b4b94c8892c8afb360181
- F src/whereInt.h 19279cd0664ce1d90b9ad3ef0108cb494acfe455
+ F src/where.c 3862a1173ae2716bde12f1ab3fb649f1d85b05c2
+ F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0
  F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
  F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
  F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
@@@ -507,8 -497,8 +514,8 @@@ F test/fkey2.test 1db212cda86b0d3ce7271
  F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
  F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
  F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d
 -F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48
 +F test/fkey6.test 6697550baa38505c9952eff130ab26a2d156c0cc
- F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
+ F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
  F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
  F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
  F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
@@@ -896,10 -889,10 +907,10 @@@ F test/superlock.test 1cde669f68d2dd37d
  F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
  F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
  F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
- F test/table.test 2a1d2fa52c531de5915f28023747d9a8c27b6f31
+ F test/table.test 06271d61eb13871490d38168433c1ef3dd82bb2a
  F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
  F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
 -F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
 +F test/tclsqlite.test a7308276aad2e6c0bfb5b0414424dd0d9cc0cad7
  F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
  F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
  F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
@@@ -1228,7 -1221,7 +1239,7 @@@ F tool/vdbe_profile.tcl 67746953071a9f8
  F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
  F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
  F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
- P f4de9e07be3819db222317725e62ea997cd22a20 67f0d469da28c023200239a1f3d0c6cef9ef0e45
- R c6574894282e9c56b60788bbd17b6d37
 -P 2896f2640ab3e102ee248d20fb68c497817524eb 945a9e687fdfee5f7103d85d131024e85d594ac3
 -R 8b4c6ed5b267d5d2bc5845aacffad250
++P 28b044a51215a3f64dafb2cf3b6cb7d2029580ef 296b0c7397790ceadbdb330959e962f6491abc3e
++R 29b28d376c9121783d6d4ac3519f50ed
  U drh
- Z d46687ae123d3be720b18e6a3cbacd2c
 -Z 0fc13d2fc810c826601883122c184fdf
++Z c3d0de9dd44c494f12cc744c4f6471c6
diff --cc manifest.uuid
index 374c4eafaec004f42876fedb2ee7d373788d613c,75b72440d459aa0d7816e6cbc765e97ccde46562..5f7a3cf0d4d507e658ecfd9d1be7b67a560e0951
@@@ -1,1 -1,1 +1,1 @@@
- 28b044a51215a3f64dafb2cf3b6cb7d2029580ef
 -296b0c7397790ceadbdb330959e962f6491abc3e
++f09055f3c4348264c7336f90646375f0d98b061e
diff --cc src/main.c
Simple merge
diff --cc src/shell.c
Simple merge
diff --cc src/sqlite.h.in
index 400d3aae5e1b8cb0d66ce2ac11f960efd5d9f9e0,4427f39d06cf07ff1d80cd59bd33fe050e8f8dc9..65fade74beca2c78bdc3abe28d8225b0e8080810
@@@ -7406,103 -7444,100 +7444,195 @@@ int sqlite3_vtab_on_conflict(sqlite3 *)
  /* #define SQLITE_ABORT 4  // Also an error code */
  #define SQLITE_REPLACE  5
  
+ /*
+ ** CAPI3REF: Prepared Statement Scan Status Opcodes
+ ** KEYWORDS: {scanstatus options}
+ **
+ ** The following constants can be used for the T parameter to the
+ ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface.  Each constant designates a
+ ** different metric for sqlite3_stmt_scanstatus() to return.
+ **
+ ** <dl>
+ ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
+ ** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set to the
+ ** total number of times that the X-th loop has run.</dd>
+ **
+ ** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
+ ** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set to the
+ ** total number of rows examined by all iterations of the X-th loop.</dd>
+ **
+ ** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
+ ** <dd>^The "double" variable pointed to by the T parameter will be set to the
+ ** query planner's estimate for the average number of rows output from each
+ ** iteration of the X-th loop.  If the query planner's estimates was accurate,
+ ** then this value will approximate the quotient NVISIT/NLOOP and the
+ ** product of this value for all prior loops with the same SELECTID will
+ ** be the NLOOP value for the current loop.
+ **
+ ** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
+ ** <dd>^The "const char *" variable pointed to by the T parameter will be set to 
+ ** a zero-terminated UTF-8 string containing the name of the index or table used
+ ** for the X-th loop.
+ **
+ ** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
+ ** <dd>^The "const char *" variable pointed to by the T parameter will be set to 
+ ** a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] description
+ ** for the X-th loop.
+ **
+ ** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+ ** <dd>^The "int" variable pointed to by the T parameter will be set to the
+ ** "select-id" for the X-th loop.  The select-id identifies which query or
+ ** subquery the loop is part of.  The main query has a select-id of zero.
+ ** The select-id is the same value as is output in the first column
+ ** of an [EXPLAIN QUERY PLAN] query.
+ ** </dl>
+ */
+ #define SQLITE_SCANSTAT_NLOOP    0
+ #define SQLITE_SCANSTAT_NVISIT   1
+ #define SQLITE_SCANSTAT_EST      2
+ #define SQLITE_SCANSTAT_NAME     3
+ #define SQLITE_SCANSTAT_EXPLAIN  4
+ #define SQLITE_SCANSTAT_SELECTID 5
+ /*
+ ** CAPI3REF: Prepared Statement Scan Status
+ **
+ ** Return status data for a single loop within query pStmt.
+ **
+ ** The "iScanStatusOp" parameter determines which status information to return.
+ ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior of
+ ** this interface is undefined.
+ ** ^The requested measurement is written into a variable pointed to by
+ ** the "pOut" parameter.
+ ** Parameter "idx" identifies the specific loop to retrieve statistics for.
+ ** Loops are numbered starting from zero. ^If idx is out of range - less than
+ ** zero or greater than or equal to the total number of loops used to implement
+ ** the statement - a non-zero value is returned and the variable that pOut
+ ** points to is unchanged.
+ **
+ ** ^Statistics might not be available for all loops in all statements. ^In cases
+ ** where there exist loops with no available statistics, this function behaves
+ ** as if the loop did not exist - it returns non-zero and leave the variable
+ ** that pOut points to unchanged.
+ **
+ ** This API is only available if the library is built with pre-processor
+ ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
+ **
+ ** See also: [sqlite3_stmt_scanstatus_reset()]
+ */
+ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
+   sqlite3_stmt *pStmt,      /* Prepared statement for which info desired */
+   int idx,                  /* Index of loop to report on */
+   int iScanStatusOp,        /* Information desired.  SQLITE_SCANSTAT_* */
+   void *pOut                /* Result written here */
+ );     
+ /*
+ ** CAPI3REF: Zero Scan-Status Counters
+ **
+ ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
+ **
+ ** This API is only available if the library is built with pre-processor
+ ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
+ */
+ SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
  
  
 +/*
 +** CAPI3REF: The pre-update hook.
 +** EXPERIMENTAL
 +**
 +** ^These interfaces are only available if SQLite is compiled using the
 +** [SQLITE_ENABLE_UPDATE_HOOK] compile-time option.
 +**
 +** ^The [sqlite3_preupdate_hook()] interface registers a callback function
 +** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation.
 +** ^At most one preupdate hook may be registered at a time on a single
 +** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
 +** the previous setting.
 +** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
 +** with a NULL pointer as the second parameter.
 +** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
 +** the first parameter to callbacks.
 +**
 +** ^The preupdate hook only fires for changes to real tables; the preupdate
 +** hook is not invoked for changes to virtual tables.
 +**
 +** ^The second parameter to the preupdate callback is a pointer to
 +** the [database connection] that registered the preupdate hook.
 +** ^The third parameter to the preupdate callback is one of the constants
 +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to indentify the
 +** kind of update operation that is about to occur.
 +** ^(The fourth parameter to the preupdate callback is the name of the
 +** database within the database connection that is being modified.  This
 +** will be "main" for the main database or "temp" for TEMP tables or 
 +** the name given after the AS keyword in the [ATTACH] statement for attached
 +** databases.)^
 +** ^The fifth parameter to the preupdate callback is the name of the
 +** table that is being modified.
 +** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
 +** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
 +** undefined for SQLITE_INSERT changes.
 +** ^The seventh parameter to the preupdate callback is the final [rowid] of
 +** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
 +** undefined for SQLITE_DELETE changes.
 +**
 +** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
 +** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
 +** provide additional information about a preupdate event. These routines
 +** may only be called from within a preupdate callback.  Invoking any of
 +** these routines from outside of a preupdate callback or with a
 +** [database connection] pointer that is different from the one supplied
 +** to the preupdate callback results in undefined and probably undesirable
 +** behavior.
 +**
 +** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
 +** in the row that is being inserted, updated, or deleted.
 +**
 +** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
 +** a [protected sqlite3_value] that contains the value of the Nth column of
 +** the table row before it is updated.  The N parameter must be between 0
 +** and one less than the number of columns or the behavior will be
 +** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
 +** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
 +** behavior is undefined.  The [sqlite3_value] that P points to
 +** will be destroyed when the preupdate callback returns.
 +**
 +** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
 +** a [protected sqlite3_value] that contains the value of the Nth column of
 +** the table row after it is updated.  The N parameter must be between 0
 +** and one less than the number of columns or the behavior will be
 +** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
 +** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
 +** behavior is undefined.  The [sqlite3_value] that P points to
 +** will be destroyed when the preupdate callback returns.
 +**
 +** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
 +** callback was invoked as a result of a direct insert, update, or delete
 +** operation; or 1 for inserts, updates, or deletes invoked by top-level 
 +** triggers; or 2 for changes resulting from triggers called by top-level
 +** triggers; and so forth.
 +**
 +** See also:  [sqlite3_update_hook()]
 +*/
 +SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
 +  sqlite3 *db,
 +  void(*xPreUpdate)(
 +    void *pCtx,                   /* Copy of third arg to preupdate_hook() */
 +    sqlite3 *db,                  /* Database handle */
 +    int op,                       /* SQLITE_UPDATE, DELETE or INSERT */
 +    char const *zDb,              /* Database name */
 +    char const *zName,            /* Table name */
 +    sqlite3_int64 iKey1,          /* Rowid of row about to be deleted/updated */
 +    sqlite3_int64 iKey2           /* New rowid value (for a rowid UPDATE) */
 +  ),
 +  void*
 +);
 +SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
 +SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
 +SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *);
 +SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
 +
  /*
  ** Undo the hack that converts floating point types to integer for
  ** builds on processors without floating point support.
diff --cc src/sqliteInt.h
Simple merge
diff --cc src/tclsqlite.c
Simple merge
Simple merge
diff --cc src/vdbe.c
Simple merge
diff --cc src/vdbe.h
Simple merge
diff --cc src/vdbeInt.h
Simple merge
diff --cc src/vdbeapi.c
index e0b204cd1be53b3d6d41bb7aacd7ddf853e37483,5744c28632ddbd0d58f0cf6607333441b2b197f1..c7c14d9c31d9facdd5e8c74a15b5a8a9bbc7ffd6
@@@ -1476,183 -1476,71 +1476,252 @@@ int sqlite3_stmt_status(sqlite3_stmt *p
    return (int)v;
  }
  
 +#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 ){
 +    memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
 +    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 ){
 +      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);
 +    }
 +  }
 +
 + preupdate_old_out:
 +  sqlite3Error(db, rc);
 +  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);
 +      }
 +    }
 +  }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;
 +      }
 +    }
 +  }
 +  *ppValue = pMem;
 +
 + preupdate_new_out:
 +  sqlite3Error(db, rc);
 +  return sqlite3ApiExit(db, rc);
 +}
 +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
++
+ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ /*
+ ** Return status data for a single loop within query pStmt.
+ */
+ int sqlite3_stmt_scanstatus(
+   sqlite3_stmt *pStmt,            /* Prepared statement being queried */
+   int idx,                        /* Index of loop to report on */
+   int iScanStatusOp,              /* Which metric to return */
+   void *pOut                      /* OUT: Write the answer here */
+ ){
+   Vdbe *p = (Vdbe*)pStmt;
+   ScanStatus *pScan;
+   if( idx<0 || idx>=p->nScan ) return 1;
+   pScan = &p->aScan[idx];
+   switch( iScanStatusOp ){
+     case SQLITE_SCANSTAT_NLOOP: {
+       *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop];
+       break;
+     }
+     case SQLITE_SCANSTAT_NVISIT: {
+       *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit];
+       break;
+     }
+     case SQLITE_SCANSTAT_EST: {
+       double r = 1.0;
+       LogEst x = pScan->nEst;
+       while( x<100 ){
+         x += 10;
+         r *= 0.5;
+       }
+       *(double*)pOut = r*sqlite3LogEstToInt(x);
+       break;
+     }
+     case SQLITE_SCANSTAT_NAME: {
+       *(const char**)pOut = pScan->zName;
+       break;
+     }
+     case SQLITE_SCANSTAT_EXPLAIN: {
+       if( pScan->addrExplain ){
+         *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+       }else{
+         *(const char**)pOut = 0;
+       }
+       break;
+     }
+     case SQLITE_SCANSTAT_SELECTID: {
+       if( pScan->addrExplain ){
+         *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+       }else{
+         *(int*)pOut = -1;
+       }
+       break;
+     }
+     default: {
+       return 1;
+     }
+   }
+   return 0;
+ }
+ /*
+ ** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
+ */
+ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
+   Vdbe *p = (Vdbe*)pStmt;
+   memset(p->anExec, 0, p->nOp * sizeof(i64));
+ }
+ #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
diff --cc src/vdbeaux.c
Simple merge
diff --cc src/vdbeblob.c
Simple merge