From 62ecc28caf3c45769fe4a7f8aa9e631a2280cf1d Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Oct 2014 01:07:21 +0000 Subject: [PATCH 01/71] Call fsync() right after ftruncate() when in journal_mode=TRUNCATE and when synchronous=FULL in order to ensure that transactions are durable across a power loss that happens moments after the commit. Proposed fix for [https://bugzilla.mozilla.org/show_bug.cgi?id=1072773]. This is a cherrypick of [3e922208b68563489]. FossilOrigin-Name: a8f9bd1e890434fcffa02fcd2baf8b0fb5d4c9dd --- manifest | 19 ++++++++++--------- manifest.uuid | 2 +- src/pager.c | 8 ++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index e210943d15..a156aa4f0e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s3.8.7 -D 2014-10-17T11:24:17.839 +C Call\sfsync()\sright\safter\sftruncate()\swhen\sin\sjournal_mode=TRUNCATE\sand\nwhen\ssynchronous=FULL\sin\sorder\sto\sensure\sthat\stransactions\sare\sdurable\nacross\sa\spower\sloss\sthat\shappens\smoments\safter\sthe\scommit.\s\sProposed\nfix\sfor\s[https://bugzilla.mozilla.org/show_bug.cgi?id=1072773].\nThis\sis\sa\scherrypick\sof\s[3e922208b68563489]. +D 2014-10-29T01:07:21.172 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,7 +215,7 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7 F src/os_win.c a019caaae2bcbbc0cc4c39af6e7d7e43d8426053 F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 -F src/pager.c a171cf9dd09c6cb162b262c328d4dfd198e04f80 +F src/pager.c a98547ad9b1b5dbbc5e7d1c520be041b5d2c0926 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a @@ -1204,10 +1204,11 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 06c576c152c4013080c255cbbeb45bf2e298be9f -R 76bb09f8a8f8bdebeb708f5bb39aa31b -T +bgcolor * #d0c0ff -T +sym-release * -T +sym-version-3.8.7 * +P e4ab094f8afce0817f4074e823fabe59fc29ebb4 +Q +3e922208b68563489c7766abb9afb4885113e7b8 +R dac8a0df55bcef8314fa6cd2a33fc123 +T *branch * branch-3.8.7 +T *sym-branch-3.8.7 * +T -sym-trunk * U drh -Z b2f516d1147acb0e1bf1c700327ee52e +Z 1e440e6f18a01c290161fa6c4a1f516b diff --git a/manifest.uuid b/manifest.uuid index f4f611fe44..bf1f77f03a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e4ab094f8afce0817f4074e823fabe59fc29ebb4 \ No newline at end of file +a8f9bd1e890434fcffa02fcd2baf8b0fb5d4c9dd \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index d3a36ef484..d840a39a15 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1941,6 +1941,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ rc = SQLITE_OK; }else{ rc = sqlite3OsTruncate(pPager->jfd, 0); + if( rc==SQLITE_OK && pPager->fullSync ){ + /* Make sure the new file size is written into the inode right away. + ** Otherwise the journal might resurrect following a power loss and + ** cause the last transaction to roll back. See + ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773 + */ + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); + } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST From 739383d25dc714bf968a67e6f5aae52cc0033e2e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Oct 2014 01:13:58 +0000 Subject: [PATCH 02/71] In the OP_Column opcode, when extracting a field that is past the end of a short record (because the row was originally inserted prior to ALTER TABLE ADD COLUMN) then make sure the output register is fully NULL and does not contain leftover flags (such as MEM_Ephem) from its previous use. Fix for ticket [43107840f1c02]. This is a cherrypick of check-in [24780f8ddc1683fc]. FossilOrigin-Name: 304ea6ba6f4cf40a76d32d37af73a253f493ba47 --- manifest | 19 ++++++++----------- manifest.uuid | 2 +- src/vdbe.c | 2 +- test/update.test | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index a156aa4f0e..d38979f110 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Call\sfsync()\sright\safter\sftruncate()\swhen\sin\sjournal_mode=TRUNCATE\sand\nwhen\ssynchronous=FULL\sin\sorder\sto\sensure\sthat\stransactions\sare\sdurable\nacross\sa\spower\sloss\sthat\shappens\smoments\safter\sthe\scommit.\s\sProposed\nfix\sfor\s[https://bugzilla.mozilla.org/show_bug.cgi?id=1072773].\nThis\sis\sa\scherrypick\sof\s[3e922208b68563489]. -D 2014-10-29T01:07:21.172 +C In\sthe\sOP_Column\sopcode,\swhen\sextracting\sa\sfield\sthat\sis\spast\sthe\send\sof\na\sshort\srecord\s(because\sthe\srow\swas\soriginally\sinserted\sprior\sto\sALTER\sTABLE\nADD\sCOLUMN)\sthen\smake\ssure\sthe\soutput\sregister\sis\sfully\sNULL\sand\sdoes\snot\ncontain\sleftover\sflags\s(such\sas\sMEM_Ephem)\sfrom\sits\sprevious\suse.\nFix\sfor\sticket\s[43107840f1c02].\s\sThis\sis\sa\scherrypick\sof\ncheck-in\s[24780f8ddc1683fc]. +D 2014-10-29T01:13:58.092 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/update.c 729f6f18fc27740591d085e1172cebe311144bf0 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 5ee15a66ce07e0482b92aa29e4dd0c5827a22d79 +F src/vdbe.c 5a1afb571853ddb911d698ac996bc4fd8ddf1eed F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h e2a060a55ee18a6ab973353a5e2ec7ee569bf787 F src/vdbeapi.c 37a6c6ae284a97bcace365f2f0a225680c0499d9 @@ -1062,7 +1062,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339 F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825 F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8 -F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb +F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32 F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae @@ -1204,11 +1204,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e4ab094f8afce0817f4074e823fabe59fc29ebb4 -Q +3e922208b68563489c7766abb9afb4885113e7b8 -R dac8a0df55bcef8314fa6cd2a33fc123 -T *branch * branch-3.8.7 -T *sym-branch-3.8.7 * -T -sym-trunk * +P a8f9bd1e890434fcffa02fcd2baf8b0fb5d4c9dd +Q +24780f8ddc1683fc62180e6961dc6bfe1168f4df +R d684ab06f9952cfb8bd4bb795d206cf9 U drh -Z 1e440e6f18a01c290161fa6c4a1f516b +Z 6a68e4e50056aa43b6faddb91db24dac diff --git a/manifest.uuid b/manifest.uuid index bf1f77f03a..e62a923d4d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a8f9bd1e890434fcffa02fcd2baf8b0fb5d4c9dd \ No newline at end of file +304ea6ba6f4cf40a76d32d37af73a253f493ba47 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 0f9f45c456..88fadb023e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2441,7 +2441,7 @@ case OP_Column: { if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); } goto op_column_out; } diff --git a/test/update.test b/test/update.test index e67b0efddc..d7baf6e702 100644 --- a/test/update.test +++ b/test/update.test @@ -604,5 +604,19 @@ do_test update-14.4 { } ;# ifcapable {trigger} +# Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29 +# An assertion fault on UPDATE +# +do_execsql_test update-15.1 { + CREATE TABLE t15(a INTEGER PRIMARY KEY, b); + INSERT INTO t15(a,b) VALUES(10,'abc'),(20,'def'),(30,'ghi'); + ALTER TABLE t15 ADD COLUMN c; + CREATE INDEX t15c ON t15(c); + INSERT INTO t15(a,b) + VALUES(5,'zyx'),(15,'wvu'),(25,'tsr'),(35,'qpo'); + UPDATE t15 SET c=printf("y%d",a) WHERE c IS NULL; + SELECT a,b,c,'|' FROM t15 ORDER BY a; +} {5 zyx y5 | 10 abc y10 | 15 wvu y15 | 20 def y20 | 25 tsr y25 | 30 ghi y30 | 35 qpo y35 |} + finish_test From bba8206be97e8b09ee9c135e94c55db10d4d19c0 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Oct 2014 01:18:03 +0000 Subject: [PATCH 03/71] Disable the use of strchrnul() unless specifically enabled by compile-time options. Cherrypick of check-in [e580470db77d6da9] FossilOrigin-Name: 837368adfe859c41b347d3124d5b3fdf790eec03 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/printf.c | 6 +----- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index d38979f110..f5c3788a32 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sOP_Column\sopcode,\swhen\sextracting\sa\sfield\sthat\sis\spast\sthe\send\sof\na\sshort\srecord\s(because\sthe\srow\swas\soriginally\sinserted\sprior\sto\sALTER\sTABLE\nADD\sCOLUMN)\sthen\smake\ssure\sthe\soutput\sregister\sis\sfully\sNULL\sand\sdoes\snot\ncontain\sleftover\sflags\s(such\sas\sMEM_Ephem)\sfrom\sits\sprevious\suse.\nFix\sfor\sticket\s[43107840f1c02].\s\sThis\sis\sa\scherrypick\sof\ncheck-in\s[24780f8ddc1683fc]. -D 2014-10-29T01:13:58.092 +C Disable\sthe\suse\sof\sstrchrnul()\sunless\sspecifically\senabled\sby\scompile-time\noptions.\s\sCherrypick\sof\scheck-in\s[e580470db77d6da9] +D 2014-10-29T01:18:03.185 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -223,7 +223,7 @@ F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5 F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196 -F src/printf.c 6b79bbd063dcbadca4cf617a4cde255bcc13ea64 +F src/printf.c 090fac0f779c93c8a95089a125339686648835e4 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e @@ -1204,8 +1204,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a8f9bd1e890434fcffa02fcd2baf8b0fb5d4c9dd -Q +24780f8ddc1683fc62180e6961dc6bfe1168f4df -R d684ab06f9952cfb8bd4bb795d206cf9 +P 304ea6ba6f4cf40a76d32d37af73a253f493ba47 +Q +e580470db77d6da970c755102790e603fb26b3c6 +R 87a2c5d1dcd7231208aa0589a51fed61 U drh -Z 6a68e4e50056aa43b6faddb91db24dac +Z b2af8bf5eda5ca802506e90d5ed9925a diff --git a/manifest.uuid b/manifest.uuid index e62a923d4d..3e0b305a64 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -304ea6ba6f4cf40a76d32d37af73a253f493ba47 \ No newline at end of file +837368adfe859c41b347d3124d5b3fdf790eec03 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index c0b3c70f6b..1df287fbb6 100644 --- a/src/printf.c +++ b/src/printf.c @@ -21,11 +21,7 @@ ** the glibc version so the glibc version is definitely preferred. */ #if !defined(HAVE_STRCHRNUL) -# if defined(linux) -# define HAVE_STRCHRNUL 1 -# else -# define HAVE_STRCHRNUL 0 -# endif +# define HAVE_STRCHRNUL 0 #endif From a26b9a77275e5ef76e2ba5ac0c480e70f5abeda4 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Oct 2014 01:26:25 +0000 Subject: [PATCH 04/71] Fix problems with running UPDATE and DELETE against a VIEW and referencing the rowid in the WHERE clause. This is a cherrypick of [95f8ebdbf87326f2] and [8523670d50004f3]. FossilOrigin-Name: cc33e846c8509419f0a1fbfb286807b4c137788d --- manifest | 19 ++++++++++--------- manifest.uuid | 2 +- src/delete.c | 2 +- src/update.c | 4 ++-- test/trigger9.test | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index f5c3788a32..be89f4c86a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Disable\sthe\suse\sof\sstrchrnul()\sunless\sspecifically\senabled\sby\scompile-time\noptions.\s\sCherrypick\sof\scheck-in\s[e580470db77d6da9] -D 2014-10-29T01:18:03.185 +C Fix\sproblems\swith\srunning\sUPDATE\sand\sDELETE\sagainst\sa\sVIEW\sand\sreferencing\nthe\srowid\sin\sthe\sWHERE\sclause.\s\sThis\sis\sa\scherrypick\sof\s[95f8ebdbf87326f2]\nand\s[8523670d50004f3]. +D 2014-10-29T01:26:25.633 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -180,7 +180,7 @@ F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14 F src/ctime.c bb434068b5308a857b181c2d204a320ff0d6c638 F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036 -F src/delete.c fae81cc2eb14b75267d4f47d3cfc9ae02aae726f +F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417 F src/expr.c fc204d08af06437ddaffe5a1b1f1f6f9e1a55d6d F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 @@ -285,7 +285,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6de09362b657f19ba83e5fa521ee715787ce9fee F src/tokenize.c cc9016e5007fc5e76789079616d2f26741bcc689 F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f -F src/update.c 729f6f18fc27740591d085e1172cebe311144bf0 +F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a @@ -1048,7 +1048,7 @@ F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4 F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 -F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31 +F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41 F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332 F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c @@ -1204,8 +1204,9 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 304ea6ba6f4cf40a76d32d37af73a253f493ba47 -Q +e580470db77d6da970c755102790e603fb26b3c6 -R 87a2c5d1dcd7231208aa0589a51fed61 +P 837368adfe859c41b347d3124d5b3fdf790eec03 +Q +8523670d50004f3112b7871f11c8b8b02aab96ab +Q +95f8ebdbf87326f23cd38e561ac5632b5367a449 +R b3ee8c71d158066739429e7ae8387325 U drh -Z b2af8bf5eda5ca802506e90d5ed9925a +Z 624aac6d2575ef133925a49cc2066eb1 diff --git a/manifest.uuid b/manifest.uuid index 3e0b305a64..99e8b826f5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -837368adfe859c41b347d3124d5b3fdf790eec03 \ No newline at end of file +cc33e846c8509419f0a1fbfb286807b4c137788d \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index b97407400b..d81dd3f6b4 100644 --- a/src/delete.c +++ b/src/delete.c @@ -481,7 +481,7 @@ void sqlite3DeleteFrom( assert( nKey==nPk ); /* OP_Found will use an unpacked key */ assert( !IsVirtual(pTab) ); if( aToOpen[iDataCur-iTabCur] ){ - assert( pPk!=0 ); + assert( pPk!=0 || pTab->pSelect!=0 ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } diff --git a/src/update.c b/src/update.c index f781a60ccd..3af4017f1b 100644 --- a/src/update.c +++ b/src/update.c @@ -431,8 +431,8 @@ void sqlite3Update( /* Top of the update loop */ if( okOnePass ){ - if( aToOpen[iDataCur-iBaseCur] ){ - assert( pPk!=0 ); + if( aToOpen[iDataCur-iBaseCur] && !isView ){ + assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); VdbeCoverageNeverTaken(v); } diff --git a/test/trigger9.test b/test/trigger9.test index f56c8acbc5..326fa63d4c 100644 --- a/test/trigger9.test +++ b/test/trigger9.test @@ -32,6 +32,7 @@ ifcapable {!trigger} { finish_test return } +set ::testprefix trigger9 proc has_rowdata {sql} { expr {[lsearch [execsql "explain $sql"] RowData]>=0} @@ -220,4 +221,36 @@ ifcapable compound { } {2} } +reset_db +do_execsql_test 4.1 { + CREATE TABLE t1(a, b); + CREATE TABLE log(x); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + CREATE VIEW v1 AS SELECT a, b FROM t1; + + CREATE TRIGGER tr1 INSTEAD OF DELETE ON v1 BEGIN + INSERT INTO log VALUES('delete'); + END; + + CREATE TRIGGER tr2 INSTEAD OF UPDATE ON v1 BEGIN + INSERT INTO log VALUES('update'); + END; + + CREATE TRIGGER tr3 INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO log VALUES('insert'); + END; +} + +do_execsql_test 4.2 { + DELETE FROM v1 WHERE rowid=1; +} {} + +do_execsql_test 4.3 { + UPDATE v1 SET a=b WHERE rowid=2; +} {} + + + + finish_test From 35404253f680a8d6939a09d24ad4286ade7b5e8f Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Oct 2014 01:27:43 +0000 Subject: [PATCH 05/71] Increase the version number to 3.8.7.1 FossilOrigin-Name: 83afe23e553e802c0947c80d0ffdd120423e7c52 --- VERSION | 2 +- configure | 18 +++++++++--------- manifest | 16 +++++++--------- manifest.uuid | 2 +- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/VERSION b/VERSION index 4351a7e3a3..f53c1ed56b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.7 +3.8.7.1 diff --git a/configure b/configure index 9b8266d812..d253f21a7d 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlite 3.8.7. +# Generated by GNU Autoconf 2.62 for sqlite 3.8.7.1. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.8.7' -PACKAGE_STRING='sqlite 3.8.7' +PACKAGE_VERSION='3.8.7.1' +PACKAGE_STRING='sqlite 3.8.7.1' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.8.7 to adapt to many kinds of systems. +\`configure' configures sqlite 3.8.7.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1548,7 +1548,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.7:";; + short | recursive ) echo "Configuration of sqlite 3.8.7.1:";; esac cat <<\_ACEOF @@ -1664,7 +1664,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.7 +sqlite configure 3.8.7.1 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.8.7, which was +It was created by sqlite $as_me 3.8.7.1, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ @@ -14021,7 +14021,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.8.7, which was +This file was extended by sqlite $as_me 3.8.7.1, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14074,7 +14074,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -sqlite config.status 3.8.7 +sqlite config.status 3.8.7.1 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/manifest b/manifest index be89f4c86a..916213d465 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Fix\sproblems\swith\srunning\sUPDATE\sand\sDELETE\sagainst\sa\sVIEW\sand\sreferencing\nthe\srowid\sin\sthe\sWHERE\sclause.\s\sThis\sis\sa\scherrypick\sof\s[95f8ebdbf87326f2]\nand\s[8523670d50004f3]. -D 2014-10-29T01:26:25.633 +C Increase\sthe\sversion\snumber\sto\s3.8.7.1 +D 2014-10-29T01:27:43.048 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.msc e31dee24038965fb6269d6d61073fd6b7e331dec F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0 F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8 -F VERSION 53a0b870e7f16d3b06623c31d233a304c163a6af +F VERSION 5cc0baaee7eeee3238f0f7b5871398d17f79d0cd F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure ad59a5f48b3c59a92b5506040a22fbe3f733a9d8 x +F configure 56fe985cf0e59cd594f9b929099d0be40260e667 x F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 @@ -1204,9 +1204,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 837368adfe859c41b347d3124d5b3fdf790eec03 -Q +8523670d50004f3112b7871f11c8b8b02aab96ab -Q +95f8ebdbf87326f23cd38e561ac5632b5367a449 -R b3ee8c71d158066739429e7ae8387325 +P cc33e846c8509419f0a1fbfb286807b4c137788d +R 5381895dceb9bc7ad4d425f399561cb7 U drh -Z 624aac6d2575ef133925a49cc2066eb1 +Z 906d83e1887c766ebb0692623bc0209a diff --git a/manifest.uuid b/manifest.uuid index 99e8b826f5..abe23b5708 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cc33e846c8509419f0a1fbfb286807b4c137788d \ No newline at end of file +83afe23e553e802c0947c80d0ffdd120423e7c52 \ No newline at end of file From 7abfe9d0c62966783f878c94ca07ee4f7a557b72 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Oct 2014 13:59:56 +0000 Subject: [PATCH 06/71] Version 3.8.7.1 FossilOrigin-Name: 3b7b72c4685aa5cf5e675c2c47ebec10d9704221 --- manifest | 11 +++++++---- manifest.uuid | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/manifest b/manifest index 916213d465..8688f8549f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\sversion\snumber\sto\s3.8.7.1 -D 2014-10-29T01:27:43.048 +C Version\s3.8.7.1 +D 2014-10-29T13:59:56.070 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -1204,7 +1204,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P cc33e846c8509419f0a1fbfb286807b4c137788d +P 83afe23e553e802c0947c80d0ffdd120423e7c52 R 5381895dceb9bc7ad4d425f399561cb7 +T +bgcolor * #d0c0ff +T +sym-release * +T +sym-version-3.8.7.1 * U drh -Z 906d83e1887c766ebb0692623bc0209a +Z e5ce942eb65e60b92fcaefcb5b84039b diff --git a/manifest.uuid b/manifest.uuid index abe23b5708..1787d659c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -83afe23e553e802c0947c80d0ffdd120423e7c52 \ No newline at end of file +3b7b72c4685aa5cf5e675c2c47ebec10d9704221 \ No newline at end of file From 04489b6dce1b28fffb9afa524b0eb854a400da21 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 31 Oct 2014 20:11:32 +0000 Subject: [PATCH 07/71] Add the experimental sqlite3_stmt_scanstatus() API. FossilOrigin-Name: 6a9bab34aeb6a01b612211a28c140de60a3e883c --- manifest | 34 ++++++++++++--------- manifest.uuid | 2 +- src/sqlite.h.in | 36 ++++++++++++++++++++++ src/tclsqlite.c | 42 +++++++++++++++++++++++++ src/test1.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ src/vdbe.c | 44 ++++++++++++++++++++++++-- src/vdbe.h | 16 ++++++++++ src/vdbeInt.h | 4 +++ src/vdbeapi.c | 37 ++++++++++++++++++++++ src/vdbeaux.c | 13 ++++++++ src/where.c | 55 +++++++++++++++++++++++++-------- test/scanstatus.test | 69 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 394 insertions(+), 31 deletions(-) create mode 100644 test/scanstatus.test diff --git a/manifest b/manifest index ce0614fbee..39eaf23ca4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\scommand-line\sshell\sman-page\sto\suse\sthe\s".tr"\stroff\sdirective\ninstead\sof\s".cc"\sfor\sescaping\sthe\sinitial\s"."\scharacters\sin\sthe\s".help"\noutput. -D 2014-10-31T14:46:51.896 +C Add\sthe\sexperimental\ssqlite3_stmt_scanstatus()\sAPI. +D 2014-10-31T20:11:32.562 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -229,15 +229,15 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 737b7dd0f3f81fe183646d22828b39f85ef3e68c +F src/sqlite.h.in 6e90cdb404e4fa8c0eb149ca79c11c6608a97ece F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 4f86ac648ea398c1bb3db036062934cde257ea23 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc -F src/tclsqlite.c c67d310c833046cccc192125d64ad422ab882684 -F src/test1.c 63d4b1707c4052cf9c05c1cbb4a62666d70a0b48 +F src/tclsqlite.c 7cdd4dd3c2a4183483feca260070d73d6e22cd47 +F src/test1.c b53f4da2f386efa5c248716cd4bdc8344a87e952 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -289,11 +289,11 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 49e659bc165e99b28492004b440e22146dc898ab -F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 -F src/vdbeInt.h acc36ac461f973f46ac7942f86abdd93d2f8cfbc -F src/vdbeapi.c 02d8afcff710eb35e3d9e49cb677308296b00009 -F src/vdbeaux.c 3d6b2b412ef2193aa4729922dfc5df1efadbf6df +F src/vdbe.c 80329be857cff3c2d6e8c1f594ac689166c44ae7 +F src/vdbe.h f8e5388173dbf8408da4ae1dcbf75911caf2253d +F src/vdbeInt.h 284b2294c188474daa9b5ce2bd0200560cb0940d +F src/vdbeapi.c 2afa2e162f290879ca9c51e8795a377035f1662a +F src/vdbeaux.c 1e2561eeb94749f6b8c0a1eb02b5fecb645ed48c F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 5665df88cbd2b38eb72b4b94c8892c8afb360181 +F src/where.c 344beac082f8f4f69ec7c4a669d74294475e5abe F src/whereInt.h 19279cd0664ce1d90b9ad3ef0108cb494acfe455 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -801,6 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 +F test/scanstatus.test a62dad3311fc51eab1d6977b082738bd2148fe07 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1210,7 +1211,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a07078b60007e88adea67bec5f0caf91f707ad78 -R f904ce78baced6aeb6bcb91c631714db -U drh -Z c463256d5d45e3bce4a212ca4dd9f3e4 +P 67f0d469da28c023200239a1f3d0c6cef9ef0e45 +R 4c76f3e7b97f67c1dd65bda3a6e96149 +T *branch * scanstatus +T *sym-scanstatus * +T -sym-trunk * +U dan +Z 4994ca943ee260eeca8f493b4f59766a diff --git a/manifest.uuid b/manifest.uuid index 4735237141..b7984cac38 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -67f0d469da28c023200239a1f3d0c6cef9ef0e45 \ No newline at end of file +6a9bab34aeb6a01b612211a28c140de60a3e883c \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index b4081f2a02..ba20cb9890 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7407,6 +7407,42 @@ int sqlite3_vtab_on_conflict(sqlite3 *); #define SQLITE_REPLACE 5 +/* +** Return status data for a single loop within query pStmt. +** +** 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. In this case the final value +** of all five output parameters is undefined. Otherwise, if idx is in range, +** the output parameters are populated and zero returned. +** +** Statistics may not be available for all loops in all statements. In cases +** where there exist loops with no available statistics, this function ignores +** them completely. +** +** This API is only available if the library is built with pre-processor +** symbol SQLITE_ENABLE_STMT_SCANSTATUS defined. +*/ +SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, + int idx, /* Index of loop to report on */ + sqlite3_int64 *pnLoop, /* OUT: Number of times loop was run */ + sqlite3_int64 *pnVisit, /* OUT: Number of rows visited (all loops) */ + sqlite3_int64 *pnEst, /* OUT: Number of rows estimated (per loop) */ + const char **pzName, /* OUT: Object name (table or index) */ + const char **pzExplain /* OUT: EQP string */ +); + + +/* +** 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*); + /* ** Undo the hack that converts floating point types to integer for diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 756d0daa5a..bff4a92421 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3641,6 +3641,45 @@ static int db_use_legacy_prepare_cmd( Tcl_ResetResult(interp); return TCL_OK; } + +/* +** Tclcmd: db_last_stmt_ptr DB +** +** If the statement cache associated with database DB is not empty, +** return the text representation of the most recently used statement +** handle. +*/ +static int db_last_stmt_ptr( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); + Tcl_CmdInfo cmdInfo; + SqliteDb *pDb; + sqlite3_stmt *pStmt = 0; + char zBuf[100]; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + + if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ + Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0); + return TCL_ERROR; + } + pDb = (SqliteDb*)cmdInfo.objClientData; + + if( pDb->stmtList ) pStmt = pDb->stmtList->pStmt; + if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ){ + return TCL_ERROR; + } + Tcl_SetResult(interp, zBuf, TCL_VOLATILE); + + return TCL_OK; +} #endif /* @@ -3760,6 +3799,9 @@ static void init_all(Tcl_Interp *interp){ Tcl_CreateObjCommand( interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 ); + Tcl_CreateObjCommand( + interp, "db_last_stmt_ptr", db_last_stmt_ptr, 0, 0 + ); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); diff --git a/src/test1.c b/src/test1.c index 802aa99b5b..72e70513bc 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2301,6 +2301,75 @@ static int test_stmt_status( return TCL_OK; } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Usage: sqlite3_stmt_scanstatus STMT IDX +*/ +static int test_stmt_scanstatus( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; /* First argument */ + int idx; /* Second argument */ + + const char *zName; + const char *zExplain; + sqlite3_int64 nLoop; + sqlite3_int64 nVisit; + sqlite3_int64 nEst; + int res; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX"); + return TCL_ERROR; + } + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; + + res = sqlite3_stmt_scanstatus( + pStmt, idx, &nLoop, &nVisit, &nEst, &zName, &zExplain + ); + if( res==0 ){ + Tcl_Obj *pRet = Tcl_NewObj(); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nEst)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1)); + Tcl_SetObjResult(interp, pRet); + }else{ + Tcl_ResetResult(interp); + } + return TCL_OK; +} + +/* +** Usage: sqlite3_stmt_scanstatus_reset STMT +*/ +static int test_stmt_scanstatus_reset( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; /* First argument */ + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT"); + return TCL_ERROR; + } + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + sqlite3_stmt_scanstatus_reset(pStmt); + return TCL_OK; +} +#endif + /* ** Usage: sqlite3_next_stmt DB STMT ** @@ -6868,6 +6937,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_user_change", test_user_change, 0 }, { "sqlite3_user_delete", test_user_delete, 0 }, #endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, + { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, +#endif }; static int bitmask_size = sizeof(Bitmask)*8; diff --git a/src/vdbe.c b/src/vdbe.c index c17bfdfe14..a92c0509b3 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -167,6 +167,18 @@ int sqlite3_found_count = 0; /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #define isSorter(x) ((x)->pSorter!=0) +/* +** The first argument passed to the IncrementExplainCounter() macro must +** be a non-NULL pointer to an object of type VdbeCursor. The second +** argument must be either "nLoop" or "nVisit" (without the double-quotes). +*/ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +# define IncrementExplainCounter(pCsr, counter) \ + if( (pCsr)->pExplain ) (pCsr)->pExplain->counter++ +#else +# define IncrementExplainCounter(pCsr, counter) +#endif + /* ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. @@ -3556,6 +3568,7 @@ case OP_SeekGT: { /* jump, in3 */ #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif + IncrementExplainCounter(pC, nLoop); if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do @@ -3664,6 +3677,8 @@ case OP_SeekGT: { /* jump, in3 */ VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; + }else{ + IncrementExplainCounter(pC, nVisit); } break; } @@ -4449,6 +4464,8 @@ case OP_Last: { /* jump */ res = 0; assert( pCrsr!=0 ); rc = sqlite3BtreeLast(pCrsr, &res); + IncrementExplainCounter(pC, nLoop); + if( res==0 ) IncrementExplainCounter(pC, nVisit); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -4488,9 +4505,9 @@ case OP_Sort: { /* jump */ ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. -** If the table or index is empty and P2>0, then jump immediately to P2. -** If P2 is 0 or if the table or index is not empty, fall through -** to the following instruction. +** If the table or index is empty, jump immediately to P2. +** If the table or index is not empty, fall through to the following +** instruction. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is @@ -4518,11 +4535,14 @@ case OP_Rewind: { /* jump */ pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } + IncrementExplainCounter(pC, nLoop); pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; + }else{ + IncrementExplainCounter(pC, nVisit); } break; } @@ -4633,6 +4653,7 @@ next_tail: pC->cacheStatus = CACHE_STALE; VdbeBranchTaken(res==0,2); if( res==0 ){ + IncrementExplainCounter(pC, nVisit); pC->nullRow = 0; pc = pOp->p2 - 1; p->aCounter[pOp->p5]++; @@ -6055,7 +6076,10 @@ case OP_VFilter: { /* jump */ VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; + }else{ + IncrementExplainCounter(pCur, nVisit); } + IncrementExplainCounter(pCur, nLoop); } pCur->nullRow = 0; @@ -6148,6 +6172,7 @@ case OP_VNext: { /* jump */ if( !res ){ /* If there is data, jump to P2 */ pc = pOp->p2 - 1; + IncrementExplainCounter(pCur, nVisit); } goto check_for_interrupt; } @@ -6347,6 +6372,19 @@ case OP_Init: { /* jump */ break; } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +case OP_Explain: { + ExplainArg *pArg; + VdbeCursor *pCur; + if( pOp->p4type==P4_EXPLAIN && (pArg = pOp->p4.pExplain)->iCsr>=0 ){ + pArg = pOp->p4.pExplain; + pCur = p->apCsr[pArg->iCsr]; + pCur->pExplain = pArg; + } + break; +} +#endif + /* Opcode: Noop * * * * * ** diff --git a/src/vdbe.h b/src/vdbe.h index f975f95543..1b470441be 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -25,6 +25,7 @@ ** of this structure. */ typedef struct Vdbe Vdbe; +typedef struct ExplainArg ExplainArg; /* ** The names of the following types declared in vdbeInt.h are required @@ -59,6 +60,7 @@ 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 */ + ExplainArg *pExplain; /* Used when p4type is P4_EXPLAIN */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS @@ -100,6 +102,19 @@ struct VdbeOpList { }; typedef struct VdbeOpList VdbeOpList; +/* +** Structure used as the P4 parameter for OP_Explain opcodes. +*/ +struct ExplainArg { + int iCsr; /* Cursor number this applies to */ + i64 nLoop; /* Number of times loop has run */ + i64 nVisit; /* Total number of rows visited */ + i64 nEst; /* Estimated number of rows per scan */ + const char *zName; /* Name of table/index being scanned */ + const char *zExplain; /* EQP text for this loop */ +}; + + /* ** Allowed values of VdbeOp.p4type */ @@ -119,6 +134,7 @@ typedef struct VdbeOpList VdbeOpList; #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_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ +#define P4_EXPLAIN (-20) /* P4 is a pointer to an instance of ExplainArg */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 623c5fdde8..839108f6bc 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -83,6 +83,7 @@ struct VdbeCursor { i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ + ExplainArg *pExplain; /* Object to store seek/visit counts (may be NULL) */ /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches @@ -291,6 +292,7 @@ struct Explain { char zBase[100]; /* Initial space */ }; + /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ @@ -368,6 +370,8 @@ struct Vdbe { int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ + ExplainArg **apExplain; /* Array of pointers to P4_EXPLAIN p4 values */ + int nExplain; /* Number of entries in array apExplain */ }; /* diff --git a/src/vdbeapi.c b/src/vdbeapi.c index daf7b101d2..b09faa1fa5 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1475,3 +1475,40 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } + +/* +** Return status data for a single loop within query pStmt. +*/ +int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, + int idx, /* Index of loop to report on */ + sqlite3_int64 *pnLoop, /* OUT: Number of times loop was run */ + sqlite3_int64 *pnVisit, /* OUT: Number of rows visited (all loops) */ + sqlite3_int64 *pnEst, /* OUT: Number of rows estimated (per loop) */ + const char **pzName, /* OUT: Object name (table or index) */ + const char **pzExplain /* OUT: EQP string */ +){ + Vdbe *p = (Vdbe*)pStmt; + ExplainArg *pExplain; + if( idx<0 || idx>=p->nExplain ) return 1; + pExplain = p->apExplain[idx]; + if( pnLoop ) *pnLoop = pExplain->nLoop; + if( pnVisit ) *pnVisit = pExplain->nVisit; + if( pnEst ) *pnEst = pExplain->nEst; + if( *pzName ) *pzName = pExplain->zName; + if( *pzExplain ) *pzExplain = pExplain->zExplain; + return 0; +} + +/* +** Zero all counters associated with the sqlite3_stmt_scanstatus() data. +*/ +void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe*)pStmt; + int i; + for(i=0; inExplain; i++){ + p->apExplain[i]->nLoop = 0; + p->apExplain[i]->nVisit = 0; + } +} + diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7dfb64130d..a8223890bd 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -672,6 +672,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ assert( db ); switch( p4type ){ + case P4_EXPLAIN: case P4_REAL: case P4_INT64: case P4_DYNAMIC: @@ -820,6 +821,13 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); + }else if( n==P4_EXPLAIN ){ + pOp->p4.p = (void*)zP4; + pOp->p4type = P4_EXPLAIN; + p->apExplain = (ExplainArg**)sqlite3DbReallocOrFree( + p->db, p->apExplain, sizeof(ExplainArg*) * p->nExplain + 1 + ); + if( p->apExplain ) p->apExplain[p->nExplain++] = (ExplainArg*)zP4; }else if( n<0 ){ pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; @@ -1103,6 +1111,10 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ zTemp[0] = 0; break; } + case P4_EXPLAIN: { + zP4 = (char*)pOp->p4.pExplain->zExplain; + break; + } default: { zP4 = pOp->p4.z; if( zP4==0 ){ @@ -2685,6 +2697,7 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); + sqlite3DbFree(db, p->apExplain); } /* diff --git a/src/where.c b/src/where.c index feccf2d11d..3565327b52 100644 --- a/src/where.c +++ b/src/where.c @@ -2820,7 +2820,7 @@ static void explainOneScan( int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ -#ifndef SQLITE_DEBUG +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pParse->explain==2 ) #endif { @@ -2831,20 +2831,38 @@ static void explainOneScan( int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ - char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ + const char *zObj; + ExplainArg *pExplain; + i64 nEstRow; /* Estimated rows per scan of pLevel */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; + sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + str.db = db; + + /* Reserve space at the start of the buffer managed by the StrAccum + ** object for *pExplain. */ + assert( sizeof(*pExplain)<=sizeof(zBuf) ); + str.nChar = sizeof(*pExplain); + + /* Append the object (table or index) name to the buffer. */ + if( pItem->pSelect ){ + zObj = ""; + }else if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ + zObj = pLoop->u.btree.pIndex->zName; + }else{ + zObj = pItem->zName; + } + sqlite3StrAccumAppend(&str, zObj, sqlite3Strlen30(zObj)+1); + + /* Append the EQP text to the buffer */ isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); - - sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - str.db = db; sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); @@ -2901,15 +2919,28 @@ static void explainOneScan( pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif + nEstRow = pLoop->nOut>=10 ? sqlite3LogEstToInt(pLoop->nOut) : 1; #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS - if( pLoop->nOut>=10 ){ - sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); - }else{ - sqlite3StrAccumAppend(&str, " (~1 row)", 9); - } + sqlite3XPrintf(&str, 0, " (~%llu rows)", nEstRow); #endif - zMsg = sqlite3StrAccumFinish(&str); - sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); + pExplain = (ExplainArg*)sqlite3StrAccumFinish(&str); + assert( pExplain || db->mallocFailed ); + if( pExplain ){ + memset(pExplain, 0, sizeof(*pExplain)); + if( pLoop->wsFlags & WHERE_INDEXED ){ + pExplain->iCsr = pLevel->iIdxCur; + }else if( pItem->pSelect==0 ){ + pExplain->iCsr = pLevel->iTabCur; + }else{ + pExplain->iCsr = -1; + } + pExplain->nEst = nEstRow; + pExplain->zName = (const char*)&pExplain[1]; + pExplain->zExplain = &pExplain->zName[sqlite3Strlen30(pExplain->zName)+1]; + sqlite3VdbeAddOp4(v, OP_Explain, + iId, iLevel, iFrom, (char*)pExplain,P4_EXPLAIN + ); + } } } #else diff --git a/test/scanstatus.test b/test/scanstatus.test new file mode 100644 index 0000000000..69a92dcb6a --- /dev/null +++ b/test/scanstatus.test @@ -0,0 +1,69 @@ +# 2014 November 1 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix scanstatus + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t2 VALUES('a', 'b'); + INSERT INTO t2 VALUES('c', 'd'); + INSERT INTO t2 VALUES('e', 'f'); +} + +proc do_scanstatus_test {tn res} { + set stmt [db_last_stmt_ptr db] + set idx 0 + set ret [list] + while {1} { + set r [sqlite3_stmt_scanstatus $stmt $idx] + if {[llength $r]==0} break + lappend ret {*}$r + incr idx + } + + uplevel [list do_test $tn [list set {} $ret] [list {*}$res]] +} + +do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 +do_scanstatus_test 1.2 { + nLoop 1 nVisit 2 nEst 1048576 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 1048576 zName t2 zExplain {SCAN TABLE t2} +} + +do_execsql_test 1.3 { + ANALYZE; + SELECT count(*) FROM t1, t2; +} 6 +do_scanstatus_test 1.4 { + nLoop 1 nVisit 2 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 3 zName t2 zExplain {SCAN TABLE t2} +} + +do_execsql_test 1.5 { + ANALYZE; + SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; +} 4 +do_scanstatus_test 1.6 { + nLoop 1 nVisit 2 nEst 2 zName t2 zExplain + {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 2 nVisit 4 nEst 2 zName t1 zExplain {SCAN TABLE t1} +} + + + + +finish_test From 89e71646df320b5ff107f618169227c5c7cac8eb Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 1 Nov 2014 18:08:04 +0000 Subject: [PATCH 08/71] Minor fixes and documentation improvements for sqlite3_stmt_scanstatus(). FossilOrigin-Name: 8d8cc9608d30bb65fffcfe488e904411cbbc7f41 --- manifest | 23 ++++---- manifest.uuid | 2 +- src/sqlite.h.in | 24 +++++++- src/vdbe.c | 3 + src/where.c | 40 +++++++++---- src/whereInt.h | 1 + test/scanstatus.test | 138 ++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 200 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 39eaf23ca4..8582d6b5e8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sexperimental\ssqlite3_stmt_scanstatus()\sAPI. -D 2014-10-31T20:11:32.562 +C Minor\sfixes\sand\sdocumentation\simprovements\sfor\ssqlite3_stmt_scanstatus(). +D 2014-11-01T18:08:04.130 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 6e90cdb404e4fa8c0eb149ca79c11c6608a97ece +F src/sqlite.h.in aeba29025ba5fc721a11c1b81ed8745f93029590 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 4f86ac648ea398c1bb3db036062934cde257ea23 @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 80329be857cff3c2d6e8c1f594ac689166c44ae7 +F src/vdbe.c 5240bad20ce0b707afee211f0c21a862b54b1e0b F src/vdbe.h f8e5388173dbf8408da4ae1dcbf75911caf2253d F src/vdbeInt.h 284b2294c188474daa9b5ce2bd0200560cb0940d F src/vdbeapi.c 2afa2e162f290879ca9c51e8795a377035f1662a @@ -302,8 +302,8 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 344beac082f8f4f69ec7c4a669d74294475e5abe -F src/whereInt.h 19279cd0664ce1d90b9ad3ef0108cb494acfe455 +F src/where.c 636ca646c8f2f53fd66f9ed5c773e84cb0c4b762 +F src/whereInt.h 99d324a8f921d7a40c605a8b197350c3cb18977d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 @@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 -F test/scanstatus.test a62dad3311fc51eab1d6977b082738bd2148fe07 +F test/scanstatus.test b4b1780bad243e1576329d05597b99f06886e4d2 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1211,10 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 67f0d469da28c023200239a1f3d0c6cef9ef0e45 -R 4c76f3e7b97f67c1dd65bda3a6e96149 -T *branch * scanstatus -T *sym-scanstatus * -T -sym-trunk * +P 6a9bab34aeb6a01b612211a28c140de60a3e883c +R d964f269915d57cf95d9198c6ba22665 U dan -Z 4994ca943ee260eeca8f493b4f59766a +Z 082decdd6298ff1a2330407f8d406dfb diff --git a/manifest.uuid b/manifest.uuid index b7984cac38..7325586095 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6a9bab34aeb6a01b612211a28c140de60a3e883c \ No newline at end of file +8d8cc9608d30bb65fffcfe488e904411cbbc7f41 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ba20cb9890..51383426d9 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7408,6 +7408,8 @@ int sqlite3_vtab_on_conflict(sqlite3 *); /* +** CAPI3REF: Prepared Statement Scan Statuses +** ** Return status data for a single loop within query pStmt. ** ** Parameter "idx" identifies the specific loop to retrieve statistics for. @@ -7415,7 +7417,25 @@ int sqlite3_vtab_on_conflict(sqlite3 *); ** zero or greater than or equal to the total number of loops used to implement ** the statement - a non-zero value is returned. In this case the final value ** of all five output parameters is undefined. Otherwise, if idx is in range, -** the output parameters are populated and zero returned. +** zero is returned and the output parameters set as follows: +** +**
    +**
  • (*pnLoop) is set to the total number of times the loop has been run. +**
  • (*pnVisit) is set to the total number of rows visited by the loop. +**
  • (*pnEst) is set to the estimate of the number of rows visited +** by each run of the loop used by the SQL optimizer. Ideally, this +** value should be close to (*pnVisit)/(*pnLoop). +**
  • (*pzName) is set to point to a nul-terminated string containing the +** name of the index of table used by this loop. +**
  • (*pzExplain) is set to point to a nul-terminated string containing +** same text that would be returned for this loop by an EXPLAIN +** QUERY PLAN command. +**
+** +** Output parameters *pzName and *pzExplain are set to point to buffers +** managed by the statement object. Both of these pointers may be invalidated +** by any API call on the same statement object, including an sqlite3_step() +** sqlite3_bind_*() call. ** ** Statistics may not be available for all loops in all statements. In cases ** where there exist loops with no available statistics, this function ignores @@ -7436,6 +7456,8 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( /* +** 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 diff --git a/src/vdbe.c b/src/vdbe.c index a92c0509b3..1abccfeeab 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3889,6 +3889,7 @@ case OP_NotExists: { /* jump, in3 */ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); + IncrementExplainCounter(pC, nLoop); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; @@ -3896,6 +3897,8 @@ case OP_NotExists: { /* jump, in3 */ VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; + }else{ + IncrementExplainCounter(pC, nVisit); } pC->seekResult = res; break; diff --git a/src/where.c b/src/where.c index 3565327b52..ae3c12725e 100644 --- a/src/where.c +++ b/src/where.c @@ -2739,7 +2739,7 @@ static int codeAllEqualityTerms( return regBase; } -#ifndef SQLITE_OMIT_EXPLAIN +#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_STMT_SCANSTATUS) /* ** This routine is a helper for explainIndexRange() below ** @@ -2815,19 +2815,23 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ static void explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ - WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + WhereInfo *pWInfo, /* WHERE clause this loop belongs to */ int iLevel, /* Value for "level" column of output */ - int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pParse->explain==2 ) #endif { + WhereLevel *pLevel = &pWInfo->a[iLevel]; struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ - int iId = pParse->iSelectId; /* Select id (left-most output column) */ +#ifdef SQLITE_OMIT_EXPLAIN + int iId = 0; /* Select id (left-most output column) */ +#else + int iId = pParse->iSelectId; /* Select id (left-most output column) */ +#endif int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ @@ -2839,7 +2843,7 @@ static void explainOneScan( pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; + if( (flags&WHERE_MULTI_OR) ) return; sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.db = db; @@ -2865,7 +2869,11 @@ static void explainOneScan( || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ +#ifdef SQLITE_OMIT_EXPLAIN + sqlite3XPrintf(&str, 0, " SUBQUERY 0"); +#else sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); +#endif }else{ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } @@ -2937,15 +2945,15 @@ static void explainOneScan( pExplain->nEst = nEstRow; pExplain->zName = (const char*)&pExplain[1]; pExplain->zExplain = &pExplain->zName[sqlite3Strlen30(pExplain->zName)+1]; - sqlite3VdbeAddOp4(v, OP_Explain, - iId, iLevel, iFrom, (char*)pExplain,P4_EXPLAIN + pWInfo->iExplain = sqlite3VdbeAddOp4(v, OP_Explain, + iId, iLevel, pLevel->iFrom, (char*)pExplain,P4_EXPLAIN ); } } } #else -# define explainOneScan(u,v,w,x,y,z) -#endif /* SQLITE_OMIT_EXPLAIN */ +# define explainOneScan(v,w,x,y,z) +#endif /* !SQLITE_OMIT_EXPLAIN || SQLITE_ENABLE_STMT_SCANSTATUS */ /* @@ -3613,9 +3621,15 @@ static Bitmask codeOneLoopStart( assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; - explainOneScan( - pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 - ); + + /* If an OP_Explain was added for this sub-loop, fix the P2 and + ** P3 parameters to it so that they are relative to the current + ** context. */ + if( pSubWInfo->iExplain!=0 ){ + sqlite3VdbeChangeP2(v, pSubWInfo->iExplain, iLevel); + sqlite3VdbeChangeP3(v, pSubWInfo->iExplain, pLevel->iFrom); + } + /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same @@ -6455,7 +6469,7 @@ WhereInfo *sqlite3WhereBegin( if( db->mallocFailed ) goto whereBeginError; } #endif - explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); + explainOneScan(pParse, pTabList, pWInfo, ii, wctrlFlags); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; diff --git a/src/whereInt.h b/src/whereInt.h index fd4cfdf88a..dcf0e00604 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -407,6 +407,7 @@ struct WhereInfo { int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ + int iExplain; /* Address of OP_Explain (if WHERE_ONETABLE_ONLY) */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ diff --git a/test/scanstatus.test b/test/scanstatus.test index 69a92dcb6a..9df80f9ba8 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -53,16 +53,148 @@ do_scanstatus_test 1.4 { nLoop 2 nVisit 6 nEst 3 zName t2 zExplain {SCAN TABLE t2} } -do_execsql_test 1.5 { - ANALYZE; +do_execsql_test 1.5 { ANALYZE } +do_execsql_test 1.6 { SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; } 4 -do_scanstatus_test 1.6 { +do_scanstatus_test 1.7 { nLoop 1 nVisit 2 nEst 2 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 2 nVisit 4 nEst 2 zName t1 zExplain {SCAN TABLE t1} } +do_execsql_test 1.8 { + SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; +} 4 + +do_scanstatus_test 1.9 { + nLoop 2 nVisit 4 nEst 2 zName t2 zExplain + {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 4 nVisit 8 nEst 2 zName t1 zExplain {SCAN TABLE t1} +} + +do_test 1.9 { + sqlite3_stmt_scanstatus_reset [db_last_stmt_ptr db] +} {} + +do_scanstatus_test 1.10 { + nLoop 0 nVisit 0 nEst 2 zName t2 zExplain + {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 0 nVisit 0 nEst 2 zName t1 zExplain {SCAN TABLE t1} +} + +#------------------------------------------------------------------------- +# Try a few different types of scans. +# +reset_db +do_execsql_test 2.1 { + CREATE TABLE x1(i INTEGER PRIMARY KEY, j); + INSERT INTO x1 VALUES(1, 'one'); + INSERT INTO x1 VALUES(2, 'two'); + INSERT INTO x1 VALUES(3, 'three'); + INSERT INTO x1 VALUES(4, 'four'); + CREATE INDEX x1j ON x1(j); + + SELECT * FROM x1 WHERE i=2; +} {2 two} + +do_scanstatus_test 2.2 { + nLoop 1 nVisit 1 nEst 1 zName x1 + zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)} +} + +do_execsql_test 2.3.1 { + SELECT * FROM x1 WHERE j='two' +} {2 two} +do_scanstatus_test 2.3.2 { + nLoop 1 nVisit 1 nEst 10 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} +} + +do_execsql_test 2.4.1 { + SELECT * FROM x1 WHERE j<'two' +} {4 four 1 one 3 three} +do_scanstatus_test 2.4.2 { + nLoop 1 nVisit 4 nEst 262144 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j='two' +} {2 two} +do_scanstatus_test 2.5.2 { + nLoop 1 nVisit 1 nEst 262144 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>?)} +} + +do_execsql_test 2.6.1 { + SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two' +} {3 three 2 two} +do_scanstatus_test 2.6.2 { + nLoop 1 nVisit 2 nEst 16384 zName x1j + zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j? AND j Date: Sat, 1 Nov 2014 18:32:18 +0000 Subject: [PATCH 09/71] Add requirements marks and make minor tweaks to documentation. FossilOrigin-Name: 49188b2bb53a92b0b0b6aaf8247edeb0c1bcd1f5 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/main.c | 15 +++++++++++---- src/sqlite.h.in | 4 ++-- src/sqliteInt.h | 7 +++---- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index ce0614fbee..8ab904b8d2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\scommand-line\sshell\sman-page\sto\suse\sthe\s".tr"\stroff\sdirective\ninstead\sof\s".cc"\sfor\sescaping\sthe\sinitial\s"."\scharacters\sin\sthe\s".help"\noutput. -D 2014-10-31T14:46:51.896 +C Add\srequirements\smarks\sand\smake\sminor\stweaks\sto\sdocumentation. +D 2014-11-01T18:32:18.050 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c 2b882f64580ea72e2d972a5296f9eaa75a353161 +F src/main.c 5f659bdb14cdba1c3b587b6ed09167c147e308a1 F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -229,10 +229,10 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 737b7dd0f3f81fe183646d22828b39f85ef3e68c +F src/sqlite.h.in c3c6180be49d91d3b0001a8d3c604684f361adc2 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 4f86ac648ea398c1bb3db036062934cde257ea23 +F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc @@ -1210,7 +1210,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a07078b60007e88adea67bec5f0caf91f707ad78 -R f904ce78baced6aeb6bcb91c631714db +P 67f0d469da28c023200239a1f3d0c6cef9ef0e45 +R dbf6a8dc4a878d1b1a7b9b3874ca58fb U drh -Z c463256d5d45e3bce4a212ca4dd9f3e4 +Z 455c35adeade418fab0456b1b175d27f diff --git a/manifest.uuid b/manifest.uuid index 4735237141..02f906627f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -67f0d469da28c023200239a1f3d0c6cef9ef0e45 \ No newline at end of file +49188b2bb53a92b0b0b6aaf8247edeb0c1bcd1f5 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 5308698797..65a662ee5a 100644 --- a/src/main.c +++ b/src/main.c @@ -329,15 +329,17 @@ int sqlite3_config(int op, ...){ switch( op ){ /* Mutex configuration options are only available in a threadsafe - ** compile. + ** compile. */ -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ case SQLITE_CONFIG_SINGLETHREAD: { /* Disable all mutexing */ sqlite3GlobalConfig.bCoreMutex = 0; sqlite3GlobalConfig.bFullMutex = 0; break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ case SQLITE_CONFIG_MULTITHREAD: { /* Disable mutexing of database connections */ /* Enable mutexing of core data structures */ @@ -345,17 +347,23 @@ int sqlite3_config(int op, ...){ sqlite3GlobalConfig.bFullMutex = 0; break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ case SQLITE_CONFIG_SERIALIZED: { /* Enable all mutexing */ sqlite3GlobalConfig.bCoreMutex = 1; sqlite3GlobalConfig.bFullMutex = 1; break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ case SQLITE_CONFIG_MUTEX: { /* Specify an alternative mutex implementation */ sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); break; } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ case SQLITE_CONFIG_GETMUTEX: { /* Retrieve the current mutex implementation */ *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; @@ -363,7 +371,6 @@ int sqlite3_config(int op, ...){ } #endif - case SQLITE_CONFIG_MALLOC: { /* Specify an alternative malloc implementation */ sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); @@ -377,7 +384,7 @@ int sqlite3_config(int op, ...){ } case SQLITE_CONFIG_MEMSTATUS: { /* Enable or disable the malloc status collection */ - sqlite3GlobalConfig.bMemstat = va_arg(ap, int); + sqlite3GlobalConfig.bMemstat = va_arg(ap, int); /* IMP: R-27464-47829 */ break; } case SQLITE_CONFIG_SCRATCH: { diff --git a/src/sqlite.h.in b/src/sqlite.h.in index b4081f2a02..d0f213f156 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1532,10 +1532,10 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
**
^This option specifies a static memory buffer that SQLite can use for -** scratch memory. There are three arguments: A pointer an 8-byte +** scratch memory. ^(There are three arguments: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N). The sz +** and the maximum number of scratch allocations (N).)^ The sz ** argument must be a multiple of 16. ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f4785411d5..e9715efcf7 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -193,10 +193,9 @@ #endif /* -** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1. -** It determines whether or not the features related to -** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can -** be overridden at runtime using the sqlite3_config() API. +** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by +** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in +** which case memory allocation statistics are disabled by default. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) # define SQLITE_DEFAULT_MEMSTATUS 1 From 6f9702ed4dd4a6312e8a4e4ec9ae174d931298c8 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 1 Nov 2014 20:38:06 +0000 Subject: [PATCH 10/71] If SQLITE_ENABLE_STMT_SCANSTATUS is defined, record the number of times each VDBE opcode is executed. Derive the values returned by sqlite3_stmt_scanstatus() from these records on demand. FossilOrigin-Name: 9ea37422a8cc2fce51bb10508e5e90f40fd4b511 --- manifest | 26 ++++----- manifest.uuid | 2 +- src/vdbe.c | 44 +------------- src/vdbe.h | 22 ++----- src/vdbeInt.h | 18 ++++-- src/vdbeapi.c | 30 +++++----- src/vdbeaux.c | 52 ++++++++++++----- src/where.c | 134 +++++++++++++++++++++---------------------- src/whereInt.h | 3 + test/scanstatus.test | 49 +++++++++++++--- 10 files changed, 203 insertions(+), 177 deletions(-) diff --git a/manifest b/manifest index 8582d6b5e8..c81e911395 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sfixes\sand\sdocumentation\simprovements\sfor\ssqlite3_stmt_scanstatus(). -D 2014-11-01T18:08:04.130 +C If\sSQLITE_ENABLE_STMT_SCANSTATUS\sis\sdefined,\srecord\sthe\snumber\sof\stimes\seach\sVDBE\sopcode\sis\sexecuted.\sDerive\sthe\svalues\sreturned\sby\ssqlite3_stmt_scanstatus()\sfrom\sthese\srecords\son\sdemand. +D 2014-11-01T20:38:06.833 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,11 +289,11 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 5240bad20ce0b707afee211f0c21a862b54b1e0b -F src/vdbe.h f8e5388173dbf8408da4ae1dcbf75911caf2253d -F src/vdbeInt.h 284b2294c188474daa9b5ce2bd0200560cb0940d -F src/vdbeapi.c 2afa2e162f290879ca9c51e8795a377035f1662a -F src/vdbeaux.c 1e2561eeb94749f6b8c0a1eb02b5fecb645ed48c +F src/vdbe.c 69d025732d242d7c97282e6570a4e5eb768ebaff +F src/vdbe.h 7d603b93d128e614ba2600f12a6c541435405522 +F src/vdbeInt.h ee8d44cba5998279039bcd91ebddb6d9a2d463b8 +F src/vdbeapi.c 19e433e69fe2b27bfc9337a207b6ebf499f41d03 +F src/vdbeaux.c bad342af7cadb8d3bf2990700a78787d602dcd69 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 @@ -302,8 +302,8 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 636ca646c8f2f53fd66f9ed5c773e84cb0c4b762 -F src/whereInt.h 99d324a8f921d7a40c605a8b197350c3cb18977d +F src/where.c fb404e3db40db61c212ffb39022e885a91252498 +F src/whereInt.h a2bc22f4e3e70eeaa57272f354c288bc3b71b80b F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 @@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 -F test/scanstatus.test b4b1780bad243e1576329d05597b99f06886e4d2 +F test/scanstatus.test 40c7712c8bc0adc3fb88e0419356880679a3a5fb F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 6a9bab34aeb6a01b612211a28c140de60a3e883c -R d964f269915d57cf95d9198c6ba22665 +P 8d8cc9608d30bb65fffcfe488e904411cbbc7f41 +R e1e809461d373caeeb0e83f126874426 U dan -Z 082decdd6298ff1a2330407f8d406dfb +Z 5d5debb04affeaeb7378f6b538c8f641 diff --git a/manifest.uuid b/manifest.uuid index 7325586095..f70d7e8aef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8d8cc9608d30bb65fffcfe488e904411cbbc7f41 \ No newline at end of file +9ea37422a8cc2fce51bb10508e5e90f40fd4b511 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 1abccfeeab..bc49505dd0 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -167,18 +167,6 @@ int sqlite3_found_count = 0; /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #define isSorter(x) ((x)->pSorter!=0) -/* -** The first argument passed to the IncrementExplainCounter() macro must -** be a non-NULL pointer to an object of type VdbeCursor. The second -** argument must be either "nLoop" or "nVisit" (without the double-quotes). -*/ -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -# define IncrementExplainCounter(pCsr, counter) \ - if( (pCsr)->pExplain ) (pCsr)->pExplain->counter++ -#else -# define IncrementExplainCounter(pCsr, counter) -#endif - /* ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. @@ -620,6 +608,9 @@ int sqlite3VdbeExec( #endif nVmStep++; pOp = &aOp[pc]; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + if( p->pFrame==0 ) p->anExec[pc]++; +#endif /* Only allow tracing if SQLITE_DEBUG is defined. */ @@ -3568,7 +3559,6 @@ case OP_SeekGT: { /* jump, in3 */ #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif - IncrementExplainCounter(pC, nLoop); if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do @@ -3677,8 +3667,6 @@ case OP_SeekGT: { /* jump, in3 */ VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; - }else{ - IncrementExplainCounter(pC, nVisit); } break; } @@ -3889,7 +3877,6 @@ case OP_NotExists: { /* jump, in3 */ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); - IncrementExplainCounter(pC, nLoop); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; @@ -3897,8 +3884,6 @@ case OP_NotExists: { /* jump, in3 */ VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; - }else{ - IncrementExplainCounter(pC, nVisit); } pC->seekResult = res; break; @@ -4467,8 +4452,6 @@ case OP_Last: { /* jump */ res = 0; assert( pCrsr!=0 ); rc = sqlite3BtreeLast(pCrsr, &res); - IncrementExplainCounter(pC, nLoop); - if( res==0 ) IncrementExplainCounter(pC, nVisit); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; @@ -4538,14 +4521,11 @@ case OP_Rewind: { /* jump */ pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } - IncrementExplainCounter(pC, nLoop); pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; - }else{ - IncrementExplainCounter(pC, nVisit); } break; } @@ -4656,7 +4636,6 @@ next_tail: pC->cacheStatus = CACHE_STALE; VdbeBranchTaken(res==0,2); if( res==0 ){ - IncrementExplainCounter(pC, nVisit); pC->nullRow = 0; pc = pOp->p2 - 1; p->aCounter[pOp->p5]++; @@ -6079,10 +6058,7 @@ case OP_VFilter: { /* jump */ VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; - }else{ - IncrementExplainCounter(pCur, nVisit); } - IncrementExplainCounter(pCur, nLoop); } pCur->nullRow = 0; @@ -6175,7 +6151,6 @@ case OP_VNext: { /* jump */ if( !res ){ /* If there is data, jump to P2 */ pc = pOp->p2 - 1; - IncrementExplainCounter(pCur, nVisit); } goto check_for_interrupt; } @@ -6375,19 +6350,6 @@ case OP_Init: { /* jump */ break; } -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -case OP_Explain: { - ExplainArg *pArg; - VdbeCursor *pCur; - if( pOp->p4type==P4_EXPLAIN && (pArg = pOp->p4.pExplain)->iCsr>=0 ){ - pArg = pOp->p4.pExplain; - pCur = p->apCsr[pArg->iCsr]; - pCur->pExplain = pArg; - } - break; -} -#endif - /* Opcode: Noop * * * * * ** diff --git a/src/vdbe.h b/src/vdbe.h index 1b470441be..966fdb622e 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -25,7 +25,6 @@ ** of this structure. */ typedef struct Vdbe Vdbe; -typedef struct ExplainArg ExplainArg; /* ** The names of the following types declared in vdbeInt.h are required @@ -60,7 +59,6 @@ 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 */ - ExplainArg *pExplain; /* Used when p4type is P4_EXPLAIN */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS @@ -102,19 +100,6 @@ struct VdbeOpList { }; typedef struct VdbeOpList VdbeOpList; -/* -** Structure used as the P4 parameter for OP_Explain opcodes. -*/ -struct ExplainArg { - int iCsr; /* Cursor number this applies to */ - i64 nLoop; /* Number of times loop has run */ - i64 nVisit; /* Total number of rows visited */ - i64 nEst; /* Estimated number of rows per scan */ - const char *zName; /* Name of table/index being scanned */ - const char *zExplain; /* EQP text for this loop */ -}; - - /* ** Allowed values of VdbeOp.p4type */ @@ -134,7 +119,6 @@ struct ExplainArg { #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_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ -#define P4_EXPLAIN (-20) /* P4 is a pointer to an instance of ExplainArg */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -298,4 +282,10 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); # define VDBE_OFFSET_LINENO(x) 0 #endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +void sqlite3VdbeScanCounter(Vdbe*, int, int, int, i64, const char*); +#else +# define sqlite3VdbeScanCounter(a,b,c,d,e) +#endif + #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 839108f6bc..9f21ac7ebf 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -83,7 +83,6 @@ struct VdbeCursor { i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ - ExplainArg *pExplain; /* Object to store seek/visit counts (may be NULL) */ /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches @@ -292,12 +291,20 @@ struct Explain { char zBase[100]; /* Initial space */ }; - /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ typedef unsigned bft; /* Bit Field Type */ +typedef struct ScanCounter ScanCounter; +struct ScanCounter { + int addrExplain; /* OP_Explain for loop */ + int addrLoop; /* Address of "loops" counter */ + int addrVisit; /* Address of "rows visited" counter */ + i64 nEst; /* Estimated rows per loop */ + char *zName; /* Name of table or index */ +}; + /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. @@ -370,8 +377,11 @@ struct Vdbe { int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ - ExplainArg **apExplain; /* Array of pointers to P4_EXPLAIN p4 values */ - int nExplain; /* Number of entries in array apExplain */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + i64 *anExec; /* Number of times each op has been executed */ + int nScan; /* Entries in aScan[] */ + ScanCounter *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ +#endif }; /* diff --git a/src/vdbeapi.c b/src/vdbeapi.c index b09faa1fa5..f2e124dc51 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1476,6 +1476,7 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ return (int)v; } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Return status data for a single loop within query pStmt. */ @@ -1489,14 +1490,20 @@ int sqlite3_stmt_scanstatus( const char **pzExplain /* OUT: EQP string */ ){ Vdbe *p = (Vdbe*)pStmt; - ExplainArg *pExplain; - if( idx<0 || idx>=p->nExplain ) return 1; - pExplain = p->apExplain[idx]; - if( pnLoop ) *pnLoop = pExplain->nLoop; - if( pnVisit ) *pnVisit = pExplain->nVisit; - if( pnEst ) *pnEst = pExplain->nEst; - if( *pzName ) *pzName = pExplain->zName; - if( *pzExplain ) *pzExplain = pExplain->zExplain; + ScanCounter *pScan; + if( idx<0 || idx>=p->nScan ) return 1; + pScan = &p->aScan[idx]; + if( pnLoop ) *pnLoop = p->anExec[pScan->addrLoop]; + if( pnVisit ) *pnVisit = p->anExec[pScan->addrVisit]; + if( pnEst ) *pnEst = pScan->nEst; + if( *pzName ) *pzName = pScan->zName; + if( *pzExplain ){ + if( pScan->addrExplain ){ + *pzExplain = p->aOp[ pScan->addrExplain ].p4.z; + }else{ + *pzExplain = 0; + } + } return 0; } @@ -1505,10 +1512,7 @@ int sqlite3_stmt_scanstatus( */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; - int i; - for(i=0; inExplain; i++){ - p->apExplain[i]->nLoop = 0; - p->apExplain[i]->nVisit = 0; - } + memset(p->anExec, 0, p->nOp * sizeof(i64)); } +#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index a8223890bd..3f75cfee7a 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -597,6 +597,34 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ return addr; } +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) +/* +** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). +*/ +void sqlite3VdbeScanCounter( + Vdbe *p, /* VM to add scanstatus() to */ + int addrExplain, /* Address of OP_Explain (or 0) */ + int addrLoop, /* Address of loop counter */ + int addrVisit, /* Address of rows visited counter */ + i64 nEst, /* Estimated number of rows */ + const char *zName /* Name of table or index being scanned */ +){ + int nByte = (p->nScan+1) * sizeof(ScanCounter); + ScanCounter *aNew; + aNew = (ScanCounter*)sqlite3DbRealloc(p->db, p->aScan, nByte); + if( aNew ){ + ScanCounter *pNew = &aNew[p->nScan++]; + pNew->addrExplain = addrExplain; + pNew->addrLoop = addrLoop; + pNew->addrVisit = addrVisit; + pNew->nEst = nEst; + pNew->zName = sqlite3DbStrDup(p->db, zName); + p->aScan = aNew; + } +} +#endif + + /* ** Change the value of the P1 operand for a specific instruction. ** This routine is useful when a large program is loaded from a @@ -672,7 +700,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ assert( db ); switch( p4type ){ - case P4_EXPLAIN: case P4_REAL: case P4_INT64: case P4_DYNAMIC: @@ -821,13 +848,6 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); - }else if( n==P4_EXPLAIN ){ - pOp->p4.p = (void*)zP4; - pOp->p4type = P4_EXPLAIN; - p->apExplain = (ExplainArg**)sqlite3DbReallocOrFree( - p->db, p->apExplain, sizeof(ExplainArg*) * p->nExplain + 1 - ); - if( p->apExplain ) p->apExplain[p->nExplain++] = (ExplainArg*)zP4; }else if( n<0 ){ pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; @@ -1111,10 +1131,6 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ zTemp[0] = 0; break; } - case P4_EXPLAIN: { - zP4 = (char*)pOp->p4.pExplain->zExplain; - break; - } default: { zP4 = pOp->p4.z; if( zP4==0 ){ @@ -1714,6 +1730,10 @@ void sqlite3VdbeMakeReady( zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = (i64*)sqlite3DbMallocZero(db, p->nOp*sizeof(i64)); +#endif + p->nCursor = nCursor; p->nOnceFlag = nOnce; if( p->aVar ){ @@ -2697,7 +2717,13 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); - sqlite3DbFree(db, p->apExplain); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + sqlite3DbFree(db, p->anExec); + for(i=0; inScan; i++){ + sqlite3DbFree(db, p->aScan[i].zName); + } + sqlite3DbFree(db, p->aScan); +#endif } /* diff --git a/src/where.c b/src/where.c index ae3c12725e..8151a7057b 100644 --- a/src/where.c +++ b/src/where.c @@ -2739,7 +2739,7 @@ static int codeAllEqualityTerms( return regBase; } -#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_STMT_SCANSTATUS) +#ifndef SQLITE_OMIT_EXPLAIN /* ** This routine is a helper for explainIndexRange() below ** @@ -2812,68 +2812,43 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ ** record is added to the output to describe the table scan strategy in ** pLevel. */ -static void explainOneScan( +static int explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ - WhereInfo *pWInfo, /* WHERE clause this loop belongs to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ int iLevel, /* Value for "level" column of output */ + int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ -#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) + int ret = 0; +#ifndef SQLITE_DEBUG if( pParse->explain==2 ) #endif { - WhereLevel *pLevel = &pWInfo->a[iLevel]; struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ -#ifdef SQLITE_OMIT_EXPLAIN - int iId = 0; /* Select id (left-most output column) */ -#else - int iId = pParse->iSelectId; /* Select id (left-most output column) */ -#endif + int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ + char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ - const char *zObj; - ExplainArg *pExplain; - i64 nEstRow; /* Estimated rows per scan of pLevel */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) ) return; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; - sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - str.db = db; - - /* Reserve space at the start of the buffer managed by the StrAccum - ** object for *pExplain. */ - assert( sizeof(*pExplain)<=sizeof(zBuf) ); - str.nChar = sizeof(*pExplain); - - /* Append the object (table or index) name to the buffer. */ - if( pItem->pSelect ){ - zObj = ""; - }else if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ - zObj = pLoop->u.btree.pIndex->zName; - }else{ - zObj = pItem->zName; - } - sqlite3StrAccumAppend(&str, zObj, sqlite3Strlen30(zObj)+1); - - /* Append the EQP text to the buffer */ isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); + + sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + str.db = db; sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ -#ifdef SQLITE_OMIT_EXPLAIN - sqlite3XPrintf(&str, 0, " SUBQUERY 0"); -#else sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); -#endif }else{ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } @@ -2927,33 +2902,48 @@ static void explainOneScan( pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif - nEstRow = pLoop->nOut>=10 ? sqlite3LogEstToInt(pLoop->nOut) : 1; #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS - sqlite3XPrintf(&str, 0, " (~%llu rows)", nEstRow); -#endif - pExplain = (ExplainArg*)sqlite3StrAccumFinish(&str); - assert( pExplain || db->mallocFailed ); - if( pExplain ){ - memset(pExplain, 0, sizeof(*pExplain)); - if( pLoop->wsFlags & WHERE_INDEXED ){ - pExplain->iCsr = pLevel->iIdxCur; - }else if( pItem->pSelect==0 ){ - pExplain->iCsr = pLevel->iTabCur; - }else{ - pExplain->iCsr = -1; - } - pExplain->nEst = nEstRow; - pExplain->zName = (const char*)&pExplain[1]; - pExplain->zExplain = &pExplain->zName[sqlite3Strlen30(pExplain->zName)+1]; - pWInfo->iExplain = sqlite3VdbeAddOp4(v, OP_Explain, - iId, iLevel, pLevel->iFrom, (char*)pExplain,P4_EXPLAIN - ); + if( pLoop->nOut>=10 ){ + sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + }else{ + sqlite3StrAccumAppend(&str, " (~1 row)", 9); } +#endif + zMsg = sqlite3StrAccumFinish(&str); + ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); } + return ret; } #else -# define explainOneScan(v,w,x,y,z) -#endif /* !SQLITE_OMIT_EXPLAIN || SQLITE_ENABLE_STMT_SCANSTATUS */ +# define explainOneScan(u,v,w,x,y,z) 0 +#endif /* SQLITE_OMIT_EXPLAIN */ + +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +static void addScanStatus( + Vdbe *v, + SrcList *pSrclist, + WhereLevel *pLvl, + int addrExplain +){ + const char *zObj = 0; + i64 nEst = 1; + WhereLoop *pLoop = pLvl->pWLoop; + if( (pLoop->wsFlags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ + zObj = pLoop->u.btree.pIndex->zName; + }else{ + zObj = pSrclist->a[pLvl->iFrom].zName; + } + if( pLoop->nOut>=10 ){ + nEst = sqlite3LogEstToInt(pLoop->nOut); + } + sqlite3VdbeScanCounter( + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj + ); +} +#else +# define addScanStatus(a, b, c, d) +#endif + /* @@ -3621,14 +3611,10 @@ static Bitmask codeOneLoopStart( assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; - - /* If an OP_Explain was added for this sub-loop, fix the P2 and - ** P3 parameters to it so that they are relative to the current - ** context. */ - if( pSubWInfo->iExplain!=0 ){ - sqlite3VdbeChangeP2(v, pSubWInfo->iExplain, iLevel); - sqlite3VdbeChangeP3(v, pSubWInfo->iExplain, pLevel->iFrom); - } + int addrExplain = explainOneScan( + pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 + ); + addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the @@ -3760,6 +3746,10 @@ static Bitmask codeOneLoopStart( } } +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + pLevel->addrVisit = sqlite3VdbeCurrentAddr(v); +#endif + /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ @@ -6461,7 +6451,10 @@ WhereInfo *sqlite3WhereBegin( */ notReady = ~(Bitmask)0; for(ii=0; iia[ii]; + wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, @@ -6469,10 +6462,15 @@ WhereInfo *sqlite3WhereBegin( if( db->mallocFailed ) goto whereBeginError; } #endif - explainOneScan(pParse, pTabList, pWInfo, ii, wctrlFlags); + addrExplain = explainOneScan( + pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags + ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; + if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ + addScanStatus(v, pTabList, pLevel, addrExplain); + } } /* Done. */ diff --git a/src/whereInt.h b/src/whereInt.h index dcf0e00604..168e11f4c7 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -85,6 +85,9 @@ struct WhereLevel { } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + int addrVisit; /* Address at which row is visited */ +#endif }; /* diff --git a/test/scanstatus.test b/test/scanstatus.test index 9df80f9ba8..e4e0bbd4a5 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -115,7 +115,7 @@ do_execsql_test 2.4.1 { SELECT * FROM x1 WHERE j<'two' } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { - nLoop 1 nVisit 4 nEst 262144 zName x1j + nLoop 1 nVisit 3 nEst 262144 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j? AND a? AND b? AND b? AND a Date: Sat, 1 Nov 2014 21:00:04 +0000 Subject: [PATCH 11/71] Minor performance enhancements to SQLITE_ENABLE_STMT_SCANSTATUS code. FossilOrigin-Name: f13d6ba8a72d75838c4aaf85326c1129da027f8b --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/vdbe.c | 4 +++- src/vdbeInt.h | 1 + src/vdbeaux.c | 7 ++----- src/where.c | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index c81e911395..974494b3b9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C If\sSQLITE_ENABLE_STMT_SCANSTATUS\sis\sdefined,\srecord\sthe\snumber\sof\stimes\seach\sVDBE\sopcode\sis\sexecuted.\sDerive\sthe\svalues\sreturned\sby\ssqlite3_stmt_scanstatus()\sfrom\sthese\srecords\son\sdemand. -D 2014-11-01T20:38:06.833 +C Minor\sperformance\senhancements\sto\sSQLITE_ENABLE_STMT_SCANSTATUS\scode. +D 2014-11-01T21:00:04.841 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,11 +289,11 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 69d025732d242d7c97282e6570a4e5eb768ebaff +F src/vdbe.c ccc626d70659160596d28b4a910b6086da788695 F src/vdbe.h 7d603b93d128e614ba2600f12a6c541435405522 -F src/vdbeInt.h ee8d44cba5998279039bcd91ebddb6d9a2d463b8 +F src/vdbeInt.h 21570e5ec8b3a385d003e6e20f3a91712b7050e5 F src/vdbeapi.c 19e433e69fe2b27bfc9337a207b6ebf499f41d03 -F src/vdbeaux.c bad342af7cadb8d3bf2990700a78787d602dcd69 +F src/vdbeaux.c 2887d02721c540b25969d3260d0d3d5668d11583 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c fb404e3db40db61c212ffb39022e885a91252498 +F src/where.c ad4a3bca9070e013ff41e8e63835788bcc43dd1c F src/whereInt.h a2bc22f4e3e70eeaa57272f354c288bc3b71b80b F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 8d8cc9608d30bb65fffcfe488e904411cbbc7f41 -R e1e809461d373caeeb0e83f126874426 +P 9ea37422a8cc2fce51bb10508e5e90f40fd4b511 +R 4191876729196c1564c4c28cce5855c1 U dan -Z 5d5debb04affeaeb7378f6b538c8f641 +Z 150c277a759b1b656399ef38dfe29c92 diff --git a/manifest.uuid b/manifest.uuid index f70d7e8aef..72c2809a53 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9ea37422a8cc2fce51bb10508e5e90f40fd4b511 \ No newline at end of file +f13d6ba8a72d75838c4aaf85326c1129da027f8b \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index bc49505dd0..890162dddc 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -609,7 +609,7 @@ int sqlite3VdbeExec( nVmStep++; pOp = &aOp[pc]; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - if( p->pFrame==0 ) p->anExec[pc]++; + if( p->anExec ) p->anExec[pc]++; #endif /* Only allow tracing if SQLITE_DEBUG is defined. @@ -5409,6 +5409,7 @@ case OP_Program: { /* jump */ pFrame->token = pProgram->token; pFrame->aOnceFlag = p->aOnceFlag; pFrame->nOnceFlag = p->nOnceFlag; + pFrame->anExec = p->anExec; pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ @@ -5437,6 +5438,7 @@ case OP_Program: { /* jump */ p->nOp = pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; p->nOnceFlag = pProgram->nOnce; + p->anExec = 0; pc = -1; memset(p->aOnceFlag, 0, p->nOnceFlag); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 9f21ac7ebf..eb2438a87c 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -132,6 +132,7 @@ struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ + i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 3f75cfee7a..548ef0ac5c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1723,6 +1723,7 @@ void sqlite3VdbeMakeReady( p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte); p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte); + p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte); if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } @@ -1730,10 +1731,6 @@ void sqlite3VdbeMakeReady( zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - p->anExec = (i64*)sqlite3DbMallocZero(db, p->nOp*sizeof(i64)); -#endif - p->nCursor = nCursor; p->nOnceFlag = nOnce; if( p->aVar ){ @@ -1794,6 +1791,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; + v->anExec = pFrame->anExec; v->aOnceFlag = pFrame->aOnceFlag; v->nOnceFlag = pFrame->nOnceFlag; v->aOp = pFrame->aOp; @@ -2718,7 +2716,6 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - sqlite3DbFree(db, p->anExec); for(i=0; inScan; i++){ sqlite3DbFree(db, p->aScan[i].zName); } diff --git a/src/where.c b/src/where.c index 8151a7057b..61c0ab7d3d 100644 --- a/src/where.c +++ b/src/where.c @@ -2821,7 +2821,7 @@ static int explainOneScan( u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; -#ifndef SQLITE_DEBUG +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pParse->explain==2 ) #endif { From 037b5324bd634e6288d7502b560bf53f273f0c94 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 3 Nov 2014 11:25:32 +0000 Subject: [PATCH 12/71] Remove unused variable from struct WhereInfo. Add some explanatory comments to new code. FossilOrigin-Name: f5313e0c680d9baebefb1cf50ddadedd4418a334 --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/vdbe.h | 4 ++-- src/vdbeInt.h | 6 +++--- src/vdbeapi.c | 2 +- src/vdbeaux.c | 10 +++++----- src/where.c | 28 ++++++++++++++++++++-------- src/whereInt.h | 1 - test/scanstatus.test | 35 +++++++++++++++++++++++++++++++++++ 9 files changed, 79 insertions(+), 33 deletions(-) diff --git a/manifest b/manifest index 974494b3b9..9b7cf5c34a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sperformance\senhancements\sto\sSQLITE_ENABLE_STMT_SCANSTATUS\scode. -D 2014-11-01T21:00:04.841 +C Remove\sunused\svariable\sfrom\sstruct\sWhereInfo.\sAdd\ssome\sexplanatory\scomments\sto\snew\scode. +D 2014-11-03T11:25:32.305 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -290,10 +290,10 @@ F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c ccc626d70659160596d28b4a910b6086da788695 -F src/vdbe.h 7d603b93d128e614ba2600f12a6c541435405522 -F src/vdbeInt.h 21570e5ec8b3a385d003e6e20f3a91712b7050e5 -F src/vdbeapi.c 19e433e69fe2b27bfc9337a207b6ebf499f41d03 -F src/vdbeaux.c 2887d02721c540b25969d3260d0d3d5668d11583 +F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 +F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 +F src/vdbeapi.c addf446ecade237bebd7e9fe769bdfb9db8d9fb1 +F src/vdbeaux.c 0aeb90cb62d7c07572798b41882838b3d4e55b44 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 @@ -302,8 +302,8 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c ad4a3bca9070e013ff41e8e63835788bcc43dd1c -F src/whereInt.h a2bc22f4e3e70eeaa57272f354c288bc3b71b80b +F src/where.c 53dae5ed6133438a9342c17bf3e95e00edbb0556 +F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 @@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 -F test/scanstatus.test 40c7712c8bc0adc3fb88e0419356880679a3a5fb +F test/scanstatus.test 0c0baa647e98940d753d40691bf6475345c05cc5 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 9ea37422a8cc2fce51bb10508e5e90f40fd4b511 -R 4191876729196c1564c4c28cce5855c1 +P f13d6ba8a72d75838c4aaf85326c1129da027f8b +R 79a96158570090f7f8b0799c9e59db67 U dan -Z 150c277a759b1b656399ef38dfe29c92 +Z b85dee7fa48b3d6596e077d675db2dc9 diff --git a/manifest.uuid b/manifest.uuid index 72c2809a53..5972c23854 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f13d6ba8a72d75838c4aaf85326c1129da027f8b \ No newline at end of file +f5313e0c680d9baebefb1cf50ddadedd4418a334 \ No newline at end of file diff --git a/src/vdbe.h b/src/vdbe.h index 966fdb622e..1b9ad8b6bf 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -283,9 +283,9 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS -void sqlite3VdbeScanCounter(Vdbe*, int, int, int, i64, const char*); +void sqlite3VdbeScanStatus(Vdbe*, int, int, int, i64, const char*); #else -# define sqlite3VdbeScanCounter(a,b,c,d,e) +# define sqlite3VdbeScanStatus(a,b,c,d,e) #endif #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index eb2438a87c..29117dd064 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -297,8 +297,8 @@ struct Explain { */ typedef unsigned bft; /* Bit Field Type */ -typedef struct ScanCounter ScanCounter; -struct ScanCounter { +typedef struct ScanStatus ScanStatus; +struct ScanStatus { int addrExplain; /* OP_Explain for loop */ int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ @@ -381,7 +381,7 @@ struct Vdbe { #ifdef SQLITE_ENABLE_STMT_SCANSTATUS i64 *anExec; /* Number of times each op has been executed */ int nScan; /* Entries in aScan[] */ - ScanCounter *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ + ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif }; diff --git a/src/vdbeapi.c b/src/vdbeapi.c index f2e124dc51..e6eb034ae9 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1490,7 +1490,7 @@ int sqlite3_stmt_scanstatus( const char **pzExplain /* OUT: EQP string */ ){ Vdbe *p = (Vdbe*)pStmt; - ScanCounter *pScan; + ScanStatus *pScan; if( idx<0 || idx>=p->nScan ) return 1; pScan = &p->aScan[idx]; if( pnLoop ) *pnLoop = p->anExec[pScan->addrLoop]; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 548ef0ac5c..da24291b4e 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -601,7 +601,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ /* ** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). */ -void sqlite3VdbeScanCounter( +void sqlite3VdbeScanStatus( Vdbe *p, /* VM to add scanstatus() to */ int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ @@ -609,11 +609,11 @@ void sqlite3VdbeScanCounter( i64 nEst, /* Estimated number of rows */ const char *zName /* Name of table or index being scanned */ ){ - int nByte = (p->nScan+1) * sizeof(ScanCounter); - ScanCounter *aNew; - aNew = (ScanCounter*)sqlite3DbRealloc(p->db, p->aScan, nByte); + int nByte = (p->nScan+1) * sizeof(ScanStatus); + ScanStatus *aNew; + aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ - ScanCounter *pNew = &aNew[p->nScan++]; + ScanStatus *pNew = &aNew[p->nScan++]; pNew->addrExplain = addrExplain; pNew->addrLoop = addrLoop; pNew->addrVisit = addrVisit; diff --git a/src/where.c b/src/where.c index 61c0ab7d3d..81298b7821 100644 --- a/src/where.c +++ b/src/where.c @@ -2808,9 +2808,12 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single -** record is added to the output to describe the table scan strategy in -** pLevel. +** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was +** defined at compile-time. If it is not a no-op, a single OP_Explain opcode +** is added to the output to describe the table scan strategy in pLevel. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. */ static int explainOneScan( Parse *pParse, /* Parse context */ @@ -2919,11 +2922,20 @@ static int explainOneScan( #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Configure the VM passed as the first argument with an +** sqlite3_stmt_scanstatus() entry corresponding to the scan used to +** implement level pLvl. Argument pSrclist is a pointer to the FROM +** clause that the scan reads data from. +** +** If argument addrExplain is not 0, it must be the address of an +** OP_Explain instruction that describes the same loop. +*/ static void addScanStatus( - Vdbe *v, - SrcList *pSrclist, - WhereLevel *pLvl, - int addrExplain + Vdbe *v, /* Vdbe to add scanstatus entry to */ + SrcList *pSrclist, /* FROM clause pLvl reads data from */ + WhereLevel *pLvl, /* Level to add scanstatus() entry for */ + int addrExplain /* Address of OP_Explain (or 0) */ ){ const char *zObj = 0; i64 nEst = 1; @@ -2936,7 +2948,7 @@ static void addScanStatus( if( pLoop->nOut>=10 ){ nEst = sqlite3LogEstToInt(pLoop->nOut); } - sqlite3VdbeScanCounter( + sqlite3VdbeScanStatus( v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj ); } diff --git a/src/whereInt.h b/src/whereInt.h index 168e11f4c7..2ccc6ec064 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -410,7 +410,6 @@ struct WhereInfo { int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ - int iExplain; /* Address of OP_Explain (if WHERE_ONETABLE_ONLY) */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ diff --git a/test/scanstatus.test b/test/scanstatus.test index e4e0bbd4a5..d4c70fbef4 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -231,4 +231,39 @@ do_scanstatus_test 3.4.2 { zExplain {SEARCH TABLE a1 USING INTEGER PRIMARY KEY (rowid=?)} } +#------------------------------------------------------------------------- +# Test that scanstatus() data is not available for searches performed +# by triggers. +# +# It is available for searches performed as part of FK processing, but +# not FK action processing. +# +do_execsql_test 4.0 { + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(x PRIMARY KEY, y, z); + CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN + SELECT * FROM t2 WHERE x BETWEEN 20 AND 40; + END; + WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100) + INSERT INTO t2 SELECT x, x*2, x*3 FROM d; +} + +do_execsql_test 4.1.1 { INSERT INTO t1 VALUES(1, 2, 3); } +do_scanstatus_test 4.1.2 { } + +do_execsql_test 4.2 { + CREATE TABLE p1(x PRIMARY KEY); + INSERT INTO p1 VALUES(1), (2), (3), (4); + CREATE TABLE c1(y REFERENCES p1); + INSERT INTO c1 VALUES(1), (2), (3); + PRAGMA foreign_keys=on; +} +do_execsql_test 4.2.1 { DELETE FROM p1 WHERE x=4 } +do_scanstatus_test 4.2.2 { + nLoop 1 nVisit 1 nEst 1 zName sqlite_autoindex_p1_1 + zExplain {SEARCH TABLE p1 USING INDEX sqlite_autoindex_p1_1 (x=?)} + + nLoop 1 nVisit 3 nEst 524288 zName c1 zExplain {SCAN TABLE c1} +} + finish_test From 7f5a7ecd216747e738588ad32064a182d2ce2928 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Nov 2014 13:24:12 +0000 Subject: [PATCH 13/71] When enlarging the size of a StrAccum object, use sqlite3DbMallocSize() to record the entire size of the allocation, not just the requested size. FossilOrigin-Name: 3dda3c937469ce661d1cd0e8d8963a03e698ee39 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/printf.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 8ab904b8d2..3034b1c180 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\srequirements\smarks\sand\smake\sminor\stweaks\sto\sdocumentation. -D 2014-11-01T18:32:18.050 +C When\senlarging\sthe\ssize\sof\sa\sStrAccum\sobject,\suse\ssqlite3DbMallocSize()\sto\nrecord\sthe\sentire\ssize\sof\sthe\sallocation,\snot\sjust\sthe\srequested\ssize. +D 2014-11-03T13:24:12.668 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -223,7 +223,7 @@ F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5 F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7 -F src/printf.c 10a2493593c8e4a538915cd3674bd7a67f70c488 +F src/printf.c ee13daccd49ddf767d057bc98395c9e83d4e2067 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e @@ -1210,7 +1210,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 67f0d469da28c023200239a1f3d0c6cef9ef0e45 -R dbf6a8dc4a878d1b1a7b9b3874ca58fb +P 49188b2bb53a92b0b0b6aaf8247edeb0c1bcd1f5 +R 041ffec3947ff9e90700478ea54978f5 U drh -Z 455c35adeade418fab0456b1b175d27f +Z 42c888343c3ca87538d56b9b17ae76ab diff --git a/manifest.uuid b/manifest.uuid index 02f906627f..8be6ab9856 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -49188b2bb53a92b0b0b6aaf8247edeb0c1bcd1f5 \ No newline at end of file +3dda3c937469ce661d1cd0e8d8963a03e698ee39 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 85d237f0e7..e20619f9a7 100644 --- a/src/printf.c +++ b/src/printf.c @@ -786,6 +786,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ assert( p->zText!=0 || p->nChar==0 ); if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; + p->nAlloc = sqlite3DbMallocSize(p->db, zNew); }else{ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_NOMEM); From 7b4d780b541ac9af0f5b183c72afa12916fd5d26 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Nov 2014 14:46:29 +0000 Subject: [PATCH 14/71] Use exponential buffer size growth in StrAccum, as long as the size does not grow to large, to avoid excess memory allocation resize operations. Also, document the fact that setting scratch memory causes SQLite to try to avoid large memory allocations. FossilOrigin-Name: a518bc3318232d652349eb29303ff250aee40459 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/printf.c | 5 +++++ src/sqlite.h.in | 11 ++++++++--- src/vdbesort.c | 8 +++----- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 3034b1c180..de67a3e45a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\senlarging\sthe\ssize\sof\sa\sStrAccum\sobject,\suse\ssqlite3DbMallocSize()\sto\nrecord\sthe\sentire\ssize\sof\sthe\sallocation,\snot\sjust\sthe\srequested\ssize. -D 2014-11-03T13:24:12.668 +C Use\sexponential\sbuffer\ssize\sgrowth\sin\sStrAccum,\sas\slong\sas\sthe\ssize\sdoes\snot\ngrow\sto\slarge,\sto\savoid\sexcess\smemory\sallocation\sresize\soperations.\s\sAlso,\ndocument\sthe\sfact\sthat\ssetting\sscratch\smemory\scauses\sSQLite\sto\stry\sto\savoid\nlarge\smemory\sallocations. +D 2014-11-03T14:46:29.027 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -223,13 +223,13 @@ F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5 F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7 -F src/printf.c ee13daccd49ddf767d057bc98395c9e83d4e2067 +F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in c3c6180be49d91d3b0001a8d3c604684f361adc2 +F src/sqlite.h.in dd0cb63fb7cb558892afe8253c3279c508c50329 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -296,7 +296,7 @@ F src/vdbeapi.c 02d8afcff710eb35e3d9e49cb677308296b00009 F src/vdbeaux.c 3d6b2b412ef2193aa4729922dfc5df1efadbf6df F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f -F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 +F src/vdbesort.c daf87ea542df088ac4607660d09976d36b6bd95d F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 @@ -1210,7 +1210,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 49188b2bb53a92b0b0b6aaf8247edeb0c1bcd1f5 -R 041ffec3947ff9e90700478ea54978f5 +P 3dda3c937469ce661d1cd0e8d8963a03e698ee39 +R e2c699e9cb6d832117ea76de0a03f26b U drh -Z 42c888343c3ca87538d56b9b17ae76ab +Z 91c9a2887aef0ce4f97740bae4c1a9ba diff --git a/manifest.uuid b/manifest.uuid index 8be6ab9856..11815fb0c2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3dda3c937469ce661d1cd0e8d8963a03e698ee39 \ No newline at end of file +a518bc3318232d652349eb29303ff250aee40459 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index e20619f9a7..ac7b051631 100644 --- a/src/printf.c +++ b/src/printf.c @@ -770,6 +770,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zOld = (p->zText==p->zBase ? 0 : p->zText); i64 szNew = p->nChar; szNew += N + 1; + if( szNew+p->nChar<=p->mxAlloc ){ + /* Force exponential buffer size growth as long as it does not overflow, + ** to avoid having to call this routine too often */ + szNew += p->nChar; + } if( szNew > p->mxAlloc ){ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_TOOBIG); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index d0f213f156..ffd0ade039 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1535,8 +1535,7 @@ struct sqlite3_mem_methods { ** scratch memory. ^(There are three arguments: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ The sz -** argument must be a multiple of 16. +** and the maximum number of scratch allocations (N).)^ ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. ** ^SQLite will not use more than two scratch buffers per thread and not @@ -1548,7 +1547,13 @@ struct sqlite3_mem_methods { ** of the size of the WAL file. ** ^If SQLite needs needs additional ** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.
+** [sqlite3_malloc()] will be used to obtain the memory needed.

+** ^When the application provides any amount of scratch memory using +** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large +** [sqlite3_malloc|heap allocations]. +** This can help [Robson proof|prevent memory allocation failures] due to heap +** fragmentation in low-memory embedded systems. +** ** ** [[SQLITE_CONFIG_PAGECACHE]]

SQLITE_CONFIG_PAGECACHE
**
^This option specifies a static memory buffer that SQLite can use for diff --git a/src/vdbesort.c b/src/vdbesort.c index 46c9f3789d..918d840716 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -847,11 +847,9 @@ int sqlite3VdbeSorterInit( if( mxCachemxPmaSize = mxCache * pgsz; - /* If the application has not configure scratch memory using - ** SQLITE_CONFIG_SCRATCH then we assume it is OK to do large memory - ** allocations. If scratch memory has been configured, then assume - ** large memory allocations should be avoided to prevent heap - ** fragmentation. + /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of + ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary + ** large heap allocations. */ if( sqlite3GlobalConfig.pScratch==0 ){ assert( pSorter->iMemory==0 ); From e2f771b04706d0c055d5c3b7731e4cda14467600 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 3 Nov 2014 15:33:17 +0000 Subject: [PATCH 15/71] Add further tests. Fixes so that compilation without ENABLE_STMT_SCANSTATUS works. FossilOrigin-Name: a2303c719222f1effb51acc6b37930561148c00c --- manifest | 20 +++---- manifest.uuid | 2 +- src/test_config.c | 6 ++ src/vdbe.c | 4 ++ src/vdbeaux.c | 4 ++ src/where.c | 2 +- test/scanstatus.test | 129 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 155 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 9b7cf5c34a..5c51df5fcc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sunused\svariable\sfrom\sstruct\sWhereInfo.\sAdd\ssome\sexplanatory\scomments\sto\snew\scode. -D 2014-11-03T11:25:32.305 +C Add\sfurther\stests.\sFixes\sso\sthat\scompilation\swithout\sENABLE_STMT_SCANSTATUS\sworks. +D 2014-11-03T15:33:17.869 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -250,7 +250,7 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8 F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f -F src/test_config.c a4cdebe093474c02eecc5e4008b1a22198edf975 +F src/test_config.c c8b8b50bf2fe5102de10e4c7100b746d7f6bf62f F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f @@ -289,11 +289,11 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c ccc626d70659160596d28b4a910b6086da788695 +F src/vdbe.c 175a360c56e75ce4eb2b60704fd7c011b93926f5 F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 F src/vdbeapi.c addf446ecade237bebd7e9fe769bdfb9db8d9fb1 -F src/vdbeaux.c 0aeb90cb62d7c07572798b41882838b3d4e55b44 +F src/vdbeaux.c cf6b8152dd22155201d57c216e6266866b61da59 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 53dae5ed6133438a9342c17bf3e95e00edbb0556 +F src/where.c d5fa1081bf7cb70478ed06489e063695c92ee1e1 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 -F test/scanstatus.test 0c0baa647e98940d753d40691bf6475345c05cc5 +F test/scanstatus.test 01afb2220f18ce85f9e338c20684f428d56e5c01 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f13d6ba8a72d75838c4aaf85326c1129da027f8b -R 79a96158570090f7f8b0799c9e59db67 +P f5313e0c680d9baebefb1cf50ddadedd4418a334 +R b9cde6c71acdc4fef0c5c1ac03d62018 U dan -Z b85dee7fa48b3d6596e077d675db2dc9 +Z f0600457ea98c0c998694790015a9674 diff --git a/manifest.uuid b/manifest.uuid index 5972c23854..fe7315da12 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f5313e0c680d9baebefb1cf50ddadedd4418a334 \ No newline at end of file +a2303c719222f1effb51acc6b37930561148c00c \ No newline at end of file diff --git a/src/test_config.c b/src/test_config.c index 2c11f713fb..03f4f76f6d 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -484,6 +484,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "stat3", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + Tcl_SetVar2(interp, "sqlite_options", "scanstatus", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "scanstatus", "0", TCL_GLOBAL_ONLY); +#endif + #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) # define SQLITE_ENABLE_LOCKING_STYLE 1 diff --git a/src/vdbe.c b/src/vdbe.c index 890162dddc..62470a743b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5409,7 +5409,9 @@ case OP_Program: { /* jump */ pFrame->token = pProgram->token; pFrame->aOnceFlag = p->aOnceFlag; pFrame->nOnceFlag = p->nOnceFlag; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; +#endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ @@ -5438,7 +5440,9 @@ case OP_Program: { /* jump */ p->nOp = pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; p->nOnceFlag = pProgram->nOnce; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; +#endif pc = -1; memset(p->aOnceFlag, 0, p->nOnceFlag); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index da24291b4e..7cf996ce5c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1723,7 +1723,9 @@ void sqlite3VdbeMakeReady( p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte); p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte); +#endif if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } @@ -1791,7 +1793,9 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS v->anExec = pFrame->anExec; +#endif v->aOnceFlag = pFrame->aOnceFlag; v->nOnceFlag = pFrame->nOnceFlag; v->aOp = pFrame->aOp; diff --git a/src/where.c b/src/where.c index 81298b7821..d7966fdfbc 100644 --- a/src/where.c +++ b/src/where.c @@ -2953,7 +2953,7 @@ static void addScanStatus( ); } #else -# define addScanStatus(a, b, c, d) +# define addScanStatus(a, b, c, d) ((void)d) #endif diff --git a/test/scanstatus.test b/test/scanstatus.test index d4c70fbef4..9b34506e91 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix scanstatus +ifcapable !scanstatus { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(x, y); @@ -266,4 +271,128 @@ do_scanstatus_test 4.2.2 { nLoop 1 nVisit 3 nEst 524288 zName c1 zExplain {SCAN TABLE c1} } +#------------------------------------------------------------------------- +# Further tests of different scan types. +# +reset_db +proc tochar {i} { + set alphabet {a b c d e f g h i j k l m n o p q r s t u v w x y z} + return [lindex $alphabet [expr $i % [llength $alphabet]]] +} +db func tochar tochar +do_execsql_test 5.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(0, 1, 'a'); + INSERT INTO t1 VALUES(1, 0, 'b'); + INSERT INTO t1 VALUES(2, 1, 'c'); + INSERT INTO t1 VALUES(3, 0, 'd'); + INSERT INTO t1 VALUES(4, 1, 'e'); + INSERT INTO t1 VALUES(5, 0, 'a'); + INSERT INTO t1 VALUES(6, 1, 'b'); + INSERT INTO t1 VALUES(7, 0, 'c'); + INSERT INTO t1 VALUES(8, 1, 'd'); + INSERT INTO t1 VALUES(9, 0, 'e'); + CREATE INDEX t1bc ON t1(b, c); + + CREATE TABLE t2(x, y); + CREATE INDEX t2xy ON t2(x, y); + WITH data(i, x, y) AS ( + SELECT 0, 0, tochar(0) + UNION ALL + SELECT i+1, (i+1)%2, tochar(i+1) FROM data WHERE i<500 + ) INSERT INTO t2 SELECT x, y FROM data; + + CREATE TABLE t3(x, y); + INSERT INTO t3 SELECT * FROM t2; + + ANALYZE; +} + +do_execsql_test 5.1.1 { + SELECT count(*) FROM t1 WHERE a IN (SELECT b FROM t1 AS ii) +} {2} +do_scanstatus_test 5.1.2 { + nLoop 1 nVisit 10 nEst 10 zName t1bc + zExplain {SCAN TABLE t1 AS ii USING COVERING INDEX t1bc} + nLoop 1 nVisit 2 nEst 8 zName sqlite_autoindex_t1_1 + zExplain {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} +} + +do_execsql_test 5.2.1 { + SELECT count(*) FROM t1 WHERE a IN (0, 1) +} {2} +do_scanstatus_test 5.2.2 { + nLoop 1 nVisit 2 nEst 2 zName sqlite_autoindex_t1_1 + zExplain {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} +} + +do_eqp_test 5.3.1 { + SELECT count(*) FROM t2 WHERE y = 'j'; +} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}} +do_execsql_test 5.3.2 { + SELECT count(*) FROM t2 WHERE y = 'j'; +} {19} +do_scanstatus_test 5.3.3 { + nLoop 1 nVisit 19 nEst 56 zName t2xy zExplain + {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} +} + +do_eqp_test 5.4.1 { + SELECT count(*) FROM t1, t2 WHERE y = c; +} { + 0 0 0 {SCAN TABLE t1 USING COVERING INDEX t1bc} + 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} +} +do_execsql_test 5.4.2 { + SELECT count(*) FROM t1, t2 WHERE y = c; +} {200} +do_scanstatus_test 5.4.3 { + nLoop 1 nVisit 10 nEst 10 zName t1bc + zExplain {SCAN TABLE t1 USING COVERING INDEX t1bc} + nLoop 10 nVisit 200 nEst 56 zName t2xy + zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} +} + +do_eqp_test 5.5.1 { + SELECT count(*) FROM t1, t3 WHERE y = c; +} { + 0 0 1 {SCAN TABLE t3} + 0 1 0 {SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?)} +} +do_execsql_test 5.5.2 { + SELECT count(*) FROM t1, t3 WHERE y = c; +} {200} +do_scanstatus_test 5.5.3 { + nLoop 1 nVisit 501 nEst 480 zName t3 zExplain {SCAN TABLE t3} + nLoop 501 nVisit 200 nEst 20 zName auto-index zExplain + {SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?)} +} + +#------------------------------------------------------------------------- +# Virtual table scans +# +ifcapable fts3 { + do_execsql_test 6.0 { + CREATE VIRTUAL TABLE ft1 USING fts4; + INSERT INTO ft1 VALUES('a d c f g h e i f c'); + INSERT INTO ft1 VALUES('g c h b g b f f f g'); + INSERT INTO ft1 VALUES('h h c c h f a e d d'); + INSERT INTO ft1 VALUES('e j i j i e b c f g'); + INSERT INTO ft1 VALUES('g f b g j c h a d f'); + INSERT INTO ft1 VALUES('j i a e g f a i a c'); + INSERT INTO ft1 VALUES('f d g g j j c a h g'); + INSERT INTO ft1 VALUES('b d h a d j j j b i'); + INSERT INTO ft1 VALUES('j e a b j e c b c i'); + INSERT INTO ft1 VALUES('a d e f b j j c g d'); + } + do_execsql_test 6.1.1 { + SELECT count(*) FROM ft1 WHERE ft1 MATCH 'd' + } {6} + do_scanstatus_test 6.1.2 { + nLoop 1 nVisit 6 nEst 24 zName ft1 zExplain + {SCAN TABLE ft1 VIRTUAL TABLE INDEX 3:} + } +} + + finish_test From d1a1c23423560f4cac2cab305d92bb2d67a04d57 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Nov 2014 16:35:55 +0000 Subject: [PATCH 16/71] Refactor the interface to make it more easily extensible. FossilOrigin-Name: 7955342da4a35b57e4ae26690b8d40f7bba20e8f --- manifest | 18 +++++----- manifest.uuid | 2 +- src/sqlite.h.in | 93 ++++++++++++++++++++++++++++++------------------- src/test1.c | 8 +++-- src/vdbeapi.c | 46 +++++++++++++++--------- 5 files changed, 102 insertions(+), 65 deletions(-) diff --git a/manifest b/manifest index 5c51df5fcc..134366e0aa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sfurther\stests.\sFixes\sso\sthat\scompilation\swithout\sENABLE_STMT_SCANSTATUS\sworks. -D 2014-11-03T15:33:17.869 +C Refactor\sthe\sinterface\sto\smake\sit\smore\seasily\sextensible. +D 2014-11-03T16:35:55.977 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in aeba29025ba5fc721a11c1b81ed8745f93029590 +F src/sqlite.h.in a110c6320b3af8d7c0660fa1adbc530b6caa2d95 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 4f86ac648ea398c1bb3db036062934cde257ea23 @@ -237,7 +237,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc F src/tclsqlite.c 7cdd4dd3c2a4183483feca260070d73d6e22cd47 -F src/test1.c b53f4da2f386efa5c248716cd4bdc8344a87e952 +F src/test1.c 5890094c09691fe9564cf0f0d5b22d35b3218c47 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -292,7 +292,7 @@ F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c 175a360c56e75ce4eb2b60704fd7c011b93926f5 F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 -F src/vdbeapi.c addf446ecade237bebd7e9fe769bdfb9db8d9fb1 +F src/vdbeapi.c 76d62888455e3d3ffeaf70911cefa94e76a4678a F src/vdbeaux.c cf6b8152dd22155201d57c216e6266866b61da59 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f5313e0c680d9baebefb1cf50ddadedd4418a334 -R b9cde6c71acdc4fef0c5c1ac03d62018 -U dan -Z f0600457ea98c0c998694790015a9674 +P a2303c719222f1effb51acc6b37930561148c00c +R cbd06b886fdee03f70c2bf18e1342ca1 +U drh +Z 0328a60e2b5415c07361c47ade3f21c5 diff --git a/manifest.uuid b/manifest.uuid index fe7315da12..5fd1f91e84 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a2303c719222f1effb51acc6b37930561148c00c \ No newline at end of file +7955342da4a35b57e4ae26690b8d40f7bba20e8f \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 51383426d9..30ef4afb60 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7406,54 +7406,75 @@ 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 option} +** +** 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. +** +**
+** [[SQLITE_SCANSTAT_NLOOP]] SQLITE_SCANSTAT_NLOOP +**
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.
+** +** [[SQLITE_SCANSTAT_NVISIT]] SQLITE_SCANSTAT_NVISIT +**
The [sqlite3_int64] variable pointed to by the T parameter will be set to the +** total number of rows visited by the X-th loop.
+** +** [[SQLITE_SCANSTAT_EST]] SQLITE_SCANSTAT_EST +**
The [sqlite3_int64] variable pointed to by the T parameter will be set to the +** query planner's estimate for the number of rows visited for each +** iteration of the X-th loop. If the query planner's estimate was accurate, +** then this value should be approximately NVISIT/NLOOP. +** +** [[SQLITE_SCANSTAT_NAME]] SQLITE_SCANSTAT_NAME +**
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]] SQLITE_SCANSTAT_EXPLAIN +**
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. +**
+*/ +#define SQLITE_SCANSTAT_NLOOP 0 +#define SQLITE_SCANSTAT_NVISIT 1 +#define SQLITE_SCANSTAT_NEST 2 +#define SQLITE_SCANSTAT_NAME 3 +#define SQLITE_SCANSTAT_EXPLAIN 4 /* -** CAPI3REF: Prepared Statement Scan Statuses +** 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. In this case the final value -** of all five output parameters is undefined. Otherwise, if idx is in range, -** zero is returned and the output parameters set as follows: +** the statement - a non-zero value is returned and the variable that pOut +** points to is unchanged. ** -**
    -**
  • (*pnLoop) is set to the total number of times the loop has been run. -**
  • (*pnVisit) is set to the total number of rows visited by the loop. -**
  • (*pnEst) is set to the estimate of the number of rows visited -** by each run of the loop used by the SQL optimizer. Ideally, this -** value should be close to (*pnVisit)/(*pnLoop). -**
  • (*pzName) is set to point to a nul-terminated string containing the -** name of the index of table used by this loop. -**
  • (*pzExplain) is set to point to a nul-terminated string containing -** same text that would be returned for this loop by an EXPLAIN -** QUERY PLAN command. -**
-** -** Output parameters *pzName and *pzExplain are set to point to buffers -** managed by the statement object. Both of these pointers may be invalidated -** by any API call on the same statement object, including an sqlite3_step() -** sqlite3_bind_*() call. -** -** Statistics may not be available for all loops in all statements. In cases -** where there exist loops with no available statistics, this function ignores -** them completely. +** 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. +** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( - sqlite3_stmt *pStmt, - int idx, /* Index of loop to report on */ - sqlite3_int64 *pnLoop, /* OUT: Number of times loop was run */ - sqlite3_int64 *pnVisit, /* OUT: Number of rows visited (all loops) */ - sqlite3_int64 *pnEst, /* OUT: Number of rows estimated (per loop) */ - const char **pzName, /* OUT: Object name (table or index) */ - const char **pzExplain /* OUT: EQP string */ -); - + 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 @@ -7461,7 +7482,7 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( ** 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. +** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); diff --git a/src/test1.c b/src/test1.c index 72e70513bc..5e526b3013 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2328,19 +2328,21 @@ static int test_stmt_scanstatus( if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; - res = sqlite3_stmt_scanstatus( - pStmt, idx, &nLoop, &nVisit, &nEst, &zName, &zExplain - ); + res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop); if( res==0 ){ Tcl_Obj *pRet = Tcl_NewObj(); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&nEst); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nEst)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1)); Tcl_SetObjResult(interp, pRet); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index e6eb034ae9..d3ba4e95d2 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1481,27 +1481,42 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ ** Return status data for a single loop within query pStmt. */ int sqlite3_stmt_scanstatus( - sqlite3_stmt *pStmt, + sqlite3_stmt *pStmt, /* Prepared statement being queried */ int idx, /* Index of loop to report on */ - sqlite3_int64 *pnLoop, /* OUT: Number of times loop was run */ - sqlite3_int64 *pnVisit, /* OUT: Number of rows visited (all loops) */ - sqlite3_int64 *pnEst, /* OUT: Number of rows estimated (per loop) */ - const char **pzName, /* OUT: Object name (table or index) */ - const char **pzExplain /* OUT: EQP string */ + 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]; - if( pnLoop ) *pnLoop = p->anExec[pScan->addrLoop]; - if( pnVisit ) *pnVisit = p->anExec[pScan->addrVisit]; - if( pnEst ) *pnEst = pScan->nEst; - if( *pzName ) *pzName = pScan->zName; - if( *pzExplain ){ - if( pScan->addrExplain ){ - *pzExplain = p->aOp[ pScan->addrExplain ].p4.z; - }else{ - *pzExplain = 0; + 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: { + *(sqlite3_int64*)pOut = pScan->nEst; + 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; + } + default: { + return 1; } } return 0; @@ -1515,4 +1530,3 @@ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ memset(p->anExec, 0, p->nOp * sizeof(i64)); } #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ - From d72219da438dcc06d78fc10b9c7958cf4f12ffab Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 3 Nov 2014 16:39:37 +0000 Subject: [PATCH 17/71] Fix a typo preventing this from building with SQLITE_ENABLE_STMT_SCANSTATUS defined. FossilOrigin-Name: 4c5714ab3dba19513374c7b1478221a0b90b450c --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/sqlite.h.in | 2 +- src/vdbeapi.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 134366e0aa..75cfa9ca43 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\sthe\sinterface\sto\smake\sit\smore\seasily\sextensible. -D 2014-11-03T16:35:55.977 +C Fix\sa\stypo\spreventing\sthis\sfrom\sbuilding\swith\sSQLITE_ENABLE_STMT_SCANSTATUS\sdefined. +D 2014-11-03T16:39:37.742 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in a110c6320b3af8d7c0660fa1adbc530b6caa2d95 +F src/sqlite.h.in 26b6aa6a1825b97c0fa16ce14fc657be00c299f6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 4f86ac648ea398c1bb3db036062934cde257ea23 @@ -292,7 +292,7 @@ F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c 175a360c56e75ce4eb2b60704fd7c011b93926f5 F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 -F src/vdbeapi.c 76d62888455e3d3ffeaf70911cefa94e76a4678a +F src/vdbeapi.c 900259bdd85cd66a9f210d8ec08147a9034593bd F src/vdbeaux.c cf6b8152dd22155201d57c216e6266866b61da59 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a2303c719222f1effb51acc6b37930561148c00c -R cbd06b886fdee03f70c2bf18e1342ca1 -U drh -Z 0328a60e2b5415c07361c47ade3f21c5 +P 7955342da4a35b57e4ae26690b8d40f7bba20e8f +R c9becfda3a2880c1d6a40a42c50145fa +U dan +Z a994e9671fe739ddd2243271f124e718 diff --git a/manifest.uuid b/manifest.uuid index 5fd1f91e84..2f63e2e7f1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7955342da4a35b57e4ae26690b8d40f7bba20e8f \ No newline at end of file +4c5714ab3dba19513374c7b1478221a0b90b450c \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 30ef4afb60..8f51f0e180 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7441,7 +7441,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *); */ #define SQLITE_SCANSTAT_NLOOP 0 #define SQLITE_SCANSTAT_NVISIT 1 -#define SQLITE_SCANSTAT_NEST 2 +#define SQLITE_SCANSTAT_EST 2 #define SQLITE_SCANSTAT_NAME 3 #define SQLITE_SCANSTAT_EXPLAIN 4 diff --git a/src/vdbeapi.c b/src/vdbeapi.c index d3ba4e95d2..d472004590 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1504,7 +1504,7 @@ int sqlite3_stmt_scanstatus( break; } case SQLITE_SCANSTAT_NAME: { - *(const char**)pOut = pScan->zName + *(const char**)pOut = pScan->zName; break; } case SQLITE_SCANSTAT_EXPLAIN: { From d84bf205c38c9f46cee73c1e24f1dee67d32a441 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 3 Nov 2014 18:03:00 +0000 Subject: [PATCH 18/71] Updates to the sqlite3_stmt_scanstatus() documentation. No changes to code. FossilOrigin-Name: d97c324eb1d870c994911c53fbf84205f4e3e7a1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 35 +++++++++++++++++++---------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 07d97518f1..8d217ecfe0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sexperimental\ssqlite3_stmt_scanstatus()\sAPI.\sFor\scomparing\sthe\snumber\sof\srows\sactually\svisited\sby\sa\sloop\swith\sthe\sestimate\sused\sby\sthe\squery\splanner. -D 2014-11-03T16:56:43.943 +C Updates\sto\sthe\ssqlite3_stmt_scanstatus()\sdocumentation.\s\sNo\schanges\sto\scode. +D 2014-11-03T18:03:00.467 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 3b69f7d9b74e2e5d0448dc2f0d2d160517afa253 +F src/sqlite.h.in 11f33a3e968a9637d6fa4ae879b83edd171ac88f F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a518bc3318232d652349eb29303ff250aee40459 4c5714ab3dba19513374c7b1478221a0b90b450c -R ce3f2c2aee62a076b6ed59326c9cde3e -U dan -Z cd275722bcaf367ed1a07165e9a16c03 +P ab3b0fc5760c6d428dbe1f974726a7d3526640bc +R e3e372d3594a5227dc7ce2380d71aae3 +U drh +Z 7bcc3180ea33e48aa6d0e7855da7bfd4 diff --git a/manifest.uuid b/manifest.uuid index c71e9c3f37..0611c8a12e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ab3b0fc5760c6d428dbe1f974726a7d3526640bc \ No newline at end of file +d97c324eb1d870c994911c53fbf84205f4e3e7a1 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index f51dca0d84..41cc439846 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7411,35 +7411,36 @@ 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 option} +/* +** 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. ** **
-** [[SQLITE_SCANSTAT_NLOOP]] SQLITE_SCANSTAT_NLOOP -**
The [sqlite3_int64] variable pointed to by the T parameter will be set to the +** [[SQLITE_SCANSTAT_NLOOP]]
SQLITE_SCANSTAT_NLOOP
+**
^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.
** -** [[SQLITE_SCANSTAT_NVISIT]] SQLITE_SCANSTAT_NVISIT -**
The [sqlite3_int64] variable pointed to by the T parameter will be set to the +** [[SQLITE_SCANSTAT_NVISIT]]
SQLITE_SCANSTAT_NVISIT
+**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the ** total number of rows visited by the X-th loop.
** -** [[SQLITE_SCANSTAT_EST]] SQLITE_SCANSTAT_EST -**
The [sqlite3_int64] variable pointed to by the T parameter will be set to the +** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
+**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the ** query planner's estimate for the number of rows visited for each ** iteration of the X-th loop. If the query planner's estimate was accurate, ** then this value should be approximately NVISIT/NLOOP. ** -** [[SQLITE_SCANSTAT_NAME]] SQLITE_SCANSTAT_NAME -**
The "const char *" variable pointed to by the T parameter will be set to +** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
+**
^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]] SQLITE_SCANSTAT_EXPLAIN -**
The "const char *" variable pointed to by the T parameter will be set to +** [[SQLITE_SCANSTAT_EXPLAIN]]
SQLITE_SCANSTAT_EXPLAIN
+**
^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. **
@@ -7458,21 +7459,23 @@ int sqlite3_vtab_on_conflict(sqlite3 *); ** 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 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 +** 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 +** ^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 */ @@ -7484,7 +7487,7 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( /* ** CAPI3REF: Zero Scan-Status Counters ** -** Zero all sqlite3_stmt_scanstatus() related event 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. From def6889d214a04780390df0aa77efcd5011620cf Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Nov 2014 12:11:23 +0000 Subject: [PATCH 19/71] Add the SQLITE_CONFIG_PCACHE_HDRSZ option for sqlite3_config(). FossilOrigin-Name: 6eb03e62a34e8e0964175283587247b0212db604 --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/btree.c | 5 +++++ src/btree.h | 1 + src/main.c | 9 +++++++++ src/pcache.c | 7 +++++++ src/pcache.h | 4 ++++ src/pcache1.c | 5 +++++ src/sqlite.h.in | 36 ++++++++++++++++++++++++------------ 9 files changed, 68 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 8d217ecfe0..2d1da1580d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\ssqlite3_stmt_scanstatus()\sdocumentation.\s\sNo\schanges\sto\scode. -D 2014-11-03T18:03:00.467 +C Add\sthe\sSQLITE_CONFIG_PCACHE_HDRSZ\soption\sfor\ssqlite3_config(). +D 2014-11-04T12:11:23.751 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,8 +172,8 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 61d96c2edacc5267fae6e477c24c774cd540d7f0 -F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8 +F src/btree.c 3cc918768d100f0efea62404b8f4e779b8c94731 +F src/btree.h 49b408be9c1cd41249076898e0673711071205d8 F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c 5f659bdb14cdba1c3b587b6ed09167c147e308a1 +F src/main.c 8903165064534858a79ae06615ea7f4b482ad482 F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -218,9 +218,9 @@ F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 F src/pager.c 8d97b3633f098fef817656dcbf167ca904511d78 F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 -F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a -F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a -F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5 +F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 +F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 +F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98 F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7 F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 11f33a3e968a9637d6fa4ae879b83edd171ac88f +F src/sqlite.h.in 915b5a955dd2f1d3c7e848f721af48ccc47b972b F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ab3b0fc5760c6d428dbe1f974726a7d3526640bc -R e3e372d3594a5227dc7ce2380d71aae3 +P d97c324eb1d870c994911c53fbf84205f4e3e7a1 +R 9efeed3832394f98added1ade80fb8e9 U drh -Z 7bcc3180ea33e48aa6d0e7855da7bfd4 +Z 388d5bd03930b5f393bf21b730c0228b diff --git a/manifest.uuid b/manifest.uuid index 0611c8a12e..d3cdc0284b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d97c324eb1d870c994911c53fbf84205f4e3e7a1 \ No newline at end of file +6eb03e62a34e8e0964175283587247b0212db604 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9300a6a54f..f815e85a6d 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8965,3 +8965,8 @@ void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){ int sqlite3BtreeIsReadonly(Btree *p){ return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; } + +/* +** Return the size of the header added to each page by this module. +*/ +int sqlite3HeaderSizeBtree(void){ return sizeof(MemPage); } diff --git a/src/btree.h b/src/btree.h index 38abdca1a2..63337b1946 100644 --- a/src/btree.h +++ b/src/btree.h @@ -196,6 +196,7 @@ void sqlite3BtreeClearCursor(BtCursor *); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); int sqlite3BtreeIsReadonly(Btree *pBt); +int sqlite3HeaderSizeBtree(void); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); diff --git a/src/main.c b/src/main.c index 65a662ee5a..6a896b2a3d 100644 --- a/src/main.c +++ b/src/main.c @@ -401,6 +401,15 @@ int sqlite3_config(int op, ...){ sqlite3GlobalConfig.nPage = va_arg(ap, int); break; } + case SQLITE_CONFIG_PCACHE_HDRSZ: { + /* Return the total size of all headers added to each page + ** of the page cache */ + *va_arg(ap, int*) = + sqlite3HeaderSizeBtree() + + sqlite3HeaderSizePcache() + + sqlite3HeaderSizePcache1(); + break; + } case SQLITE_CONFIG_PCACHE: { /* no-op */ diff --git a/src/pcache.c b/src/pcache.c index 191a9d00f4..13551872d1 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -651,6 +651,13 @@ void sqlite3PcacheShrink(PCache *pCache){ sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); } +/* +** Return the size of the header added by this middleware layer +** in the page-cache hierarchy. +*/ +int sqlite3HeaderSizePcache(void){ return sizeof(PgHdr); } + + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified diff --git a/src/pcache.h b/src/pcache.h index dd9bfc7451..9ed62a88ff 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -160,4 +160,8 @@ void sqlite3PcacheStats(int*,int*,int*,int*); void sqlite3PCacheSetDefault(void); +/* Return the header size */ +int sqlite3HeaderSizePcache(void); +int sqlite3HeaderSizePcache1(void); + #endif /* _PCACHE_H_ */ diff --git a/src/pcache1.c b/src/pcache1.c index a8c3217382..cad41b1b73 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -981,6 +981,11 @@ void sqlite3PCacheSetDefault(void){ sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods); } +/* +** Return the size of the header on each page of this PCACHE implementation. +*/ +int sqlite3HeaderSizePcache1(void){ return sizeof(PgHdr1); } + #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 41cc439846..13373afe4a 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1559,28 +1559,30 @@ struct sqlite3_mem_methods { **
^This option specifies a static memory buffer that SQLite can use for ** the database page cache with the default page cache implementation. ** This configuration should not be used if an application-define page -** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option. -** There are three arguments to this option: A pointer to 8-byte aligned +** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2] +** configuration option. +** ^There are three arguments to this option: A pointer to 8-byte aligned ** memory, the size of each page buffer (sz), and the number of pages (N). ** The sz argument should be the size of the largest database page -** (a power of two between 512 and 32768) plus a little extra for each -** page header. ^The page header size is 20 to 40 bytes depending on -** the host architecture. ^It is harmless, apart from the wasted memory, -** to make sz a little too large. The first -** argument should point to an allocation of at least sz*N bytes of memory. +** (a power of two between 512 and 32768) plus some extra bytes for each +** page header. ^The number of extra bytes needed by the page header +** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option +** to [sqlite3_config()]. +** ^It is harmless, apart from the wasted memory, +** for the sz parameter to be larger than necessary. The first +** argument should pointer to an 8-byte aligned block of memory that +** is at least sz*N bytes of memory, otherwise subsequent behavior is +** undefined. ** ^SQLite will use the memory provided by the first argument to satisfy its ** memory needs for the first N pages that it adds to cache. ^If additional ** page cache memory is needed beyond what is provided by this option, then -** SQLite goes to [sqlite3_malloc()] for the additional storage space. -** The pointer in the first argument must -** be aligned to an 8-byte boundary or subsequent behavior of SQLite -** will be undefined.
+** SQLite goes to [sqlite3_malloc()] for the additional storage space. ** ** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
**
^This option specifies a static memory buffer that SQLite will use ** for all of its dynamic memory allocation needs beyond those provided ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. -** There are three arguments: An 8-byte aligned pointer to the memory, +** ^There are three arguments: An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), @@ -1728,6 +1730,15 @@ struct sqlite3_mem_methods { ** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** +** +** [[SQLITE_CONFIG_PCACHE_HDRSZ]] +**
SQLITE_CONFIG_PCACHE_HDRSZ +**
^This option takes a single parameter which is a pointer to an integer +** and writes into that integer the number of extra bytes per page required +** for each page in [SQLITE_CONFIG_PAGECACHE]. The amount of +** extra space required can change depending on the compiler, +** target platform, and SQLite version. +** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ @@ -1752,6 +1763,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ +#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ /* ** CAPI3REF: Database Connection Configuration Options From 5279d3433c2ef6089559eb65d3ed1a3e298cc3b3 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Nov 2014 13:41:32 +0000 Subject: [PATCH 20/71] Improved documentation and addition of source-code evidence marks for the sqlite3_config() interface. FossilOrigin-Name: 681031a436fdd4cce426d6cd43cbae6b83167d26 --- manifest | 16 ++++---- manifest.uuid | 2 +- src/btree.c | 8 +++- src/main.c | 45 ++++++++++++++++++----- src/sqlite.h.in | 98 ++++++++++++++++++++++++++----------------------- 5 files changed, 103 insertions(+), 66 deletions(-) diff --git a/manifest b/manifest index 2d1da1580d..c02ddb43b9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_CONFIG_PCACHE_HDRSZ\soption\sfor\ssqlite3_config(). -D 2014-11-04T12:11:23.751 +C Improved\sdocumentation\sand\saddition\sof\ssource-code\sevidence\smarks\sfor\sthe\nsqlite3_config()\sinterface. +D 2014-11-04T13:41:32.444 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,7 +172,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 3cc918768d100f0efea62404b8f4e779b8c94731 +F src/btree.c 5b6e02a2cb69bfba5d44d0a093b8cc7468fdcf61 F src/btree.h 49b408be9c1cd41249076898e0673711071205d8 F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c 8903165064534858a79ae06615ea7f4b482ad482 +F src/main.c c673d0972da4b6826a3e907029faf5be0840cd57 F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 915b5a955dd2f1d3c7e848f721af48ccc47b972b +F src/sqlite.h.in 81c5105a19bd1c16a06d59e729ddc3bb0c26d003 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P d97c324eb1d870c994911c53fbf84205f4e3e7a1 -R 9efeed3832394f98added1ade80fb8e9 +P 6eb03e62a34e8e0964175283587247b0212db604 +R a92bedb66491253840f18dd40e991665 U drh -Z 388d5bd03930b5f393bf21b730c0228b +Z 6591907c91e192439bb8b0655576863e diff --git a/manifest.uuid b/manifest.uuid index d3cdc0284b..e57823b45e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6eb03e62a34e8e0964175283587247b0212db604 \ No newline at end of file +681031a436fdd4cce426d6cd43cbae6b83167d26 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index f815e85a6d..6fe8e10f3d 100644 --- a/src/btree.c +++ b/src/btree.c @@ -6649,7 +6649,13 @@ static int balance_nonroot( nMaxCells*sizeof(u8*) /* apCell */ + nMaxCells*sizeof(u16) /* szCell */ + pBt->pageSize; /* aSpace1 */ - assert( szScratch<=16896 || szScratch<=6*pBt->pageSize ); + + /* EVIDENCE-OF: R-37926-08392 SQLite will never request a scratch buffer + ** that is more than 6 times the database page size, except when + ** performing a checkpoint in WAL mode when the scratch buffer request + ** size is a small fraction of the size of the WAL file. */ + assert( szScratch<=6*pBt->pageSize ); + apCell = sqlite3ScratchMalloc( szScratch ); if( apCell==0 ){ rc = SQLITE_NOMEM; diff --git a/src/main.c b/src/main.c index 6a896b2a3d..80800d7cf6 100644 --- a/src/main.c +++ b/src/main.c @@ -372,38 +372,54 @@ int sqlite3_config(int op, ...){ #endif case SQLITE_CONFIG_MALLOC: { - /* Specify an alternative malloc implementation */ + /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The argument specifies alternative + ** low-level memory allocation routines to be used in place of the memory + ** allocation routines built into SQLite. */ sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); break; } case SQLITE_CONFIG_GETMALLOC: { - /* Retrieve the current malloc() implementation */ + /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is + ** filled with the currently defined memory allocation routines. */ if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; break; } case SQLITE_CONFIG_MEMSTATUS: { - /* Enable or disable the malloc status collection */ - sqlite3GlobalConfig.bMemstat = va_arg(ap, int); /* IMP: R-27464-47829 */ + /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes + ** single argument of type int, interpreted as a boolean, which enables + ** or disables the collection of memory allocation statistics. */ + sqlite3GlobalConfig.bMemstat = va_arg(ap, int); break; } case SQLITE_CONFIG_SCRATCH: { - /* Designate a buffer for scratch memory space */ + /* EVIDENCE-OF: R-08404-60887 There are three arguments to + ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from + ** which the scratch allocations will be drawn, the size of each scratch + ** allocation (sz), and the maximum number of scratch allocations (N). */ sqlite3GlobalConfig.pScratch = va_arg(ap, void*); sqlite3GlobalConfig.szScratch = va_arg(ap, int); sqlite3GlobalConfig.nScratch = va_arg(ap, int); break; } case SQLITE_CONFIG_PAGECACHE: { - /* Designate a buffer for page cache memory space */ + /* EVIDENCE-OF: R-31408-40510 There are three arguments to + ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size + ** of each page buffer (sz), and the number of pages (N). */ sqlite3GlobalConfig.pPage = va_arg(ap, void*); sqlite3GlobalConfig.szPage = va_arg(ap, int); sqlite3GlobalConfig.nPage = va_arg(ap, int); break; } case SQLITE_CONFIG_PCACHE_HDRSZ: { - /* Return the total size of all headers added to each page - ** of the page cache */ + /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes + ** a single parameter which is a pointer to an integer and writes into + ** that integer the number of extra bytes per page required for each page + ** in SQLITE_CONFIG_PAGECACHE. */ *va_arg(ap, int*) = sqlite3HeaderSizeBtree() + sqlite3HeaderSizePcache() + @@ -422,11 +438,18 @@ int sqlite3_config(int op, ...){ } case SQLITE_CONFIG_PCACHE2: { - /* Specify an alternative page cache implementation */ + /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. This object specifies the interface to a custom page cache + ** implementation. */ sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); break; } case SQLITE_CONFIG_GETPCACHE2: { + /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. SQLite copies of the current page cache implementation into + ** that object. */ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ sqlite3PCacheSetDefault(); } @@ -436,7 +459,9 @@ int sqlite3_config(int op, ...){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) case SQLITE_CONFIG_HEAP: { - /* Designate a buffer for heap memory space */ + /* EVIDENCE-OF: R-19854-42126 There are three arguments to + ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the + ** number of bytes in the memory buffer, and the minimum allocation size. */ sqlite3GlobalConfig.pHeap = va_arg(ap, void*); sqlite3GlobalConfig.nHeap = va_arg(ap, int); sqlite3GlobalConfig.mnReq = va_arg(ap, int); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 13373afe4a..271b7a0ad1 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1499,25 +1499,27 @@ struct sqlite3_mem_methods { ** SQLITE_CONFIG_SERIALIZED configuration option.
** ** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
-**
^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mem_methods] structure. The argument specifies +**
^(The SQLITE_CONFIG_MALLOC option takes a single argument which is +** a pointer to an instance of the [sqlite3_mem_methods] structure. +** The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.
** ** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
-**
^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] +**
^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which +** is a pointer to an instance of the [sqlite3_mem_methods] structure. +** The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
** ** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
-**
^This option takes single argument of type int, interpreted as a -** boolean, which enables or disables the collection of memory allocation -** statistics. ^(When memory allocation statistics are disabled, the +**
^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +** interpreted as a boolean, which enables or disables the collection of +** memory allocation statistics. ^(When memory allocation statistics are disabled, the ** following SQLite interfaces become non-operational: **
    **
  • [sqlite3_memory_used()] @@ -1531,8 +1533,9 @@ struct sqlite3_mem_methods { **
** ** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
-**
^This option specifies a static memory buffer that SQLite can use for -** scratch memory. ^(There are three arguments: A pointer an 8-byte +**
^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer +** that SQLite can use for scratch memory. ^(There are three arguments +** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), ** and the maximum number of scratch allocations (N).)^ @@ -1556,12 +1559,13 @@ struct sqlite3_mem_methods { **
** ** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
-**
^This option specifies a static memory buffer that SQLite can use for -** the database page cache with the default page cache implementation. +**
^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer +** that SQLite can use for the database page cache with the default page +** cache implementation. ** This configuration should not be used if an application-define page ** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2] ** configuration option. -** ^There are three arguments to this option: A pointer to 8-byte aligned +** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned ** memory, the size of each page buffer (sz), and the number of pages (N). ** The sz argument should be the size of the largest database page ** (a power of two between 512 and 32768) plus some extra bytes for each @@ -1579,10 +1583,11 @@ struct sqlite3_mem_methods { ** SQLite goes to [sqlite3_malloc()] for the additional storage space.
** ** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
-**
^This option specifies a static memory buffer that SQLite will use -** for all of its dynamic memory allocation needs beyond those provided -** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. -** ^There are three arguments: An 8-byte aligned pointer to the memory, +**
^The SQLITE_CONFIG_HEAP option specifies a static memory buffer +** that SQLite will use for all of its dynamic memory allocation needs +** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. +** ^There are three arguments to SQLITE_CONFIG_HEAP: +** An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), @@ -1596,9 +1601,9 @@ struct sqlite3_mem_methods { ** for the minimum allocation size are 2**5 through 2**8.
** ** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
-**
^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mutex_methods] structure. The argument specifies -** alternative low-level mutex routines to be used in place +**
^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a +** pointer to an instance of the [sqlite3_mutex_methods] structure. +** The argument specifies alternative low-level mutex routines to be used in place ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the ** content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with @@ -1608,8 +1613,8 @@ struct sqlite3_mem_methods { ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
-**
^(This option takes a single argument which is a pointer to an -** instance of the [sqlite3_mutex_methods] structure. The +**
^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which +** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] ** structure is filled with the currently defined mutex routines.)^ ** This option can be used to overload the default mutex allocation @@ -1621,24 +1626,24 @@ struct sqlite3_mem_methods { ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
-**
^(This option takes two arguments that determine the default -** memory allocation for the lookaside memory allocator on each -** [database connection]. The first argument is the +**
^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine +** the default size of lookaside memory on each [database connection]. +** The first argument is the ** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(This option sets the -** default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** verb to [sqlite3_db_config()] can be used to change the lookaside +** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE +** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] +** option to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^
** ** [[SQLITE_CONFIG_PCACHE2]]
SQLITE_CONFIG_PCACHE2
-**
^(This option takes a single argument which is a pointer to -** an [sqlite3_pcache_methods2] object. This object specifies the interface -** to a custom page cache implementation.)^ ^SQLite makes a copy of the -** object and uses it for page cache memory allocations.
+**
^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is +** a pointer to an [sqlite3_pcache_methods2] object. This object specifies +** the interface to a custom page cache implementation.)^ +** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
** ** [[SQLITE_CONFIG_GETPCACHE2]]
SQLITE_CONFIG_GETPCACHE2
-**
^(This option takes a single argument which is a pointer to an -** [sqlite3_pcache_methods2] object. SQLite copies of the current +**
^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of the current ** page cache implementation into that object.)^
** ** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
@@ -1662,10 +1667,10 @@ struct sqlite3_mem_methods { ** function must be threadsafe. ** ** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI -**
^(This option takes a single argument of type int. If non-zero, then -** URI handling is globally enabled. If the parameter is zero, then URI handling -** is globally disabled.)^ ^If URI handling is globally enabled, all filenames -** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or +**
^(The SQLITE_CONFIG_URI option takes a single argument of type int. +** If non-zero, then URI handling is globally enabled. If the parameter is zero, +** then URI handling is globally disabled.)^ ^If URI handling is globally enabled, +** all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or ** specified as part of [ATTACH] commands are interpreted as URIs, regardless ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database ** connection is opened. ^If it is globally disabled, filenames are @@ -1675,9 +1680,10 @@ struct sqlite3_mem_methods { ** [SQLITE_USE_URI] symbol defined.)^ ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
SQLITE_CONFIG_COVERING_INDEX_SCAN -**
^This option takes a single integer argument which is interpreted as -** a boolean in order to enable or disable the use of covering indices for -** full table scans in the query optimizer. ^The default setting is determined +**
^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer +** argument which is interpreted as a boolean in order to enable or disable +** the use of covering indices for full table scans in the query optimizer. +** ^The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans @@ -1725,17 +1731,17 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] **
SQLITE_CONFIG_WIN32_HEAPSIZE -**
^This option is only available if SQLite is compiled for Windows -** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. -** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value +**
^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is +** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. +** ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** ** ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] **
SQLITE_CONFIG_PCACHE_HDRSZ -**
^This option takes a single parameter which is a pointer to an integer -** and writes into that integer the number of extra bytes per page required -** for each page in [SQLITE_CONFIG_PAGECACHE]. The amount of +**
^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which +** is a pointer to an integer and writes into that integer the number of extra +** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. The amount of ** extra space required can change depending on the compiler, ** target platform, and SQLite version. ** From cbd55b0362c8dd2a0c7c3bd0bc56bd16ccd2d962 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Nov 2014 14:22:27 +0000 Subject: [PATCH 21/71] Change the definition of SQLITE_CONFIG_SCRATCH so that at most one scratch buffer is used per thread. Use the generic heap memory allocator for the WalIterator object when running a checkpoint. FossilOrigin-Name: 391c9b85abcb5ba300fb2e116384639310c69ed2 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/btree.c | 7 ++----- src/malloc.c | 11 ++++++----- src/sqlite.h.in | 8 ++------ src/wal.c | 8 ++++---- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index c02ddb43b9..9decec2f00 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sdocumentation\sand\saddition\sof\ssource-code\sevidence\smarks\sfor\sthe\nsqlite3_config()\sinterface. -D 2014-11-04T13:41:32.444 +C Change\sthe\sdefinition\sof\sSQLITE_CONFIG_SCRATCH\sso\sthat\sat\smost\sone\sscratch\nbuffer\sis\sused\sper\sthread.\s\sUse\sthe\sgeneric\sheap\smemory\sallocator\sfor\sthe\nWalIterator\sobject\swhen\srunning\sa\scheckpoint. +D 2014-11-04T14:22:27.705 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,7 +172,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 5b6e02a2cb69bfba5d44d0a093b8cc7468fdcf61 +F src/btree.c 11d1262110c2d459b68121833fa3ec6625b1d022 F src/btree.h 49b408be9c1cd41249076898e0673711071205d8 F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 @@ -195,7 +195,7 @@ F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 F src/main.c c673d0972da4b6826a3e907029faf5be0840cd57 -F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec +F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 -F src/sqlite.h.in 81c5105a19bd1c16a06d59e729ddc3bb0c26d003 +F src/sqlite.h.in 6e9af739d79f0bea2584b70fb1c54d3bb1a2eab6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -299,7 +299,7 @@ F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c daf87ea542df088ac4607660d09976d36b6bd95d F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 -F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 +F src/wal.c 825c948066c7604a07d56e67958cdab210749016 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/where.c d5fa1081bf7cb70478ed06489e063695c92ee1e1 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 6eb03e62a34e8e0964175283587247b0212db604 -R a92bedb66491253840f18dd40e991665 +P 681031a436fdd4cce426d6cd43cbae6b83167d26 +R cb98a95faa41015902ec00cd7a294542 U drh -Z 6591907c91e192439bb8b0655576863e +Z 113a55cc7642fbc8d6bb5b88b140b929 diff --git a/manifest.uuid b/manifest.uuid index e57823b45e..cd70e30b51 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -681031a436fdd4cce426d6cd43cbae6b83167d26 \ No newline at end of file +391c9b85abcb5ba300fb2e116384639310c69ed2 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 6fe8e10f3d..fe15c922ca 100644 --- a/src/btree.c +++ b/src/btree.c @@ -6650,12 +6650,9 @@ static int balance_nonroot( + nMaxCells*sizeof(u16) /* szCell */ + pBt->pageSize; /* aSpace1 */ - /* EVIDENCE-OF: R-37926-08392 SQLite will never request a scratch buffer - ** that is more than 6 times the database page size, except when - ** performing a checkpoint in WAL mode when the scratch buffer request - ** size is a small fraction of the size of the WAL file. */ + /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer + ** that is more than 6 times the database page size. */ assert( szScratch<=6*pBt->pageSize ); - apCell = sqlite3ScratchMalloc( szScratch ); if( apCell==0 ){ rc = SQLITE_NOMEM; diff --git a/src/malloc.c b/src/malloc.c index 6fb9d53d1b..4960f91e02 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -377,11 +377,12 @@ void *sqlite3ScratchMalloc(int n){ #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* Verify that no more than two scratch allocations per thread - ** are outstanding at one time. (This is only checked in the - ** single-threaded case since checking in the multi-threaded case - ** would be much more complicated.) */ - assert( scratchAllocOut<=1 ); + /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch + ** buffers per thread. + ** + ** This can only be checked in single-threaded mode. + */ + assert( scratchAllocOut==0 ); if( p ) scratchAllocOut++; #endif diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 271b7a0ad1..44f7800ca2 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1541,13 +1541,9 @@ struct sqlite3_mem_methods { ** and the maximum number of scratch allocations (N).)^ ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. -** ^SQLite will not use more than two scratch buffers per thread and not -** more than one scratch buffer per thread when not performing -** a [checkpoint] in [WAL mode]. +** ^SQLite will not use more than one scratch buffers per thread. ** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size, except when performing a [checkpoint] -** in [WAL mode] when the scratch buffer request size is a small fraction -** of the size of the WAL file. +** times the database page size. ** ^If SQLite needs needs additional ** scratch memory beyond what is provided by this configuration option, then ** [sqlite3_malloc()] will be used to obtain the memory needed.

diff --git a/src/wal.c b/src/wal.c index c0861d5be7..d2ed293a4d 100644 --- a/src/wal.c +++ b/src/wal.c @@ -1504,7 +1504,7 @@ static void walMergesort( ** Free an iterator allocated by walIteratorInit(). */ static void walIteratorFree(WalIterator *p){ - sqlite3ScratchFree(p); + sqlite3_free(p); } /* @@ -1539,7 +1539,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + iLast*sizeof(ht_slot); - p = (WalIterator *)sqlite3ScratchMalloc(nByte); + p = (WalIterator *)sqlite3_malloc(nByte); if( !p ){ return SQLITE_NOMEM; } @@ -1549,7 +1549,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ /* Allocate temporary space used by the merge-sort routine. This block ** of memory will be freed before this function returns. */ - aTmp = (ht_slot *)sqlite3ScratchMalloc( + aTmp = (ht_slot *)sqlite3_malloc( sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) ); if( !aTmp ){ @@ -1586,7 +1586,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ p->aSegment[i].aPgno = (u32 *)aPgno; } } - sqlite3ScratchFree(aTmp); + sqlite3_free(aTmp); if( rc!=SQLITE_OK ){ walIteratorFree(p); From 4d9f188f005b204e5e7aa4f60762ad67948d2f9c Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Nov 2014 17:23:24 +0000 Subject: [PATCH 22/71] Add various requirements evidence marks for sqlite3_config() options. FossilOrigin-Name: d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/global.c | 8 ++++++++ src/main.c | 25 ++++++++++++++++++++----- src/vdbesort.c | 2 +- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 9decec2f00..e9f3481cba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sdefinition\sof\sSQLITE_CONFIG_SCRATCH\sso\sthat\sat\smost\sone\sscratch\nbuffer\sis\sused\sper\sthread.\s\sUse\sthe\sgeneric\sheap\smemory\sallocator\sfor\sthe\nWalIterator\sobject\swhen\srunning\sa\scheckpoint. -D 2014-11-04T14:22:27.705 +C Add\svarious\srequirements\sevidence\smarks\sfor\ssqlite3_config()\soptions. +D 2014-11-04T17:23:24.610 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -185,7 +185,7 @@ F src/expr.c 0391a657df4959eaf2a2fd7d77de5ebe750686ee F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee -F src/global.c 01c1f36ecfcf10770db648422a8852c222308bb9 +F src/global.c a50ad0b9ee328107a65aa8f5f3cd34905e74745c F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c c673d0972da4b6826a3e907029faf5be0840cd57 +F src/main.c 42f857be3cef3e1f9752d8e46d61345f80932396 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -296,7 +296,7 @@ F src/vdbeapi.c 900259bdd85cd66a9f210d8ec08147a9034593bd F src/vdbeaux.c cf6b8152dd22155201d57c216e6266866b61da59 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f -F src/vdbesort.c daf87ea542df088ac4607660d09976d36b6bd95d +F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 825c948066c7604a07d56e67958cdab210749016 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 681031a436fdd4cce426d6cd43cbae6b83167d26 -R cb98a95faa41015902ec00cd7a294542 +P 391c9b85abcb5ba300fb2e116384639310c69ed2 +R 59d979fd0dabfa4a2d3ae24d9471db8f U drh -Z 113a55cc7642fbc8d6bb5b88b140b929 +Z d72c7362e49ef35f8e5912118c20e6ff diff --git a/manifest.uuid b/manifest.uuid index cd70e30b51..969ed55bc1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -391c9b85abcb5ba300fb2e116384639310c69ed2 \ No newline at end of file +d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 \ No newline at end of file diff --git a/src/global.c b/src/global.c index e769eb425f..b5323e8df6 100644 --- a/src/global.c +++ b/src/global.c @@ -135,11 +135,19 @@ const unsigned char sqlite3CtypeMap[256] = { ** ** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled ** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. +** +** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** SQLITE_USE_URI symbol defined. */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif +/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the +** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if +** that compile-time option is omitted. +*/ #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #endif diff --git a/src/main.c b/src/main.c index 80800d7cf6..4c33bbde9d 100644 --- a/src/main.c +++ b/src/main.c @@ -523,11 +523,19 @@ int sqlite3_config(int op, ...){ ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. */ case SQLITE_CONFIG_URI: { + /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single + ** argument of type int. If non-zero, then URI handling is globally + ** enabled. If the parameter is zero, then URI handling is globally + ** disabled. */ sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; } case SQLITE_CONFIG_COVERING_INDEX_SCAN: { + /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN + ** option takes a single integer argument which is interpreted as a + ** boolean in order to enable or disable the use of covering indices for + ** full table scans in the query optimizer. */ sqlite3GlobalConfig.bUseCis = va_arg(ap, int); break; } @@ -542,20 +550,27 @@ int sqlite3_config(int op, ...){ #endif case SQLITE_CONFIG_MMAP_SIZE: { + /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit + ** integer (sqlite3_int64) values that are the default mmap size limit + ** (the default setting for PRAGMA mmap_size) and the maximum allowed + ** mmap size limit. */ sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ - mxMmap = SQLITE_MAX_MMAP_SIZE; - } - sqlite3GlobalConfig.mxMmap = mxMmap; + /* EVIDENCE-OF: R-53367-43190 If either argument to this option is + ** negative, then that argument is changed to its compile-time default. */ + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; + sqlite3GlobalConfig.mxMmap = mxMmap; sqlite3GlobalConfig.szMmap = szMmap; break; } -#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) +#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ case SQLITE_CONFIG_WIN32_HEAPSIZE: { + /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit + ** unsigned integer value that specifies the maximum size of the created + ** heap. */ sqlite3GlobalConfig.nHeap = va_arg(ap, int); break; } diff --git a/src/vdbesort.c b/src/vdbesort.c index 918d840716..df8357a57e 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -100,7 +100,7 @@ ** The sorter is running in multi-threaded mode if (a) the library was built ** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater ** than zero, and (b) worker threads have been enabled at runtime by calling -** sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, ...). +** "PRAGMA threads=N" with some value of N greater than 0. ** ** When Rewind() is called, any data remaining in memory is flushed to a ** final PMA. So at this point the data is stored in some number of sorted From 73767829b9a224197d8d046f653535770bd97174 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Tue, 4 Nov 2014 19:37:22 +0000 Subject: [PATCH 23/71] For the Win32 VFS, allow memory mapped files to work when compiled without WAL support. FossilOrigin-Name: 1fc7e2f3d34e25e7b59aa8b51d10c1e27ab4a527 --- manifest | 17 ++++++++++------- manifest.uuid | 2 +- src/os_win.c | 27 +++++++++++++++++---------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index e9f3481cba..74e32143e0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\svarious\srequirements\sevidence\smarks\sfor\ssqlite3_config()\soptions. -D 2014-11-04T17:23:24.610 +C For\sthe\sWin32\sVFS,\sallow\smemory\smapped\sfiles\sto\swork\swhen\scompiled\swithout\sWAL\ssupport. +D 2014-11-04T19:37:22.576 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -213,7 +213,7 @@ F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7 -F src/os_win.c a019caaae2bcbbc0cc4c39af6e7d7e43d8426053 +F src/os_win.c a9e500dd963fb1f67d7860e58b5772abe6123862 F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 F src/pager.c 8d97b3633f098fef817656dcbf167ca904511d78 F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b @@ -1211,7 +1211,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 391c9b85abcb5ba300fb2e116384639310c69ed2 -R 59d979fd0dabfa4a2d3ae24d9471db8f -U drh -Z d72c7362e49ef35f8e5912118c20e6ff +P d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 +R c0de55f8c674bc2f58a7f862c94a6470 +T *branch * winMmapNoWal +T *sym-winMmapNoWal * +T -sym-trunk * +U mistachkin +Z 8ecf95ce02a024463c10f127838cfcbc diff --git a/manifest.uuid b/manifest.uuid index 969ed55bc1..e9b06734b6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 \ No newline at end of file +1fc7e2f3d34e25e7b59aa8b51d10c1e27ab4a527 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index 8ca2107d90..2a7681c73f 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -34,6 +34,11 @@ with SQLITE_OMIT_WAL." #endif +#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 +# error "Memory mapped files require support from the Windows NT kernel,\ + compile with SQLITE_MAX_MMAP_SIZE=0." +#endif + /* ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions ** based on the sub-platform)? @@ -163,10 +168,11 @@ /* ** Do we need to manually define the Win32 file mapping APIs for use with WAL -** mode (e.g. these APIs are available in the Windows CE SDK; however, they -** are not present in the header file)? +** mode or memory mapped files (e.g. these APIs are available in the Windows +** CE SDK; however, they are not present in the header file)? */ -#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) +#if SQLITE_WIN32_FILEMAPPING_API && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) /* ** Two of the file mapping APIs are different under WinRT. Figure out which ** set we need. @@ -194,7 +200,7 @@ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); ** This file mapping API is common to both Win32 and WinRT. */ WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); -#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */ +#endif /* SQLITE_WIN32_FILEMAPPING_API */ /* ** Some Microsoft compilers lack this definition. @@ -487,7 +493,7 @@ static struct win_syscall { LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) #if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ - !defined(SQLITE_OMIT_WAL)) + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, #else { "CreateFileMappingA", (SYSCALL)0, 0 }, @@ -497,7 +503,7 @@ static struct win_syscall { DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) #if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - !defined(SQLITE_OMIT_WAL)) + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, @@ -837,7 +843,8 @@ static struct win_syscall { LPOVERLAPPED))aSyscall[48].pCurrent) #endif -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)) +#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, @@ -907,7 +914,7 @@ static struct win_syscall { #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ LPOVERLAPPED))aSyscall[58].pCurrent) -#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) +#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, #else { "UnmapViewOfFile", (SYSCALL)0, 0 }, @@ -970,7 +977,7 @@ static struct win_syscall { #define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) -#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) +#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, #else { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, @@ -1034,7 +1041,7 @@ static struct win_syscall { #define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) -#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) +#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, #else { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, From fdece7bad171dbb43985dfc7f53cf4a6e368c350 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Tue, 4 Nov 2014 19:52:15 +0000 Subject: [PATCH 24/71] Skip tests that require WAL mode when it is not enabled. FossilOrigin-Name: 6fc4ead26d19b9348bbda34c3053ae1e066abc32 --- manifest | 15 ++++----- manifest.uuid | 2 +- test/mmap1.test | 86 +++++++++++++++++++++++++------------------------ 3 files changed, 51 insertions(+), 52 deletions(-) diff --git a/manifest b/manifest index 74e32143e0..cf7c330a5e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sthe\sWin32\sVFS,\sallow\smemory\smapped\sfiles\sto\swork\swhen\scompiled\swithout\sWAL\ssupport. -D 2014-11-04T19:37:22.576 +C Skip\stests\sthat\srequire\sWAL\smode\swhen\sit\sis\snot\senabled. +D 2014-11-04T19:52:15.610 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -728,7 +728,7 @@ F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 -F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b +F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 @@ -1211,10 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 -R c0de55f8c674bc2f58a7f862c94a6470 -T *branch * winMmapNoWal -T *sym-winMmapNoWal * -T -sym-trunk * +P 1fc7e2f3d34e25e7b59aa8b51d10c1e27ab4a527 +R ab0636a3afda48f38dd438546ea79dde U mistachkin -Z 8ecf95ce02a024463c10f127838cfcbc +Z 673ee028789258ee8d4aa78195cdb56d diff --git a/manifest.uuid b/manifest.uuid index e9b06734b6..b10e2d0d51 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1fc7e2f3d34e25e7b59aa8b51d10c1e27ab4a527 \ No newline at end of file +6fc4ead26d19b9348bbda34c3053ae1e066abc32 \ No newline at end of file diff --git a/test/mmap1.test b/test/mmap1.test index ece3e0201e..18aec9f8fa 100644 --- a/test/mmap1.test +++ b/test/mmap1.test @@ -33,7 +33,7 @@ proc register_rblob_code {dbname seed} { set ::rcnt $seed proc rblob {n} { set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF] - set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] + set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] string range [string repeat [set str] [expr [set n]/4]] 1 [set n] } $dbname func rblob rblob @@ -42,7 +42,7 @@ proc register_rblob_code {dbname seed} { # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on # unix and 9 on windows. The difference is that windows only ever maps -# an integer number of OS pages (i.e. creates mappings that are a multiple +# an integer number of OS pages (i.e. creates mappings that are a multiple # of 4KB in size). Whereas on unix any sized mapping may be created. # foreach {t mmap_size nRead c2init} { @@ -106,50 +106,52 @@ foreach {t mmap_size nRead c2init} { set ::rcnt 0 proc rblob {n} { set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] - set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] + set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] string range [string repeat $str [expr $n/4]] 1 $n } reset_db db func rblob rblob -do_execsql_test 2.1 { - PRAGMA auto_vacuum = 1; - PRAGMA mmap_size = 67108864; - PRAGMA journal_mode = wal; - CREATE TABLE t1(a, b, UNIQUE(a, b)); - INSERT INTO t1 VALUES(rblob(500), rblob(500)); - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 - PRAGMA wal_checkpoint; -} {67108864 wal 0 103 103} - -do_execsql_test 2.2 { - PRAGMA auto_vacuum; - SELECT count(*) FROM t1; -} {1 32} - -if {[permutation] != "inmemory_journal"} { - do_test 2.3 { - sqlite3 db2 test.db - db2 func rblob rblob - db2 eval { - DELETE FROM t1 WHERE (rowid%4); - PRAGMA wal_checkpoint; - } - db2 eval { - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 - SELECT count(*) FROM t1; - } - } {16} - - do_execsql_test 2.4 { +ifcapable wal { + do_execsql_test 2.1 { + PRAGMA auto_vacuum = 1; + PRAGMA mmap_size = 67108864; + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b, UNIQUE(a, b)); + INSERT INTO t1 VALUES(rblob(500), rblob(500)); + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 PRAGMA wal_checkpoint; - } {0 24 24} - db2 close + } {67108864 wal 0 103 103} + + do_execsql_test 2.2 { + PRAGMA auto_vacuum; + SELECT count(*) FROM t1; + } {1 32} + + if {[permutation] != "inmemory_journal"} { + do_test 2.3 { + sqlite3 db2 test.db + db2 func rblob rblob + db2 eval { + DELETE FROM t1 WHERE (rowid%4); + PRAGMA wal_checkpoint; + } + db2 eval { + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 + SELECT count(*) FROM t1; + } + } {16} + + do_execsql_test 2.4 { + PRAGMA wal_checkpoint; + } {0 24 24} + db2 close + } } reset_db @@ -227,7 +229,7 @@ do_test 4.4 { do_execsql_test 4.5 { COMMIT } #------------------------------------------------------------------------- -# Ensure that existing cursors holding xFetch() references are not +# Ensure that existing cursors holding xFetch() references are not # confused if those pages are moved to make way for the root page of a # new table or index. # @@ -296,7 +298,7 @@ foreach {tn1 mmap1 mmap2} { sql1 "PRAGMA mmap_size = $mmap1" sql2 "PRAGMA mmap_size = $mmap2" - do_test $tn1.$tn { + do_test $tn1.$tn { for {set i 1} {$i <= 100} {incr i} { if {$i % 2} { set c1 sql1 @@ -311,7 +313,7 @@ foreach {tn1 mmap1 mmap2} { UPDATE t2 SET x = (SELECT md5sum(a) FROM t1); } - set res [$c2 { + set res [$c2 { SELECT count(*) FROM t1; SELECT x == (SELECT md5sum(a) FROM t1) FROM t2; PRAGMA integrity_check; From 547fb61807b3ac19ee97d5acc99e0810e4baba5d Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 4 Nov 2014 21:38:45 +0000 Subject: [PATCH 25/71] Improved output formatting for the showstat4 tool. FossilOrigin-Name: 7df82c46da437bc743576358c25e758280067df8 --- manifest | 12 ++++++------ manifest.uuid | 2 +- tool/showstat4.c | 9 +++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index e9f3481cba..9ad9755cc5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\svarious\srequirements\sevidence\smarks\sfor\ssqlite3_config()\soptions. -D 2014-11-04T17:23:24.610 +C Improved\soutput\sformatting\sfor\sthe\sshowstat4\stool. +D 2014-11-04T21:38:45.383 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -1190,7 +1190,7 @@ F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 F tool/showdb.c bd073a78bce714a0e42d92ea474b3eb8cb53be5d F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5 -F tool/showstat4.c c39279d6bd37cb999b634f0064f6f86ad7af008f +F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a F tool/showwal.c 85cb36d4fe3e93e2fbd63e786e0d1ce42d0c4fad F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 391c9b85abcb5ba300fb2e116384639310c69ed2 -R 59d979fd0dabfa4a2d3ae24d9471db8f +P d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 +R 3d8e834a0bd7bfcb019dc53478b58f7b U drh -Z d72c7362e49ef35f8e5912118c20e6ff +Z 0a79c8f46f24bb92a10190eb30b27d6d diff --git a/manifest.uuid b/manifest.uuid index 969ed55bc1..11e49b8e8c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 \ No newline at end of file +7df82c46da437bc743576358c25e758280067df8 \ No newline at end of file diff --git a/tool/showstat4.c b/tool/showstat4.c index 668d2106af..215962919e 100644 --- a/tool/showstat4.c +++ b/tool/showstat4.c @@ -39,6 +39,7 @@ int main(int argc, char **argv){ int nSample; i64 iVal; const char *zSep; + int iRow = 0; if( argc!=2 ){ fprintf(stderr, "Usage: %s DATABASE-FILE\n", argv[0]); @@ -60,13 +61,13 @@ int main(int argc, char **argv){ } while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( zIdx==0 || strcmp(zIdx, (const char*)sqlite3_column_text(pStmt,0))!=0 ){ - if( zIdx ) printf("\n"); + if( zIdx ) printf("\n**************************************" + "**************\n\n"); sqlite3_free(zIdx); zIdx = sqlite3_mprintf("%s", sqlite3_column_text(pStmt,0)); - printf("%s:\n", zIdx); - }else{ - printf(" -----------------------------------------------------------\n"); + iRow = 0; } + printf("%s sample %d ------------------------------------\n", zIdx, ++iRow); printf(" nEq = %s\n", sqlite3_column_text(pStmt,1)); printf(" nLt = %s\n", sqlite3_column_text(pStmt,2)); printf(" nDLt = %s\n", sqlite3_column_text(pStmt,3)); From 8d1edb92c4c5d29bb0746b79778692b66e2c1296 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 5 Nov 2014 09:07:28 +0000 Subject: [PATCH 26/71] Add the ".scanstats on" command to the shell tool. Executing this command causes the shell tool to print values from sqlite3_stmt_scanstatus() after each query is run. FossilOrigin-Name: 7974c0ed10ffdc960a43fed89845c2bed428958d --- manifest | 14 ++++++------- manifest.uuid | 2 +- src/shell.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 9ad9755cc5..29e1d31cf2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\soutput\sformatting\sfor\sthe\sshowstat4\stool. -D 2014-11-04T21:38:45.383 +C Add\sthe\s".scanstats\son"\scommand\sto\sthe\sshell\stool.\sExecuting\sthis\scommand\scauses\sthe\sshell\stool\sto\sprint\svalues\sfrom\ssqlite3_stmt_scanstatus()\safter\seach\squery\sis\srun. +D 2014-11-05T09:07:28.365 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,7 +228,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 282f8f5278e0c78eb442217531172ec9e1538796 +F src/shell.c 5ad1eb4dfcd7a57e15825207a9bd559415bf34b1 F src/sqlite.h.in 6e9af739d79f0bea2584b70fb1c54d3bb1a2eab6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P d423349d2cd8bc7e04f3d90ca7bab11e1ad86e25 -R 3d8e834a0bd7bfcb019dc53478b58f7b -U drh -Z 0a79c8f46f24bb92a10190eb30b27d6d +P 7df82c46da437bc743576358c25e758280067df8 +R f4931dcb1177b970d566df3dbaa382ec +U dan +Z 44baa22d0450fc9fcacf5946d93d71c5 diff --git a/manifest.uuid b/manifest.uuid index 11e49b8e8c..ccd696efe4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7df82c46da437bc743576358c25e758280067df8 \ No newline at end of file +7974c0ed10ffdc960a43fed89845c2bed428958d \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 59cd2011e7..3423bb0143 100644 --- a/src/shell.c +++ b/src/shell.c @@ -457,6 +457,7 @@ struct ShellState { int echoOn; /* True to echo input commands */ int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ int statsOn; /* True to display memory stats before each finalize */ + int scanstatsOn; /* True to display scan stats before each finalize */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ @@ -1185,6 +1186,42 @@ static int display_stats( return 0; } +/* +** Display scan stats. +*/ +static void display_scanstats( + sqlite3 *db, /* Database to query */ + ShellState *pArg /* Pointer to ShellState */ +){ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + int i; + fprintf(pArg->out, "-------- scanstats --------\n"); + for(i=0; 1; i++){ + sqlite3_stmt *p = pArg->pStmt; + sqlite3_int64 nEst, nLoop, nVisit; + const char *zExplain; + if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ + break; + } + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&nEst); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); + + fprintf(pArg->out, "Loop %d: \"%s\"\n", i, zExplain); + fprintf(pArg->out, " nLoop=%-8lld nVisit=%-8lld nEst=%-8lld\n", + nLoop, nVisit, nEst + ); + } +#else + fprintf(pArg->out, "-------- scanstats --------\n"); + fprintf(pArg->out, + "sqlite3_stmt_scanstatus() unavailable - " + "rebuild with SQLITE_ENABLE_STMT_SCANSTATUS\n" + ); +#endif + fprintf(pArg->out, "---------------------------\n"); +} + /* ** Parameter azArray points to a zero-terminated array of strings. zStr ** points to a single nul-terminated string. Return non-zero if zStr @@ -1423,6 +1460,11 @@ static int shell_exec( display_stats(db, pArg, 0); } + /* print loop-counters if required */ + if( pArg && pArg->scanstatsOn ){ + display_scanstats(db, pArg); + } + /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** next statement to execute. */ @@ -3014,6 +3056,16 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_close(pSrc); }else + + if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ + if( nArg==2 ){ + p->scanstatsOn = booleanValue(azArg[1]); + }else{ + fprintf(stderr, "Usage: .scanstats on|off\n"); + rc = 1; + } + }else + if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ ShellState data; char *zErrMsg = 0; @@ -4140,6 +4192,8 @@ int main(int argc, char **argv){ data.autoEQP = 1; }else if( strcmp(z,"-stats")==0 ){ data.statsOn = 1; + }else if( strcmp(z,"-scanstats")==0 ){ + data.scanstatsOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ From e0de876e279cc6cfd9f809a145f1172cbae9837e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Nov 2014 13:13:13 +0000 Subject: [PATCH 27/71] Enhance whereLoopCheaperProperSubset(X,Y) so that it does not report true if X uses skip-scan less than Y, since in that case X might deserve to be cheaper even if it is a proper subset. FossilOrigin-Name: c106b755369c1f8546e897ecd2ac56fd09d6e885 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 12 +++++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 29e1d31cf2..8e0066d70e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s".scanstats\son"\scommand\sto\sthe\sshell\stool.\sExecuting\sthis\scommand\scauses\sthe\sshell\stool\sto\sprint\svalues\sfrom\ssqlite3_stmt_scanstatus()\safter\seach\squery\sis\srun. -D 2014-11-05T09:07:28.365 +C Enhance\swhereLoopCheaperProperSubset(X,Y)\sso\sthat\sit\sdoes\snot\sreport\strue\nif\sX\suses\sskip-scan\sless\sthan\sY,\ssince\sin\sthat\scase\sX\smight\ndeserve\sto\sbe\scheaper\seven\sif\sit\sis\sa\sproper\ssubset. +D 2014-11-05T13:13:13.983 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 825c948066c7604a07d56e67958cdab210749016 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c d5fa1081bf7cb70478ed06489e063695c92ee1e1 +F src/where.c 240961041f35862ebcafd260587c79a1ab7347f8 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7df82c46da437bc743576358c25e758280067df8 -R f4931dcb1177b970d566df3dbaa382ec -U dan -Z 44baa22d0450fc9fcacf5946d93d71c5 +P 7974c0ed10ffdc960a43fed89845c2bed428958d +R 418c93fe7ac7140cffa87d5f3271cb48 +U drh +Z 68c42aaa0a73598a09ed4215a5cfd466 diff --git a/manifest.uuid b/manifest.uuid index ccd696efe4..da46c6359a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7974c0ed10ffdc960a43fed89845c2bed428958d \ No newline at end of file +c106b755369c1f8546e897ecd2ac56fd09d6e885 \ No newline at end of file diff --git a/src/where.c b/src/where.c index d7966fdfbc..34614e6bb3 100644 --- a/src/where.c +++ b/src/where.c @@ -4012,10 +4012,11 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } /* -** Return TRUE if both of the following are true: +** Return TRUE if all of the following are true: ** ** (1) X has the same or lower cost that Y ** (2) X is a proper subset of Y +** (3) X skips at least as many columns as Y ** ** By "proper subset" we mean that X uses fewer WHERE clause terms ** than Y and that every WHERE clause term used by X is also used @@ -4023,7 +4024,9 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** ** If X is a proper subset of Y then Y is a better choice and ought ** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. +** relationship is inverted and needs to be adjusted. The third rule +** was added because if X uses skip-scan less than Y it still might +** deserve a lower cost even if it is a proper subset of Y. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ @@ -4033,6 +4036,7 @@ static int whereLoopCheaperProperSubset( if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ return 0; /* X is not a subset of Y */ } + if( pY->nSkip > pX->nSkip ) return 0; if( pX->rRun >= pY->rRun ){ if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ @@ -4068,9 +4072,7 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; if( whereLoopCheaperProperSubset(p, pTemplate) ){ /* Adjust pTemplate cost downward so that it is cheaper than its - ** subset p. Except, do not adjust the cost estimate downward for - ** a loop that skips more columns. */ - if( pTemplate->nSkip>p->nSkip ) continue; + ** subset p. */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1)); pTemplate->rRun = p->rRun; From 937994aa6596a0a77504f06d86d11f30bdc82fb3 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 5 Nov 2014 14:19:05 +0000 Subject: [PATCH 28/71] Add a test case to check that the previous commit is effective. FossilOrigin-Name: 948d6e5d07bc14b6de32ec2144c716a5532f894c --- manifest | 14 ++++++------ manifest.uuid | 2 +- test/skipscan6.test | 55 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 8e0066d70e..c849d3cf1c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\swhereLoopCheaperProperSubset(X,Y)\sso\sthat\sit\sdoes\snot\sreport\strue\nif\sX\suses\sskip-scan\sless\sthan\sY,\ssince\sin\sthat\scase\sX\smight\ndeserve\sto\sbe\scheaper\seven\sif\sit\sis\sa\sproper\ssubset. -D 2014-11-05T13:13:13.983 +C Add\sa\stest\scase\sto\scheck\sthat\sthe\sprevious\scommit\sis\seffective. +D 2014-11-05T14:19:05.905 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -849,7 +849,7 @@ F test/skipscan1.test 7e15e1cc524524e7b2c4595ec85c75501d22f4ff F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5 F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2 -F test/skipscan6.test 3a891b45d6df266ced861a2ad9d03fca2bc7fcc5 +F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 F test/sort.test c4400e7533748f6bd7413851ff148645e82b9e2d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7974c0ed10ffdc960a43fed89845c2bed428958d -R 418c93fe7ac7140cffa87d5f3271cb48 -U drh -Z 68c42aaa0a73598a09ed4215a5cfd466 +P c106b755369c1f8546e897ecd2ac56fd09d6e885 +R 27944d6d7573adcf0b31a08e199961ff +U dan +Z 1a8729ffc04f45ef7b13c20540a14cbb diff --git a/manifest.uuid b/manifest.uuid index da46c6359a..911dbed051 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c106b755369c1f8546e897ecd2ac56fd09d6e885 \ No newline at end of file +948d6e5d07bc14b6de32ec2144c716a5532f894c \ No newline at end of file diff --git a/test/skipscan6.test b/test/skipscan6.test index 9eda9a66f3..026c4d7b00 100644 --- a/test/skipscan6.test +++ b/test/skipscan6.test @@ -141,5 +141,60 @@ do_execsql_test 2.2 { } {/INDEX good .bb=. AND aa=. AND dd>. AND dd<../} +# Create a table containing 100 rows. Column "a" contains a copy of the +# rowid value - sequentially increasing integers from 1 to 100. Column +# "b" contains the value of (a % 5). Columns "c" and "d" both contain +# constant values (i.e. the same for every row). +# +# Then create a second table t2. t2 is the same as t3 except for the +# order in which the indexes are created. +# +do_execsql_test 3.0 { + CREATE TABLE t3(a, b, c, d); + CREATE INDEX t3_ba ON t3(b, a, c); + CREATE INDEX t3_a ON t3(a); + + WITH d(a, b) AS ( + SELECT 1, 1 + UNION ALL + SELECT a+1, (a+1) % 5 FROM d WHERE a<100 + ) + INSERT INTO t3 SELECT a, b, 'c', 'd' FROM d; + + CREATE TABLE t2(a, b, c, d); + CREATE INDEX t2_a ON t2(a); + CREATE INDEX t2_ba ON t2(b, a, c); + INSERT INTO t2 SELECT * FROM t3; + + ANALYZE; + SELECT * FROM sqlite_stat1; +} { + t2 t2_ba {100 20 1 1} + t2 t2_a {100 1} + t3 t3_a {100 1} + t3 t3_ba {100 20 1 1} +} + +# Use index "t3_a", as (a=?) is expected to match only a single row. +# +do_eqp_test 3.1 { + SELECT * FROM t3 WHERE a = ? AND c = ? +} { + 0 0 0 {SEARCH TABLE t3 USING INDEX t3_a (a=?)} +} + +# The same query on table t2. This should use index "t2_a", for the +# same reason. At one point though, it was mistakenly using a skip-scan. +# +do_eqp_test 3.2 { + SELECT * FROM t2 WHERE a = ? AND c = ? +} { + 0 0 0 {SEARCH TABLE t2 USING INDEX t2_a (a=?)} +} + +finish_test + + + finish_test From 6b5631e02f2204da55742ec6e89b3633d36f51cb Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Nov 2014 15:57:39 +0000 Subject: [PATCH 29/71] Make sure that NULL results from OP_Column are fully and completely NULL and do not have the MEM_Ephem bit set. Fix for ticket [094d39a4c95ee4]. FossilOrigin-Name: 42705fd7d892c4fdfb95fbbb468c99569beece25 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/vdbe.c | 2 +- test/table.test | 18 +++++++++++++++++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index c849d3cf1c..29f44c63b9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\stest\scase\sto\scheck\sthat\sthe\sprevious\scommit\sis\seffective. -D 2014-11-05T14:19:05.905 +C Make\ssure\sthat\sNULL\sresults\sfrom\sOP_Column\sare\sfully\sand\scompletely\sNULL\nand\sdo\snot\shave\sthe\sMEM_Ephem\sbit\sset.\s\sFix\sfor\sticket\s[094d39a4c95ee4]. +D 2014-11-05T15:57:39.984 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 175a360c56e75ce4eb2b60704fd7c011b93926f5 +F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 F src/vdbeapi.c 900259bdd85cd66a9f210d8ec08147a9034593bd @@ -879,7 +879,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 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 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P c106b755369c1f8546e897ecd2ac56fd09d6e885 -R 27944d6d7573adcf0b31a08e199961ff -U dan -Z 1a8729ffc04f45ef7b13c20540a14cbb +P 948d6e5d07bc14b6de32ec2144c716a5532f894c +R 4628888308aa60120db393287d665a20 +U drh +Z e07070b00a71f6116b6f23e15e08fb5e diff --git a/manifest.uuid b/manifest.uuid index 911dbed051..8df21c81cd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -948d6e5d07bc14b6de32ec2144c716a5532f894c \ No newline at end of file +42705fd7d892c4fdfb95fbbb468c99569beece25 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 62470a743b..bf9b233a26 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2301,7 +2301,7 @@ case OP_Column: { pC->payloadSize = pC->szRow = avail = pReg->n; pC->aRow = (u8*)pReg->z; }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ diff --git a/test/table.test b/test/table.test index 656884ca73..69f105aa6c 100644 --- a/test/table.test +++ b/test/table.test @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # -# $Id: table.test,v 1.53 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -773,4 +772,21 @@ do_catchsql_test table-16.7 { INSERT INTO t16 DEFAULT VALUES; } {1 {unknown function: group_concat()}} +# Ticket [https://www.sqlite.org/src/info/094d39a4c95ee4abbc417f04214617675ba15c63] +# describes a assertion fault that occurs on a CREATE TABLE .. AS SELECT statement. +# the following test verifies that the problem has been fixed. +# +do_execsql_test table-17.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a TEXT); + INSERT INTO t1(a) VALUES(1),(2); + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(x TEXT, y TEXT); + INSERT INTO t2(x,y) VALUES(3,4); + DROP TABLE IF EXISTS t3; + CREATE TABLE t3 AS + SELECT a AS p, coalesce(y,a) AS q FROM t1 LEFT JOIN t2 ON a=x; + SELECT p, q, '|' FROM t3 ORDER BY p; +} {1 1 | 2 2 |} + finish_test From 6d3f91d040ae42394d7b1534cce8ead374cc0f7c Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 5 Nov 2014 19:26:12 +0000 Subject: [PATCH 30/71] Change the query planner to do a better job of estimating the number rows selected by a BETWEEN operator using STAT4 when both upper and lower bounds are contained within the same sample. FossilOrigin-Name: 2d36be5d9a1cdd4fd2d54fc4eeece32a81cbacc1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 34 +++++++++++++++++++++------------- test/analyze8.test | 8 ++++---- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 29f44c63b9..d1dcbe649d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sthat\sNULL\sresults\sfrom\sOP_Column\sare\sfully\sand\scompletely\sNULL\nand\sdo\snot\shave\sthe\sMEM_Ephem\sbit\sset.\s\sFix\sfor\sticket\s[094d39a4c95ee4]. -D 2014-11-05T15:57:39.984 +C Change\sthe\squery\splanner\sto\sdo\sa\sbetter\sjob\sof\sestimating\sthe\snumber\srows\nselected\sby\sa\sBETWEEN\soperator\susing\sSTAT4\swhen\sboth\supper\sand\slower\sbounds\nare\scontained\swithin\sthe\ssame\ssample. +D 2014-11-05T19:26:12.741 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 825c948066c7604a07d56e67958cdab210749016 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 240961041f35862ebcafd260587c79a1ab7347f8 +F src/where.c 2c2081c546c90227577c502765611555503ce3f7 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -321,7 +321,7 @@ F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213 F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f -F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88 +F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82 F test/analyze9.test 72795c8113604b5dcd47a1498a61d6d7fb5d041a F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 948d6e5d07bc14b6de32ec2144c716a5532f894c -R 4628888308aa60120db393287d665a20 +P 42705fd7d892c4fdfb95fbbb468c99569beece25 +R b31ea7cd782cb3cc21bda8e8c039f16c U drh -Z e07070b00a71f6116b6f23e15e08fb5e +Z 7c6a788d1b7b1ae57295ef90b3d9da88 diff --git a/manifest.uuid b/manifest.uuid index 8df21c81cd..64b0a08a4b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42705fd7d892c4fdfb95fbbb468c99569beece25 \ No newline at end of file +2d36be5d9a1cdd4fd2d54fc4eeece32a81cbacc1 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 34614e6bb3..92f783b2e9 100644 --- a/src/where.c +++ b/src/where.c @@ -1897,7 +1897,6 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ - #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Estimate the location of a particular key among all keys in an @@ -1906,9 +1905,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ ** aStat[0] Est. number of rows less than pVal ** aStat[1] Est. number of rows equal to pVal ** -** Return SQLITE_OK on success. +** Return the index of the sample that is the smallest sample that +** is greater than or equal to pRec. */ -static void whereKeyStats( +static int whereKeyStats( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ UnpackedRecord *pRec, /* Vector of values to consider */ @@ -1990,6 +1990,7 @@ static void whereKeyStats( } aStat[0] = iLower + iGap; } + return i; } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ @@ -2140,7 +2141,7 @@ static int whereRangeSkipScanEst( ** If either of the upper or lower bound is not present, then NULL is passed in ** place of the corresponding WhereTerm. ** -** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index +** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index ** column subject to the range constraint. Or, equivalently, the number of ** equality constraints optimized by the proposed index scan. For example, ** assuming index p is on t1(a, b), and the SQL query is: @@ -2156,7 +2157,7 @@ static int whereRangeSkipScanEst( ** ** When this function is called, *pnOut is set to the sqlite3LogEst() of the ** number of rows that the index scan is expected to visit without -** considering the range constraints. If nEq is 0, this is the number of +** considering the range constraints. If nEq is 0, then *pnOut is the number of ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) ** to account for the range constraints pLower and pUpper. ** @@ -2180,9 +2181,7 @@ static int whereRangeScanEst( Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; - if( p->nSample>0 - && nEqnSampleCol - ){ + if( p->nSample>0 && nEqnSampleCol ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; @@ -2198,15 +2197,19 @@ static int whereRangeScanEst( ** is not a simple variable or literal value), the lower bound of the ** range is $P. Due to a quirk in the way whereKeyStats() works, even ** if $L is available, whereKeyStats() is called for both ($P) and - ** ($P:$L) and the larger of the two returned values used. + ** ($P:$L) and the larger of the two returned values is used. ** ** Similarly, iUpper is to be set to the estimate of the number of rows ** less than the upper bound of the range query. Where the upper bound ** is either ($P) or ($P:$U). Again, even if $U is available, both values ** of iUpper are requested of whereKeyStats() and the smaller used. + ** + ** The number of rows between the two bounds is then just iUpper-iLower. */ - tRowcnt iLower; - tRowcnt iUpper; + tRowcnt iLower; /* Rows less than the lower bound */ + tRowcnt iUpper; /* Rows less than the upper bound */ + int iLwrIdx = -2; /* aSample[] for the lower bound */ + int iUprIdx = -1; /* aSample[] for the upper bound */ if( pRec ){ testcase( pRec->nField!=pBuilder->nRecValid ); @@ -2244,7 +2247,7 @@ static int whereRangeScanEst( rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 0, a); + iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; @@ -2259,7 +2262,7 @@ static int whereRangeScanEst( rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; - whereKeyStats(pParse, p, pRec, 1, a); + iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNewiLower ){ nNew = sqlite3LogEst(iUpper - iLower); + /* TUNING: If both iUpper and iLower are derived from the same + ** sample, then assume they are 4x more selective. This brings + ** the estimated selectivity more in line with what it would be + ** if estimated without the use of STAT3/4 tables. */ + if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } diff --git a/test/analyze8.test b/test/analyze8.test index 4384c39676..1079e68080 100644 --- a/test/analyze8.test +++ b/test/analyze8.test @@ -86,23 +86,23 @@ do_test 2.1 { # range. # # Test 3.2 is a little unstable. It depends on the planner estimating -# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN +# that (b BETWEEN 30 AND 34) will match more rows than (c BETWEEN # 800000 AND 900000). Which is a pretty close call (50 vs. 32), so # the planner could get it wrong with an unlucky set of samples. This # case happens to work, but others ("b BETWEEN 40 AND 44" for example) # will fail. # do_execsql_test 3.0 { - SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54; + SELECT count(*) FROM t1 WHERE b BETWEEN 30 AND 34; SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; } {50 376 32} do_test 3.1 { - eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000} + eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b? AND c Date: Wed, 5 Nov 2014 21:21:08 +0000 Subject: [PATCH 31/71] Fix harmless compiler warnings in the new balance_nonroot() routine. FossilOrigin-Name: 83a1e5db926b3a6d40f4a5cf9a8e6852b9bac9ac --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/btree.c | 19 ++++++++++++------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index d1dcbe649d..6994d5e8ec 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\squery\splanner\sto\sdo\sa\sbetter\sjob\sof\sestimating\sthe\snumber\srows\nselected\sby\sa\sBETWEEN\soperator\susing\sSTAT4\swhen\sboth\supper\sand\slower\sbounds\nare\scontained\swithin\sthe\ssame\ssample. -D 2014-11-05T19:26:12.741 +C Fix\sharmless\scompiler\swarnings\sin\sthe\snew\sbalance_nonroot()\sroutine. +D 2014-11-05T21:21:08.046 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,7 +172,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 11d1262110c2d459b68121833fa3ec6625b1d022 +F src/btree.c 4a126e2066076872ab6f37f9ad116eb5f651cd38 F src/btree.h 49b408be9c1cd41249076898e0673711071205d8 F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 42705fd7d892c4fdfb95fbbb468c99569beece25 -R b31ea7cd782cb3cc21bda8e8c039f16c +P 2d36be5d9a1cdd4fd2d54fc4eeece32a81cbacc1 +R e9a3ba77188e96b62213debbd39f0d21 U drh -Z 7c6a788d1b7b1ae57295ef90b3d9da88 +Z dda139af7d076df31a05d3458397d7d6 diff --git a/manifest.uuid b/manifest.uuid index 64b0a08a4b..82de0553f1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2d36be5d9a1cdd4fd2d54fc4eeece32a81cbacc1 \ No newline at end of file +83a1e5db926b3a6d40f4a5cf9a8e6852b9bac9ac \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index fe15c922ca..8b4a2a4f3b 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1297,8 +1297,8 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ int top; /* First byte of cell content area */ + int rc = SQLITE_OK; /* Integer return code */ int gap; /* First byte of gap between cell pointers and cell content */ - int rc; /* Integer return code */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); @@ -1328,13 +1328,13 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ testcase( gap+1==top ); testcase( gap==top ); if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){ - int rc = SQLITE_OK; int bDefrag = 0; u8 *pSpace = pageFindSlot(pPage, nByte, &rc, &bDefrag); if( rc ) return rc; if( bDefrag ) goto defragment_page; if( pSpace ){ - *pIdx = pSpace - data; + assert( pSpace>=data && (pSpace - data)<65536 ); + *pIdx = (int)(pSpace - data); return SQLITE_OK; } } @@ -6117,7 +6117,10 @@ static int pageFreeArray( if( pCell>=pStart && pCellaData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } pFree = pCell; szFree = sz; if( pFree+sz>pEnd ) return 0; @@ -6128,7 +6131,10 @@ static int pageFreeArray( nRet++; } } - if( pFree ) freeSpace(pPg, pFree - aData, szFree); + if( pFree ){ + assert( pFree>aData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } return nRet; } @@ -6192,7 +6198,7 @@ static void editPage( for(i=0; inOverflow; i++){ int iCell = (iOld + pPg->aiOvfl[i]) - iNew; if( iCell>=0 && iCellaCellIdx[iCell * 2]; + pCellptr = &pPg->aCellIdx[iCell * 2]; memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); nCell++; if( pageInsertArray( @@ -6881,7 +6887,6 @@ static int balance_nonroot( } for(i=0; i Date: Thu, 6 Nov 2014 03:55:10 +0000 Subject: [PATCH 32/71] Change the SQLITE_SCANSTAT_EST parameter so that it returns a double for the estimated number of output rows per loop, rather than a 64-bit integer. Revise the output format for the ".scanstats on" in the shell to make use of this new capability. FossilOrigin-Name: f9684000665ae7ef6f89c3773612b8286b8f545a --- manifest | 32 ++++++++++--------- manifest.uuid | 2 +- src/shell.c | 13 +++++--- src/sqlite.h.in | 12 ++++--- src/test1.c | 6 ++-- src/vdbe.h | 2 +- src/vdbeInt.h | 2 +- src/vdbeapi.c | 8 ++++- src/vdbeaux.c | 2 +- src/where.c | 6 +--- test/scanstatus.test | 76 ++++++++++++++++++++++---------------------- 11 files changed, 85 insertions(+), 76 deletions(-) diff --git a/manifest b/manifest index a8453434a2..75d37178fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixes\sto\sthe\sWindows\sVFS\sto\sallow\smemory\smapped\sfiles\sto\swork\swithout\sWAL\ssupport. -D 2014-11-05T21:34:56.096 +C Change\sthe\sSQLITE_SCANSTAT_EST\sparameter\sso\sthat\sit\sreturns\sa\sdouble\sfor\nthe\sestimated\snumber\sof\soutput\srows\sper\sloop,\srather\sthan\sa\s64-bit\sinteger.\nRevise\sthe\soutput\sformat\sfor\sthe\s".scanstats\son"\sin\sthe\sshell\sto\smake\suse\nof\sthis\snew\scapability. +D 2014-11-06T03:55:10.745 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,8 +228,8 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 5ad1eb4dfcd7a57e15825207a9bd559415bf34b1 -F src/sqlite.h.in 6e9af739d79f0bea2584b70fb1c54d3bb1a2eab6 +F src/shell.c 908ff96ef1551b28b940aaf4c886ba2681057209 +F src/sqlite.h.in e13a7b64efa8d6a591577e6a5281fb22783c0133 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -237,7 +237,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc F src/tclsqlite.c 7cdd4dd3c2a4183483feca260070d73d6e22cd47 -F src/test1.c 5890094c09691fe9564cf0f0d5b22d35b3218c47 +F src/test1.c ac7f3bad83ef4508d5efc85b32e86da48db8ed7e F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -290,10 +290,10 @@ F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df -F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 -F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 -F src/vdbeapi.c 900259bdd85cd66a9f210d8ec08147a9034593bd -F src/vdbeaux.c cf6b8152dd22155201d57c216e6266866b61da59 +F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 +F src/vdbeInt.h c32c1de25e3821a5b53d73abdb23ccc644ec5b63 +F src/vdbeapi.c 6a126fd8ed297ff0542bfbf7891b92977b5ed653 +F src/vdbeaux.c 9b0a251b6dfab349dd6c6efb40062eb7386b26f5 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 825c948066c7604a07d56e67958cdab210749016 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 2c2081c546c90227577c502765611555503ce3f7 +F src/where.c 3862a1173ae2716bde12f1ab3fb649f1d85b05c2 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 -F test/scanstatus.test 01afb2220f18ce85f9e338c20684f428d56e5c01 +F test/scanstatus.test a6dd739bc4d9638e8f5c2493b518057f2b681655 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1211,8 +1211,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 83a1e5db926b3a6d40f4a5cf9a8e6852b9bac9ac 6fc4ead26d19b9348bbda34c3053ae1e066abc32 -R 3ad47b2ac5693ba63ff5c591cf540d89 -T +closed 6fc4ead26d19b9348bbda34c3053ae1e066abc32 +P 272fddc14cc322655eeba670bc0f9fc30e5a804c +R c0f850c2227a7a137fbc73d5c1c5136e +T *branch * scanstatus +T *sym-scanstatus * +T -sym-trunk * U drh -Z ee3b32335a4c8630acaf81919b28b64e +Z f39cd1607e4aacbb491c044bd0bb317e diff --git a/manifest.uuid b/manifest.uuid index b558f09274..d125168b7d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -272fddc14cc322655eeba670bc0f9fc30e5a804c \ No newline at end of file +f9684000665ae7ef6f89c3773612b8286b8f545a \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 3423bb0143..4dd0ffa1a1 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1195,21 +1195,24 @@ static void display_scanstats( ){ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int i; + double rEstLoop = 1.0; fprintf(pArg->out, "-------- scanstats --------\n"); for(i=0; 1; i++){ sqlite3_stmt *p = pArg->pStmt; - sqlite3_int64 nEst, nLoop, nVisit; + sqlite3_int64 nLoop, nVisit; + double rEst; const char *zExplain; if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ break; } sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&nEst); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - fprintf(pArg->out, "Loop %d: \"%s\"\n", i, zExplain); - fprintf(pArg->out, " nLoop=%-8lld nVisit=%-8lld nEst=%-8lld\n", - nLoop, nVisit, nEst + fprintf(pArg->out, "Loop %2d: \"%s\"\n", i, zExplain); + rEstLoop *= rEst; + fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", + nLoop, nVisit, (sqlite3_int64)rEstLoop, rEst ); } #else diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 44f7800ca2..c309dc1c5b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7440,13 +7440,15 @@ int sqlite3_vtab_on_conflict(sqlite3 *); ** ** [[SQLITE_SCANSTAT_NVISIT]]

SQLITE_SCANSTAT_NVISIT
**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the -** total number of rows visited by the X-th loop.
+** total number of rows examined by all iterations of the X-th loop. ** ** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
-**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the -** query planner's estimate for the number of rows visited for each -** iteration of the X-th loop. If the query planner's estimate was accurate, -** then this value should be approximately NVISIT/NLOOP. +**
^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 the first N-1 loops will approximate +** the NLOOP value for the N-th loop. ** ** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
**
^The "const char *" variable pointed to by the T parameter will be set to diff --git a/src/test1.c b/src/test1.c index 5e526b3013..fcc1a23de1 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2318,7 +2318,7 @@ static int test_stmt_scanstatus( const char *zExplain; sqlite3_int64 nLoop; sqlite3_int64 nVisit; - sqlite3_int64 nEst; + double rEst; int res; if( objc!=3 ){ @@ -2336,9 +2336,9 @@ static int test_stmt_scanstatus( sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); - sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&nEst); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nEst)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst)); sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); diff --git a/src/vdbe.h b/src/vdbe.h index 1b9ad8b6bf..b715241b41 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -283,7 +283,7 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS -void sqlite3VdbeScanStatus(Vdbe*, int, int, int, i64, const char*); +void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); #else # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 29117dd064..a42ca3dffc 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -302,7 +302,7 @@ struct ScanStatus { int addrExplain; /* OP_Explain for loop */ int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ - i64 nEst; /* Estimated rows per loop */ + LogEst nEst; /* Estimated output rows per loop */ char *zName; /* Name of table or index */ }; diff --git a/src/vdbeapi.c b/src/vdbeapi.c index d472004590..d907afee00 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1500,7 +1500,13 @@ int sqlite3_stmt_scanstatus( break; } case SQLITE_SCANSTAT_EST: { - *(sqlite3_int64*)pOut = pScan->nEst; + 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: { diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7cf996ce5c..d8ee5c8e8c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -606,7 +606,7 @@ void sqlite3VdbeScanStatus( int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ - i64 nEst, /* Estimated number of rows */ + LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ int nByte = (p->nScan+1) * sizeof(ScanStatus); diff --git a/src/where.c b/src/where.c index 92f783b2e9..c3641c7cc7 100644 --- a/src/where.c +++ b/src/where.c @@ -2946,18 +2946,14 @@ static void addScanStatus( int addrExplain /* Address of OP_Explain (or 0) */ ){ const char *zObj = 0; - i64 nEst = 1; WhereLoop *pLoop = pLvl->pWLoop; if( (pLoop->wsFlags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ zObj = pLoop->u.btree.pIndex->zName; }else{ zObj = pSrclist->a[pLvl->iFrom].zName; } - if( pLoop->nOut>=10 ){ - nEst = sqlite3LogEstToInt(pLoop->nOut); - } sqlite3VdbeScanStatus( - v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj ); } #else diff --git a/test/scanstatus.test b/test/scanstatus.test index 9b34506e91..7713bae5fc 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -45,8 +45,8 @@ proc do_scanstatus_test {tn res} { do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.2 { - nLoop 1 nVisit 2 nEst 1048576 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 1048576 zName t2 zExplain {SCAN TABLE t2} + nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN TABLE t2} } do_execsql_test 1.3 { @@ -54,8 +54,8 @@ do_execsql_test 1.3 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.4 { - nLoop 1 nVisit 2 nEst 2 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 3 zName t2 zExplain {SCAN TABLE t2} + nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN TABLE t2} } do_execsql_test 1.5 { ANALYZE } @@ -63,9 +63,9 @@ do_execsql_test 1.6 { SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; } 4 do_scanstatus_test 1.7 { - nLoop 1 nVisit 2 nEst 2 zName t2 zExplain + nLoop 1 nVisit 2 nEst 2.0 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 2 nVisit 4 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} } do_execsql_test 1.8 { @@ -73,9 +73,9 @@ do_execsql_test 1.8 { } 4 do_scanstatus_test 1.9 { - nLoop 2 nVisit 4 nEst 2 zName t2 zExplain + nLoop 2 nVisit 4 nEst 2.0 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 4 nVisit 8 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} } do_test 1.9 { @@ -83,9 +83,9 @@ do_test 1.9 { } {} do_scanstatus_test 1.10 { - nLoop 0 nVisit 0 nEst 2 zName t2 zExplain + nLoop 0 nVisit 0 nEst 2.0 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 0 nVisit 0 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} } #------------------------------------------------------------------------- @@ -104,7 +104,7 @@ do_execsql_test 2.1 { } {2 two} do_scanstatus_test 2.2 { - nLoop 1 nVisit 1 nEst 1 zName x1 + nLoop 1 nVisit 1 nEst 1.0 zName x1 zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)} } @@ -112,7 +112,7 @@ do_execsql_test 2.3.1 { SELECT * FROM x1 WHERE j='two' } {2 two} do_scanstatus_test 2.3.2 { - nLoop 1 nVisit 1 nEst 10 zName x1j + nLoop 1 nVisit 1 nEst 10.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} } @@ -120,7 +120,7 @@ do_execsql_test 2.4.1 { SELECT * FROM x1 WHERE j<'two' } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { - nLoop 1 nVisit 3 nEst 262144 zName x1j + nLoop 1 nVisit 3 nEst 262144.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j='two' } {2 two} do_scanstatus_test 2.5.2 { - nLoop 1 nVisit 1 nEst 262144 zName x1j + nLoop 1 nVisit 1 nEst 262144.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>?)} } @@ -136,7 +136,7 @@ do_execsql_test 2.6.1 { SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two' } {3 three 2 two} do_scanstatus_test 2.6.2 { - nLoop 1 nVisit 2 nEst 16384 zName x1j + nLoop 1 nVisit 2 nEst 16384.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j? AND j? AND a? AND b? AND b? AND a Date: Thu, 6 Nov 2014 04:42:20 +0000 Subject: [PATCH 33/71] Add the SQLITE_SCANSTAT_SELECTID metric. Use it to improve the ".stmtscan on" output in the shell. FossilOrigin-Name: 64ad5761a841f71530d41565b9fbe9d19c2d6aff --- manifest | 21 +++++++++------------ manifest.uuid | 2 +- src/shell.c | 22 +++++++++++++++++----- src/sqlite.h.in | 12 ++++++++++-- src/vdbeInt.h | 1 + src/vdbeapi.c | 8 ++++++++ 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 75d37178fb..25d04501fe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sSQLITE_SCANSTAT_EST\sparameter\sso\sthat\sit\sreturns\sa\sdouble\sfor\nthe\sestimated\snumber\sof\soutput\srows\sper\sloop,\srather\sthan\sa\s64-bit\sinteger.\nRevise\sthe\soutput\sformat\sfor\sthe\s".scanstats\son"\sin\sthe\sshell\sto\smake\suse\nof\sthis\snew\scapability. -D 2014-11-06T03:55:10.745 +C Add\sthe\sSQLITE_SCANSTAT_SELECTID\smetric.\s\sUse\sit\sto\simprove\sthe\n".stmtscan\son"\soutput\sin\sthe\sshell. +D 2014-11-06T04:42:20.310 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,8 +228,8 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 908ff96ef1551b28b940aaf4c886ba2681057209 -F src/sqlite.h.in e13a7b64efa8d6a591577e6a5281fb22783c0133 +F src/shell.c 74768f90bd0f8880937d52e2eb756655dba0015a +F src/sqlite.h.in 087d30a4c7ec7ae19bcaa03a9db9d6ee7a73b0b3 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -291,8 +291,8 @@ F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 -F src/vdbeInt.h c32c1de25e3821a5b53d73abdb23ccc644ec5b63 -F src/vdbeapi.c 6a126fd8ed297ff0542bfbf7891b92977b5ed653 +F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 +F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 F src/vdbeaux.c 9b0a251b6dfab349dd6c6efb40062eb7386b26f5 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f @@ -1211,10 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 272fddc14cc322655eeba670bc0f9fc30e5a804c -R c0f850c2227a7a137fbc73d5c1c5136e -T *branch * scanstatus -T *sym-scanstatus * -T -sym-trunk * +P f9684000665ae7ef6f89c3773612b8286b8f545a +R 34f47ade33b56f41a439ae08635a112b U drh -Z f39cd1607e4aacbb491c044bd0bb317e +Z 216d325be8d3eddf6fd433a7ff464585 diff --git a/manifest.uuid b/manifest.uuid index d125168b7d..13ff805ffa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f9684000665ae7ef6f89c3773612b8286b8f545a \ No newline at end of file +64ad5761a841f71530d41565b9fbe9d19c2d6aff \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 4dd0ffa1a1..b6ae6e15a6 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1195,12 +1195,14 @@ static void display_scanstats( ){ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int i; - double rEstLoop = 1.0; + double *arEstLoop = 0; + int nEstLoop = 0; fprintf(pArg->out, "-------- scanstats --------\n"); for(i=0; 1; i++){ sqlite3_stmt *p = pArg->pStmt; sqlite3_int64 nLoop, nVisit; - double rEst; + double rEst, rLoop; + int iSid; const char *zExplain; if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ break; @@ -1208,13 +1210,23 @@ static void display_scanstats( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); + if( iSid>=nEstLoop ){ + arEstLoop = sqlite3_realloc(arEstLoop, sizeof(arEstLoop[0])*(iSid+1) ); + while( nEstLoop<=iSid ) arEstLoop[nEstLoop++] = 1.0; + } + if( iSid>=0 ){ + arEstLoop[iSid] *= rEst; + rLoop = arEstLoop[iSid]; + }else{ + rLoop = rEst; + } fprintf(pArg->out, "Loop %2d: \"%s\"\n", i, zExplain); - rEstLoop *= rEst; fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", - nLoop, nVisit, (sqlite3_int64)rEstLoop, rEst + nLoop, nVisit, (sqlite3_int64)rLoop, rEst ); } + sqlite3_free(arEstLoop); #else fprintf(pArg->out, "-------- scanstats --------\n"); fprintf(pArg->out, diff --git a/src/sqlite.h.in b/src/sqlite.h.in index c309dc1c5b..00bf5e2d98 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7447,8 +7447,8 @@ int sqlite3_vtab_on_conflict(sqlite3 *); ** 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 the first N-1 loops will approximate -** the NLOOP value for the N-th loop. +** product of this value for all prior loops with the same SELECTID will +** be the NLOOP value for the current loop. ** ** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
**
^The "const char *" variable pointed to by the T parameter will be set to @@ -7459,6 +7459,13 @@ int sqlite3_vtab_on_conflict(sqlite3 *); **
^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]]
SQLITE_SCANSTAT_SELECT
+**
^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. ** */ #define SQLITE_SCANSTAT_NLOOP 0 @@ -7466,6 +7473,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *); #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 diff --git a/src/vdbeInt.h b/src/vdbeInt.h index a42ca3dffc..1a7297e946 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -302,6 +302,7 @@ struct ScanStatus { int addrExplain; /* OP_Explain for loop */ int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ + int iSelectID; /* The "Select-ID" for this loop */ LogEst nEst; /* Estimated output rows per loop */ char *zName; /* Name of table or index */ }; diff --git a/src/vdbeapi.c b/src/vdbeapi.c index d907afee00..5744c28632 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1521,6 +1521,14 @@ int sqlite3_stmt_scanstatus( } break; } + case SQLITE_SCANSTAT_SELECTID: { + if( pScan->addrExplain ){ + *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; + }else{ + *(int*)pOut = -1; + } + break; + } default: { return 1; } From 42f30bce1158008097d271fd06c31398cf631aea Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Nov 2014 12:08:21 +0000 Subject: [PATCH 34/71] Changes the formatting of ".scanstats on" in the shell so that the stats for subqueries are grouped together and occur after the main query. FossilOrigin-Name: eacbbd8849db9b023eff15ef1cb42ec941299433 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c | 54 +++++++++++++++++++++++---------------------------- 3 files changed, 31 insertions(+), 37 deletions(-) diff --git a/manifest b/manifest index 25d04501fe..af1ed3e99c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_SCANSTAT_SELECTID\smetric.\s\sUse\sit\sto\simprove\sthe\n".stmtscan\son"\soutput\sin\sthe\sshell. -D 2014-11-06T04:42:20.310 +C Changes\sthe\sformatting\sof\s".scanstats\son"\sin\sthe\sshell\sso\sthat\sthe\sstats\sfor\nsubqueries\sare\sgrouped\stogether\sand\soccur\safter\sthe\smain\squery. +D 2014-11-06T12:08:21.237 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,7 +228,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 74768f90bd0f8880937d52e2eb756655dba0015a +F src/shell.c 22c7c693f322091b26e9333a8fa50c56e4aba667 F src/sqlite.h.in 087d30a4c7ec7ae19bcaa03a9db9d6ee7a73b0b3 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f9684000665ae7ef6f89c3773612b8286b8f545a -R 34f47ade33b56f41a439ae08635a112b +P 64ad5761a841f71530d41565b9fbe9d19c2d6aff +R 301cd68395834791ac0b2ebb68f39e69 U drh -Z 216d325be8d3eddf6fd433a7ff464585 +Z c6dcae9ced19f9079c51a47717359be1 diff --git a/manifest.uuid b/manifest.uuid index 13ff805ffa..6061834c99 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -64ad5761a841f71530d41565b9fbe9d19c2d6aff \ No newline at end of file +eacbbd8849db9b023eff15ef1cb42ec941299433 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index b6ae6e15a6..3505e59d4b 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1194,39 +1194,33 @@ static void display_scanstats( ShellState *pArg /* Pointer to ShellState */ ){ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - int i; - double *arEstLoop = 0; - int nEstLoop = 0; + int i, k, n = 1; fprintf(pArg->out, "-------- scanstats --------\n"); - for(i=0; 1; i++){ - sqlite3_stmt *p = pArg->pStmt; - sqlite3_int64 nLoop, nVisit; - double rEst, rLoop; - int iSid; - const char *zExplain; - if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ - break; + for(k=0; n>0; k++){ + double rEstLoop = 1.0; + for(i=n=0; 1; i++){ + sqlite3_stmt *p = pArg->pStmt; + sqlite3_int64 nLoop, nVisit; + double rEst; + int iSid; + const char *zExplain; + if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ + break; + } + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); + if( iSid!=k ) continue; + if( n==0 && k>0 ) fprintf(pArg->out, "-------- subquery %d --------\n", k); + n++; + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); + fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain); + rEstLoop *= rEst; + fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", + nLoop, nVisit, (sqlite3_int64)rEstLoop, rEst + ); } - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); - if( iSid>=nEstLoop ){ - arEstLoop = sqlite3_realloc(arEstLoop, sizeof(arEstLoop[0])*(iSid+1) ); - while( nEstLoop<=iSid ) arEstLoop[nEstLoop++] = 1.0; - } - if( iSid>=0 ){ - arEstLoop[iSid] *= rEst; - rLoop = arEstLoop[iSid]; - }else{ - rLoop = rEst; - } - fprintf(pArg->out, "Loop %2d: \"%s\"\n", i, zExplain); - fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", - nLoop, nVisit, (sqlite3_int64)rLoop, rEst - ); } - sqlite3_free(arEstLoop); #else fprintf(pArg->out, "-------- scanstats --------\n"); fprintf(pArg->out, From 179bac3a14924c42656efdfddc5bbfd8e8a2be32 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Nov 2014 12:17:24 +0000 Subject: [PATCH 35/71] On the ".scanstats on" output in the shell, initialize the estimated count for the first loop of each subquery to the actual loop count. FossilOrigin-Name: d1c51c8455d5ce972a77720c2d56228646ced27c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c | 5 ++++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index af1ed3e99c..05212e91e7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\sthe\sformatting\sof\s".scanstats\son"\sin\sthe\sshell\sso\sthat\sthe\sstats\sfor\nsubqueries\sare\sgrouped\stogether\sand\soccur\safter\sthe\smain\squery. -D 2014-11-06T12:08:21.237 +C On\sthe\s".scanstats\son"\soutput\sin\sthe\sshell,\sinitialize\sthe\sestimated\scount\sfor\nthe\sfirst\sloop\sof\seach\ssubquery\sto\sthe\sactual\sloop\scount. +D 2014-11-06T12:17:24.789 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,7 +228,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 22c7c693f322091b26e9333a8fa50c56e4aba667 +F src/shell.c 64a941c079837fd1a0d920273832e6275b777402 F src/sqlite.h.in 087d30a4c7ec7ae19bcaa03a9db9d6ee7a73b0b3 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 64ad5761a841f71530d41565b9fbe9d19c2d6aff -R 301cd68395834791ac0b2ebb68f39e69 +P eacbbd8849db9b023eff15ef1cb42ec941299433 +R c65acc2e5374aae8ca471af05c87c9aa U drh -Z c6dcae9ced19f9079c51a47717359be1 +Z b18ed09265a53348fca40701c374436f diff --git a/manifest.uuid b/manifest.uuid index 6061834c99..fc422bc396 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eacbbd8849db9b023eff15ef1cb42ec941299433 \ No newline at end of file +d1c51c8455d5ce972a77720c2d56228646ced27c \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 3505e59d4b..ca49e00a69 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1209,7 +1209,10 @@ static void display_scanstats( } sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); if( iSid!=k ) continue; - if( n==0 && k>0 ) fprintf(pArg->out, "-------- subquery %d --------\n", k); + if( n==0 ){ + rEstLoop = (double)nLoop; + if( k>0 ) fprintf(pArg->out, "-------- subquery %d --------\n", k); + } n++; sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); From 15f23c2cf0da0ecd46f588a156af251fb58c3234 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Nov 2014 12:46:16 +0000 Subject: [PATCH 36/71] Further improvements to the ".scanstats on" display in the shell. Be sure to show the results of all subqueries even if there are gaps in the SELECTID values. Add ".scanstats" to the ".help" output. FossilOrigin-Name: ee922682bb7235dbcd23a22fcfdfa188f6d3228a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 05212e91e7..3bbd6d3bd3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C On\sthe\s".scanstats\son"\soutput\sin\sthe\sshell,\sinitialize\sthe\sestimated\scount\sfor\nthe\sfirst\sloop\sof\seach\ssubquery\sto\sthe\sactual\sloop\scount. -D 2014-11-06T12:17:24.789 +C Further\simprovements\sto\sthe\s".scanstats\son"\sdisplay\sin\sthe\sshell.\s\sBe\ssure\nto\sshow\sthe\sresults\sof\sall\ssubqueries\seven\sif\sthere\sare\sgaps\sin\sthe\s\nSELECTID\svalues.\s\sAdd\s".scanstats"\sto\sthe\s".help"\soutput. +D 2014-11-06T12:46:16.708 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,7 +228,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 64a941c079837fd1a0d920273832e6275b777402 +F src/shell.c 48fe276aada42a15722aee2584e6321345ed4609 F src/sqlite.h.in 087d30a4c7ec7ae19bcaa03a9db9d6ee7a73b0b3 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P eacbbd8849db9b023eff15ef1cb42ec941299433 -R c65acc2e5374aae8ca471af05c87c9aa +P d1c51c8455d5ce972a77720c2d56228646ced27c +R 1f66f00948a1acda590c099646f9e3d3 U drh -Z b18ed09265a53348fca40701c374436f +Z 2bc412ec02d784f50574dd160207db0a diff --git a/manifest.uuid b/manifest.uuid index fc422bc396..5ac436c534 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d1c51c8455d5ce972a77720c2d56228646ced27c \ No newline at end of file +ee922682bb7235dbcd23a22fcfdfa188f6d3228a \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index ca49e00a69..915b69263b 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1194,9 +1194,10 @@ static void display_scanstats( ShellState *pArg /* Pointer to ShellState */ ){ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - int i, k, n = 1; + int i, k, n, mx; fprintf(pArg->out, "-------- scanstats --------\n"); - for(k=0; n>0; k++){ + mx = 0; + for(k=0; k<=mx; k++){ double rEstLoop = 1.0; for(i=n=0; 1; i++){ sqlite3_stmt *p = pArg->pStmt; @@ -1208,10 +1209,11 @@ static void display_scanstats( break; } sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); + if( iSid>mx ) mx = iSid; if( iSid!=k ) continue; if( n==0 ){ rEstLoop = (double)nLoop; - if( k>0 ) fprintf(pArg->out, "-------- subquery %d --------\n", k); + if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k); } n++; sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); @@ -1224,14 +1226,8 @@ static void display_scanstats( ); } } -#else - fprintf(pArg->out, "-------- scanstats --------\n"); - fprintf(pArg->out, - "sqlite3_stmt_scanstatus() unavailable - " - "rebuild with SQLITE_ENABLE_STMT_SCANSTATUS\n" - ); -#endif fprintf(pArg->out, "---------------------------\n"); +#endif } /* @@ -1687,6 +1683,7 @@ static char zHelp[] = ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" + ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" @@ -3072,6 +3069,9 @@ static int do_meta_command(char *zLine, ShellState *p){ if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ if( nArg==2 ){ p->scanstatsOn = booleanValue(azArg[1]); +#ifndef SQLITE_ENABLE_STMT_SCANSTATUS + fprintf(stderr, "Warning: .scanstats not available in this build.\n"); +#endif }else{ fprintf(stderr, "Usage: .scanstats on|off\n"); rc = 1; From 8790b6e860fb5c9dacc3ddc1ecb27b384dd71c2a Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Nov 2014 01:43:56 +0000 Subject: [PATCH 37/71] Update documentation on sqlite3_config() and add corresponding evidence marks. FossilOrigin-Name: 360c8ca11c3315c8e08c7c52ff5468e3f723e562 --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/main.c | 32 ++++++++++++++++++++++---------- src/sqlite.h.in | 10 ++++++---- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/manifest b/manifest index 277b0baf4c..2ad90a7f0d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Added\sSQLITE_SCANSTAT_SELECTID.\s\sChange\sthe\svalue\sreturned\sby\nSQLITE_SCANSTAT_EST\sfrom\ssqlite3_int64\sto\sdouble.\s\sEnhanced\sthe\sformatting\nand\sdisplay\sof\sscan\sstatistics\susing\sthe\s".scanstats\son"\scommand\sin\sthe\nshell. -D 2014-11-06T14:43:53.299 +C Update\sdocumentation\son\ssqlite3_config()\sand\sadd\scorresponding\sevidence\smarks. +D 2014-11-07T01:43:56.762 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c 42f857be3cef3e1f9752d8e46d61345f80932396 +F src/main.c f88ed28716cbbada0f3d81479e6d43823b553de6 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 48fe276aada42a15722aee2584e6321345ed4609 -F src/sqlite.h.in 087d30a4c7ec7ae19bcaa03a9db9d6ee7a73b0b3 +F src/sqlite.h.in 83e34312bc974a99f03e1b040854c18145d7b662 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -1211,8 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 272fddc14cc322655eeba670bc0f9fc30e5a804c ee922682bb7235dbcd23a22fcfdfa188f6d3228a -R 1f66f00948a1acda590c099646f9e3d3 -T +closed ee922682bb7235dbcd23a22fcfdfa188f6d3228a +P 20c7614addb8494cd7f40263a50fa6f428cce1c7 +R ccc709fd5070dead531e2a6ad6b5aa29 U drh -Z 1da4b43998d0836d48029478818e14c6 +Z 3b414dc01fd5a3ebe6b3ed14cc9e0f06 diff --git a/manifest.uuid b/manifest.uuid index 1e9e58656e..01580f60c0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -20c7614addb8494cd7f40263a50fa6f428cce1c7 \ No newline at end of file +360c8ca11c3315c8e08c7c52ff5468e3f723e562 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 4c33bbde9d..ae3753c139 100644 --- a/src/main.c +++ b/src/main.c @@ -457,6 +457,9 @@ int sqlite3_config(int op, ...){ break; } +/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only +** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or +** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) case SQLITE_CONFIG_HEAP: { /* EVIDENCE-OF: R-19854-42126 There are three arguments to @@ -474,17 +477,19 @@ int sqlite3_config(int op, ...){ } if( sqlite3GlobalConfig.pHeap==0 ){ - /* If the heap pointer is NULL, then restore the malloc implementation - ** back to NULL pointers too. This will cause the malloc to go - ** back to its default implementation when sqlite3_initialize() is - ** run. + /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) + ** is NULL, then SQLite reverts to using its default memory allocator + ** (the system malloc() implementation), undoing any prior invocation of + ** SQLITE_CONFIG_MALLOC. + ** + ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to + ** revert to its default implementation when sqlite3_initialize() is run */ memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); }else{ - /* The heap pointer is not NULL, then install one of the - ** mem5.c/mem3.c methods. The enclosing #if guarantees at - ** least one of these methods is currently enabled. - */ + /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the + ** alternative memory allocator is engaged to handle all of SQLites + ** memory allocation needs. */ #ifdef SQLITE_ENABLE_MEMSYS3 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); #endif @@ -557,7 +562,13 @@ int sqlite3_config(int op, ...){ sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); /* EVIDENCE-OF: R-53367-43190 If either argument to this option is - ** negative, then that argument is changed to its compile-time default. */ + ** negative, then that argument is changed to its compile-time default. + ** + ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be + ** silently truncated if necessary so that it does not exceed the + ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE + ** compile-time option. + */ if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; @@ -2389,7 +2400,8 @@ int sqlite3ParseUri( assert( *pzErrMsg==0 ); - if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) + if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ + || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 00bf5e2d98..192280e726 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1582,14 +1582,16 @@ struct sqlite3_mem_methods { **
^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs ** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. +** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled +** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns +** [SQLITE_ERROR] if invoked otherwise. ** ^There are three arguments to SQLITE_CONFIG_HEAP: ** An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the -** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or -** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory +** memory pointer is not NULL then the alternative memory ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte ** boundary or subsequent behavior of SQLite will be undefined. @@ -1719,8 +1721,8 @@ struct sqlite3_mem_methods { ** ^The default setting can be overridden by each database connection using ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size -** cannot be changed at run-time. Nor may the maximum allowed mmap size -** exceed the compile-time maximum mmap size set by the +** will be silently truncated if necessary so that it does not exceed the +** compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. From 6137138ded9c5ca02d65d62d0ec4f3ff7cde05d2 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Nov 2014 11:39:16 +0000 Subject: [PATCH 38/71] Fix typo in sqlite3.h reported on the mailing list. FossilOrigin-Name: 402703212a8488f8b571ce170b3b6c7374bd7daa --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 2ad90a7f0d..b80e3b8250 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sdocumentation\son\ssqlite3_config()\sand\sadd\scorresponding\sevidence\smarks. -D 2014-11-07T01:43:56.762 +C Fix\stypo\sin\ssqlite3.h\sreported\son\sthe\smailing\slist. +D 2014-11-07T11:39:16.680 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -229,7 +229,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 48fe276aada42a15722aee2584e6321345ed4609 -F src/sqlite.h.in 83e34312bc974a99f03e1b040854c18145d7b662 +F src/sqlite.h.in f433227d7f619887a1064913fa66cefa3da4349a F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 20c7614addb8494cd7f40263a50fa6f428cce1c7 -R ccc709fd5070dead531e2a6ad6b5aa29 +P 360c8ca11c3315c8e08c7c52ff5468e3f723e562 +R 367fba2464fa0866db1d5cae2a24beee U drh -Z 3b414dc01fd5a3ebe6b3ed14cc9e0f06 +Z 3885b799624859bdb0af87865d5681ed diff --git a/manifest.uuid b/manifest.uuid index 01580f60c0..185fd7e51d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -360c8ca11c3315c8e08c7c52ff5468e3f723e562 \ No newline at end of file +402703212a8488f8b571ce170b3b6c7374bd7daa \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 192280e726..fc741b7291 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -52,7 +52,7 @@ extern "C" { /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications -** should not use deprecated interfaces - they are support for backwards +** should not use deprecated interfaces - they are supported for backwards ** compatibility only. Application writers should be aware that ** experimental interfaces are subject to change in point releases. ** From 86a11b8a6a671c1f0d55c7adb47994f2cec37f01 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Nov 2014 13:24:29 +0000 Subject: [PATCH 39/71] Fix harmless typos in comments. FossilOrigin-Name: 94c564da4c2cf5dffe58fdf7a180e9ba4cc3de69 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/date.c | 8 ++++---- src/global.c | 4 ++-- src/vacuum.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index b80e3b8250..ace0366e33 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypo\sin\ssqlite3.h\sreported\son\sthe\smailing\slist. -D 2014-11-07T11:39:16.680 +C Fix\sharmless\stypos\sin\scomments. +D 2014-11-07T13:24:29.246 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -179,13 +179,13 @@ F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 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/expr.c 0391a657df4959eaf2a2fd7d77de5ebe750686ee F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee -F src/global.c a50ad0b9ee328107a65aa8f5f3cd34905e74745c +F src/global.c 6ded36dda9466fc1c9a3c5492ded81d79bf3977d F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 @@ -288,7 +288,7 @@ F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 -F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a +F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 360c8ca11c3315c8e08c7c52ff5468e3f723e562 -R 367fba2464fa0866db1d5cae2a24beee +P 402703212a8488f8b571ce170b3b6c7374bd7daa +R 9f78be6a67e175be94522748bee570f6 U drh -Z 3885b799624859bdb0af87865d5681ed +Z 1fff294369c9fe8b2c9ed9357ff2fdd6 diff --git a/manifest.uuid b/manifest.uuid index 185fd7e51d..3f84a89f53 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -402703212a8488f8b571ce170b3b6c7374bd7daa \ No newline at end of file +94c564da4c2cf5dffe58fdf7a180e9ba4cc3de69 \ No newline at end of file diff --git a/src/date.c b/src/date.c index 11b04ea004..10d9006263 100644 --- a/src/date.c +++ b/src/date.c @@ -16,7 +16,7 @@ ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** SQLite processes all times and dates as Julian Day numbers. The +** SQLite processes all times and dates as julian day numbers. The ** dates and times are stored as the number of days since noon ** in Greenwich on November 24, 4714 B.C. according to the Gregorian ** calendar system. @@ -31,7 +31,7 @@ ** ** The Gregorian calendar system is used for all dates and times, ** even those that predate the Gregorian calendar. Historians usually -** use the Julian calendar for dates prior to 1582-10-15 and for some +** use the julian calendar for dates prior to 1582-10-15 and for some ** dates afterwards, depending on locale. Beware of this difference. ** ** The conversion algorithms are implemented based on descriptions @@ -304,7 +304,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ } /* -** Attempt to parse the given string into a Julian Day Number. Return +** Attempt to parse the given string into a julian day number. Return ** the number of errors. ** ** The following are acceptable forms for the input string: @@ -875,7 +875,7 @@ static void dateFunc( ** %f ** fractional seconds SS.SSS ** %H hour 00-24 ** %j day of year 000-366 -** %J ** Julian day number +** %J ** julian day number ** %m month 01-12 ** %M minute 00-59 ** %s seconds since 1970-01-01 diff --git a/src/global.c b/src/global.c index b5323e8df6..4bc8edb3bc 100644 --- a/src/global.c +++ b/src/global.c @@ -237,8 +237,8 @@ const Token sqlite3IntTokens[] = { ** ** IMPORTANT: Changing the pending byte to any value other than ** 0x40000000 results in an incompatible database file format! -** Changing the pending byte during operating results in undefined -** and dileterious behavior. +** Changing the pending byte during operation will result in undefined +** and incorrect behavior. */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; diff --git a/src/vacuum.c b/src/vacuum.c index 4d0c0976a1..9df8e08b22 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -94,7 +94,7 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ ** overwriting the database with the vacuumed content. ** ** Only 1x temporary space and only 1x writes would be required if -** the copy of step (3) were replace by deleting the original database +** the copy of step (3) were replaced by deleting the original database ** and renaming the transient database as the original. But that will ** not work if other processes are attached to the original database. ** And a power loss in between deleting the original and renaming the From 9a06d30bb5266c008ad3a2493fecf5f65c36d56a Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Nov 2014 13:52:44 +0000 Subject: [PATCH 40/71] In the ".scanstats on" output from the shell, round the estRows value to the nearest integer, rather than rounding toward zero. FossilOrigin-Name: 5700508535c35ac6b158b527e1d47e529e8e28ab --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index ace0366e33..b3d774824c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\stypos\sin\scomments. -D 2014-11-07T13:24:29.246 +C In\sthe\s".scanstats\son"\soutput\sfrom\sthe\sshell,\sround\sthe\sestRows\svalue\sto\nthe\snearest\sinteger,\srather\sthan\srounding\stoward\szero. +D 2014-11-07T13:52:44.718 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,7 +228,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 48fe276aada42a15722aee2584e6321345ed4609 +F src/shell.c 0500307f63e3675dc4ab21112c6086b4d146fc08 F src/sqlite.h.in f433227d7f619887a1064913fa66cefa3da4349a F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 402703212a8488f8b571ce170b3b6c7374bd7daa -R 9f78be6a67e175be94522748bee570f6 +P 94c564da4c2cf5dffe58fdf7a180e9ba4cc3de69 +R bf25c89aa0a2170169c258f353b46c64 U drh -Z 1fff294369c9fe8b2c9ed9357ff2fdd6 +Z 9c39d53d1fb35cc72c3ed2e42a4f819b diff --git a/manifest.uuid b/manifest.uuid index 3f84a89f53..7b8b4f079c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -94c564da4c2cf5dffe58fdf7a180e9ba4cc3de69 \ No newline at end of file +5700508535c35ac6b158b527e1d47e529e8e28ab \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 915b69263b..a33e65b1f8 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1222,7 +1222,7 @@ static void display_scanstats( fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain); rEstLoop *= rEst; fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", - nLoop, nVisit, (sqlite3_int64)rEstLoop, rEst + nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst ); } } From 97d3898335b39b07e8753d0d705dd4b396bd85a2 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Nov 2014 14:37:32 +0000 Subject: [PATCH 41/71] Fix another harmless comment typo. FossilOrigin-Name: b45bc80bb16f07192d84fd14433bb724a84d4146 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqliteInt.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index b3d774824c..579589c94b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\s".scanstats\son"\soutput\sfrom\sthe\sshell,\sround\sthe\sestRows\svalue\sto\nthe\snearest\sinteger,\srather\sthan\srounding\stoward\szero. -D 2014-11-07T13:52:44.718 +C Fix\sanother\sharmless\scomment\stypo. +D 2014-11-07T14:37:32.349 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -232,7 +232,7 @@ F src/shell.c 0500307f63e3675dc4ab21112c6086b4d146fc08 F src/sqlite.h.in f433227d7f619887a1064913fa66cefa3da4349a F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 +F src/sqliteInt.h 71b0bf1a7fc55b5cb374f7579fd140e730a6e0f4 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc @@ -1211,7 +1211,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 94c564da4c2cf5dffe58fdf7a180e9ba4cc3de69 -R bf25c89aa0a2170169c258f353b46c64 +P 5700508535c35ac6b158b527e1d47e529e8e28ab +R 95ce072bedb368f2e0f6da4bf10906cf U drh -Z 9c39d53d1fb35cc72c3ed2e42a4f819b +Z 8c052ffec320f3367f2daa07942512b6 diff --git a/manifest.uuid b/manifest.uuid index 7b8b4f079c..13afcc03f7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5700508535c35ac6b158b527e1d47e529e8e28ab \ No newline at end of file +b45bc80bb16f07192d84fd14433bb724a84d4146 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e9715efcf7..4d272b06a1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -562,7 +562,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst -** of 40. However, since LogEst quantaties are suppose to be estimates, +** of 40. However, since LogEst quantities are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** ** "LogEst" is short for "Logarithmic Estimate". From b391b944319fad869ec86b4798a0e62daf04d48c Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 7 Nov 2014 14:41:11 +0000 Subject: [PATCH 42/71] Add new test file e_blobopen.test, containing tests for sqlite3_blob_open(). FossilOrigin-Name: ecbccd0e594d22b3ae7fabc8037951dc49570bc3 --- main.mk | 1 + manifest | 30 ++- manifest.uuid | 2 +- src/sqlite.h.in | 58 +++-- src/tclsqlite.c | 2 + src/test1.c | 152 ----------- src/test_blob.c | 319 +++++++++++++++++++++++ src/test_config.c | 6 + src/vdbe.c | 5 +- test/e_blobopen.test | 549 +++++++++++++++++++++++++++++++++++++++ test/fkey7.test | 17 ++ test/without_rowid5.test | 3 +- 12 files changed, 950 insertions(+), 194 deletions(-) create mode 100644 src/test_blob.c create mode 100644 test/e_blobopen.test diff --git a/main.mk b/main.mk index 4a7ac02710..c8bf72b48b 100644 --- a/main.mk +++ b/main.mk @@ -246,6 +246,7 @@ TESTSRC = \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ + $(TOP)/src/test_blob.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ diff --git a/manifest b/manifest index 579589c94b..e08707974e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sanother\sharmless\scomment\stypo. -D 2014-11-07T14:37:32.349 +C Add\snew\stest\sfile\se_blobopen.test,\scontaining\stests\sfor\ssqlite3_blob_open(). +D 2014-11-07T14:41:11.404 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -151,7 +151,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk bbc8b6000ed143a1a8d31d3b4995c359a3188fa1 +F main.mk 3fececc835c5c23637c3e0af970e27a81a9ba476 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -229,15 +229,15 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c 0500307f63e3675dc4ab21112c6086b4d146fc08 -F src/sqlite.h.in f433227d7f619887a1064913fa66cefa3da4349a +F src/sqlite.h.in 5abfd7d6c9bd2054105820de5ce12b1e491b1dc9 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 71b0bf1a7fc55b5cb374f7579fd140e730a6e0f4 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc -F src/tclsqlite.c 7cdd4dd3c2a4183483feca260070d73d6e22cd47 -F src/test1.c ac7f3bad83ef4508d5efc85b32e86da48db8ed7e +F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228 +F src/test1.c cce6ad0effe8c66a62d2634d9714ffdc7372ef11 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -249,8 +249,9 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 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 c8b8b50bf2fe5102de10e4c7100b746d7f6bf62f +F src/test_config.c 035c17a173937d019b8dfc1d524f9d3fc8123504 F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f @@ -289,7 +290,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c -F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df +F src/vdbe.c d5dab22208e36e5689e9fb553aea3613921054ec F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 @@ -451,6 +452,7 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 +F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 w test/e_blob.test F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579 F test/e_createtable.test c7e67b49e6cf92473c8fb30ab26143e9e2128cf7 F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a @@ -491,7 +493,7 @@ F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48 -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 @@ -1155,7 +1157,7 @@ F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test 1081aabf60a1e1123b7f9a8f6ae19954351843b0 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a -F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107 +F test/without_rowid5.test 61256715b686359df48ca1742db50cc7e3e7b862 F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac @@ -1211,7 +1213,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 5700508535c35ac6b158b527e1d47e529e8e28ab -R 95ce072bedb368f2e0f6da4bf10906cf -U drh -Z 8c052ffec320f3367f2daa07942512b6 +P b45bc80bb16f07192d84fd14433bb724a84d4146 +R 0ead7b89f3ed1286937ae097bba351c9 +U dan +Z d785e78de9d268050b7beac3067db32e diff --git a/manifest.uuid b/manifest.uuid index 13afcc03f7..6227627e36 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b45bc80bb16f07192d84fd14433bb724a84d4146 \ No newline at end of file +ecbccd0e594d22b3ae7fabc8037951dc49570bc3 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index fc741b7291..bed64bfae2 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5657,26 +5657,42 @@ typedef struct sqlite3_blob sqlite3_blob; ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** )^ ** +** ^(Parameter zDb is not the filename that contains the database, but +** rather the symbolic name of the database. For attached databases, this is +** the name that appears after the AS keyword in the [ATTACH] statement. +** For the main database file, the database name is "main". For TEMP +** tables, the database name is "temp".)^ +** ** ^If the flags parameter is non-zero, then the BLOB is opened for read -** and write access. ^If it is zero, the BLOB is opened for read access. -** ^It is not possible to open a column that is part of an index or primary -** key for writing. ^If [foreign key constraints] are enabled, it is -** not possible to open a column that is part of a [child key] for writing. +** and write access. ^If the flags parameter is zero, the BLOB is opened for +** read-only access. ** -** ^Note that the database name is not the filename that contains -** the database but rather the symbolic name of the database that -** appears after the AS keyword when the database is connected using [ATTACH]. -** ^For the main database file, the database name is "main". -** ^For TEMP tables, the database name is "temp". +** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored +** in *ppBlob. Otherwise an [error code] is returned and, unless the error +** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided +** the API is not misused, it is always safe to call [sqlite3_blob_close()] +** on *ppBlob after this function it returns. +** +** This function fails with SQLITE_ERROR if any of the following are true: +**
    +**
  • ^(Database zDb does not exist)^, +**
  • ^(Table zTable does not exist within database zDb)^, +**
  • ^(Table zTable is a WITHOUT ROWID table)^, +**
  • ^(Column zColumn does not exist)^, +**
  • ^(Row iRow is not present in the table)^, +**
  • ^(The specified column of row iRow contains a value that is not +** a TEXT or BLOB value)^, +**
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE +** constraint and the blob is being opened for read/write access)^, +**
  • ^([foreign key constraints | Foreign key constraints] are enabled, +** column zColumn is part of a [child key] definition and the blob is +** being opened for read/write access)^. +**
+** +** ^Unless it returns SQLITE_MISUSE, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** -** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written -** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set -** to be a null pointer.)^ -** ^This function sets the [database connection] error code and message -** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related -** functions. ^Note that the *ppBlob variable is always initialized in a -** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob -** regardless of the success or failure of this routine. ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects @@ -5694,13 +5710,9 @@ typedef struct sqlite3_blob sqlite3_blob; ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** -** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID] -** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables. -** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces -** and the built-in [zeroblob] SQL function can be used, if desired, -** to create an empty, zero-filled blob in which to read or write using -** this interface. +** and the built-in [zeroblob] SQL function may be used to create a +** zero-filled blob to read or write using the incremental-blob interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. diff --git a/src/tclsqlite.c b/src/tclsqlite.c index bff4a92421..4fb78a5d12 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3725,6 +3725,7 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); + extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); @@ -3768,6 +3769,7 @@ static void init_all(Tcl_Interp *interp){ Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); + Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); diff --git a/src/test1.c b/src/test1.c index fcc1a23de1..e7a5929323 100644 --- a/src/test1.c +++ b/src/test1.c @@ -1651,154 +1651,6 @@ static int blobHandleFromObj( return TCL_OK; } -/* -** sqlite3_blob_bytes CHANNEL -*/ -static int test_blob_bytes( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int nByte; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - nByte = sqlite3_blob_bytes(pBlob); - Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); - - return TCL_OK; -} - -/* -** sqlite3_blob_close CHANNEL -*/ -static int test_blob_close( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - sqlite3_blob_close(pBlob); - - return TCL_OK; -} - -/* -** sqlite3_blob_read CHANNEL OFFSET N -** -** This command is used to test the sqlite3_blob_read() in ways that -** the Tcl channel interface does not. The first argument should -** be the name of a valid channel created by the [incrblob] method -** of a database handle. This function calls sqlite3_blob_read() -** to read N bytes from offset OFFSET from the underlying SQLite -** blob handle. -** -** On success, a byte-array object containing the read data is -** returned. On failure, the interpreter result is set to the -** text representation of the returned error code (i.e. "SQLITE_NOMEM") -** and a Tcl exception is thrown. -*/ -static int test_blob_read( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int nByte; - int iOffset; - unsigned char *zBuf = 0; - int rc; - - if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) - || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) - ){ - return TCL_ERROR; - } - - if( nByte>0 ){ - zBuf = (unsigned char *)Tcl_Alloc(nByte); - } - rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); - if( rc==SQLITE_OK ){ - Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); - }else{ - Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); - } - Tcl_Free((char *)zBuf); - - return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); -} - -/* -** sqlite3_blob_write CHANNEL OFFSET DATA ?NDATA? -** -** This command is used to test the sqlite3_blob_write() in ways that -** the Tcl channel interface does not. The first argument should -** be the name of a valid channel created by the [incrblob] method -** of a database handle. This function calls sqlite3_blob_write() -** to write the DATA byte-array to the underlying SQLite blob handle. -** at offset OFFSET. -** -** On success, an empty string is returned. On failure, the interpreter -** result is set to the text representation of the returned error code -** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. -*/ -static int test_blob_write( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int iOffset; - int rc; - - unsigned char *zBuf; - int nBuf; - - if( objc!=4 && objc!=5 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA ?NDATA?"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ - return TCL_ERROR; - } - - zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); - if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ - return TCL_ERROR; - } - rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); - if( rc!=SQLITE_OK ){ - Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); - } - - return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); -} - static int test_blob_reopen( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ @@ -6910,11 +6762,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB - { "sqlite3_blob_read", test_blob_read, 0 }, - { "sqlite3_blob_write", test_blob_write, 0 }, { "sqlite3_blob_reopen", test_blob_reopen, 0 }, - { "sqlite3_blob_bytes", test_blob_bytes, 0 }, - { "sqlite3_blob_close", test_blob_close, 0 }, #endif { "pcache_stats", test_pcache_stats, 0 }, #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY diff --git a/src/test_blob.c b/src/test_blob.c new file mode 100644 index 0000000000..d88c91366a --- /dev/null +++ b/src/test_blob.c @@ -0,0 +1,319 @@ +/* +** 2014 October 30 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +*/ +#include "sqliteInt.h" +#include "tcl.h" +#include +#include +#include + +/* These functions are implemented in main.c. */ +extern const char *sqlite3ErrName(int); + +/* From test1.c: */ +extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); +extern void *sqlite3TestTextToPtr(const char *z); + +/* +** Return a pointer to a buffer containing a text representation of the +** pointer passed as the only argument. The original pointer may be extracted +** from the text using sqlite3TestTextToPtr(). +*/ +static char *ptrToText(void *p){ + static char buf[100]; + sqlite3_snprintf(sizeof(buf)-1, buf, "%p", p); + return buf; +} + +/* +** Attempt to extract a blob handle (type sqlite3_blob*) from the Tcl +** object passed as the second argument. If successful, set *ppBlob to +** point to the blob handle and return TCL_OK. Otherwise, store an error +** message in the tcl interpreter and return TCL_ERROR. The final value +** of *ppBlob is undefined in this case. +** +** If the object contains a string that begins with "incrblob_", then it +** is assumed to be the name of a Tcl channel opened using the [db incrblob] +** command (see tclsqlite.c). Otherwise, it is assumed to be a pointer +** encoded using the ptrToText() routine or similar. +*/ +static int blobHandleFromObj( + Tcl_Interp *interp, + Tcl_Obj *pObj, + sqlite3_blob **ppBlob +){ + char *z; + int n; + + z = Tcl_GetStringFromObj(pObj, &n); + if( n==0 ){ + *ppBlob = 0; + }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){ + int notUsed; + Tcl_Channel channel; + ClientData instanceData; + + channel = Tcl_GetChannel(interp, z, ¬Used); + if( !channel ) return TCL_ERROR; + + Tcl_Flush(channel); + Tcl_Seek(channel, 0, SEEK_SET); + + instanceData = Tcl_GetChannelInstanceData(channel); + *ppBlob = *((sqlite3_blob **)instanceData); + }else{ + *ppBlob = (sqlite3_blob*)sqlite3TestTextToPtr(z); + } + + return TCL_OK; +} + +/* +** Like Tcl_GetString(), except that if the string is 0 bytes in size, a +** NULL Pointer is returned. +*/ +static char *blobStringFromObj(Tcl_Obj *pObj){ + int n; + char *z; + z = Tcl_GetStringFromObj(pObj, &n); + return (n ? z : 0); +} + +/* +** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME +** +** Tcl test harness for the sqlite3_blob_open() function. +*/ +static int test_blob_open( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* Calling TCL interpreter */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + const char *zDb; + const char *zTable; + const char *zColumn; + sqlite_int64 iRowid; + int flags; + const char *zVarname; + int nVarname; + + sqlite3_blob *pBlob = (sqlite3_blob*)0xFFFFFFFF; + int rc; + + if( objc!=8 ){ + const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME"; + Tcl_WrongNumArgs(interp, 1, objv, zUsage); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zDb = Tcl_GetString(objv[2]); + zTable = blobStringFromObj(objv[3]); + zColumn = Tcl_GetString(objv[4]); + if( Tcl_GetWideIntFromObj(interp, objv[5], &iRowid) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[6], &flags) ) return TCL_ERROR; + zVarname = Tcl_GetStringFromObj(objv[7], &nVarname); + + if( nVarname>0 ){ + rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, &pBlob); + Tcl_SetVar(interp, zVarname, ptrToText(pBlob), 0); + }else{ + rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, 0); + } + + if( rc==SQLITE_OK ){ + Tcl_ResetResult(interp); + }else{ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + + +/* +** sqlite3_blob_close HANDLE +*/ +static int test_blob_close( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int rc; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + rc = sqlite3_blob_close(pBlob); + + if( rc ){ + Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); + }else{ + Tcl_ResetResult(interp); + } + return TCL_OK; +} + +/* +** sqlite3_blob_bytes HANDLE +*/ +static int test_blob_bytes( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int nByte; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + nByte = sqlite3_blob_bytes(pBlob); + Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); + + return TCL_OK; +} + +/* +** sqlite3_blob_read CHANNEL OFFSET N +** +** This command is used to test the sqlite3_blob_read() in ways that +** the Tcl channel interface does not. The first argument should +** be the name of a valid channel created by the [incrblob] method +** of a database handle. This function calls sqlite3_blob_read() +** to read N bytes from offset OFFSET from the underlying SQLite +** blob handle. +** +** On success, a byte-array object containing the read data is +** returned. On failure, the interpreter result is set to the +** text representation of the returned error code (i.e. "SQLITE_NOMEM") +** and a Tcl exception is thrown. +*/ +static int test_blob_read( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int nByte; + int iOffset; + unsigned char *zBuf = 0; + int rc; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) + || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) + ){ + return TCL_ERROR; + } + + if( nByte>0 ){ + zBuf = (unsigned char *)Tcl_Alloc(nByte); + } + rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); + }else{ + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + } + Tcl_Free((char *)zBuf); + + return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); +} + +/* +** sqlite3_blob_write HANDLE OFFSET DATA ?NDATA? +** +** This command is used to test the sqlite3_blob_write() in ways that +** the Tcl channel interface does not. The first argument should +** be the name of a valid channel created by the [incrblob] method +** of a database handle. This function calls sqlite3_blob_write() +** to write the DATA byte-array to the underlying SQLite blob handle. +** at offset OFFSET. +** +** On success, an empty string is returned. On failure, the interpreter +** result is set to the text representation of the returned error code +** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. +*/ +static int test_blob_write( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int iOffset; + int rc; + + unsigned char *zBuf; + int nBuf; + + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ + return TCL_ERROR; + } + + zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); + if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ + return TCL_ERROR; + } + rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + } + + return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); +} + + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetest_blob_Init(Tcl_Interp *interp){ + static struct { + char *zName; + Tcl_ObjCmdProc *xProc; + } aObjCmd[] = { + { "sqlite3_blob_open", test_blob_open }, + { "sqlite3_blob_close", test_blob_close }, + { "sqlite3_blob_bytes", test_blob_bytes }, + { "sqlite3_blob_read", test_blob_read }, + { "sqlite3_blob_write", test_blob_write }, + }; + int i; + for(i=0; ipKeyInfo, aTempRec, sizeof(aTempRec), &pFree - ); + ); if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); - assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ + /* assert( (pIn3->flags & MEM_Zero)==0 ); // zeroblobs already expanded */ + ExpandBlob(pIn3); sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; diff --git a/test/e_blobopen.test b/test/e_blobopen.test new file mode 100644 index 0000000000..01f62cdd78 --- /dev/null +++ b/test/e_blobopen.test @@ -0,0 +1,549 @@ +# 2014 October 30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobopen + +forcedelete test.db2 + +do_execsql_test 1.0 { + ATTACH 'test.db2' AS aux; + + CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + + CREATE TABLE main.x1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TEMP TABLE x2(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + CREATE TABLE aux.x3(a INTEGER PRIMARY KEY, b TEXT, c BLOB); + + INSERT INTO main.t1 VALUES(1, 'main one', X'0101'); + INSERT INTO main.t1 VALUES(2, 'main two', X'0102'); + INSERT INTO main.t1 VALUES(3, 'main three', X'0103'); + INSERT INTO main.t1 VALUES(4, 'main four', X'0104'); + INSERT INTO main.t1 VALUES(5, 'main five', X'0105'); + + INSERT INTO main.x1 VALUES(1, 'x main one', X'000101'); + INSERT INTO main.x1 VALUES(2, 'x main two', X'000102'); + INSERT INTO main.x1 VALUES(3, 'x main three', X'000103'); + INSERT INTO main.x1 VALUES(4, 'x main four', X'000104'); + INSERT INTO main.x1 VALUES(5, 'x main five', X'000105'); + + INSERT INTO temp.t1 VALUES(1, 'temp one', X'0201'); + INSERT INTO temp.t1 VALUES(2, 'temp two', X'0202'); + INSERT INTO temp.t1 VALUES(3, 'temp three', X'0203'); + INSERT INTO temp.t1 VALUES(4, 'temp four', X'0204'); + INSERT INTO temp.t1 VALUES(5, 'temp five', X'0205'); + + INSERT INTO temp.x2 VALUES(1, 'x temp one', X'000201'); + INSERT INTO temp.x2 VALUES(2, 'x temp two', X'000202'); + INSERT INTO temp.x2 VALUES(3, 'x temp three', X'000203'); + INSERT INTO temp.x2 VALUES(4, 'x temp four', X'000204'); + INSERT INTO temp.x2 VALUES(5, 'x temp five', X'000205'); + + INSERT INTO aux.t1 VALUES(1, 'aux one', X'0301'); + INSERT INTO aux.t1 VALUES(2, 'aux two', X'0302'); + INSERT INTO aux.t1 VALUES(3, 'aux three', X'0303'); + INSERT INTO aux.t1 VALUES(4, 'aux four', X'0304'); + INSERT INTO aux.t1 VALUES(5, 'aux five', X'0305'); + + INSERT INTO aux.x3 VALUES(1, 'x aux one', X'000301'); + INSERT INTO aux.x3 VALUES(2, 'x aux two', X'000302'); + INSERT INTO aux.x3 VALUES(3, 'x aux three', X'000303'); + INSERT INTO aux.x3 VALUES(4, 'x aux four', X'000304'); + INSERT INTO aux.x3 VALUES(5, 'x aux five', X'000305'); +} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-37639-55938 This interfaces opens a handle to the BLOB +# located in row iRow, column zColumn, table zTable in database zDb; in +# other words, the same BLOB that would be selected by: SELECT zColumn +# FROM zDb.zTable WHERE rowid = iRow; +# +proc read_blob {zDb zTab zCol iRow} { + sqlite3_blob_open db $zDb $zTab $zCol $iRow 0 B + set nByte [sqlite3_blob_bytes $B] + set data [sqlite3_blob_read $B 0 $nByte] + sqlite3_blob_close $B + return $data +} + +do_test 1.1.1 { read_blob main t1 b 1 } "main one" +do_test 1.1.2 { read_blob main t1 c 1 } "\01\01" +do_test 1.1.3 { read_blob temp t1 b 1 } "temp one" +do_test 1.1.4 { read_blob temp t1 c 1 } "\02\01" +do_test 1.1.6 { read_blob aux t1 b 1 } "aux one" +do_test 1.1.7 { read_blob aux t1 c 1 } "\03\01" + +do_test 1.2.1 { read_blob main t1 b 4 } "main four" +do_test 1.2.2 { read_blob main t1 c 4 } "\01\04" +do_test 1.2.3 { read_blob temp t1 b 4 } "temp four" +do_test 1.2.4 { read_blob temp t1 c 4 } "\02\04" +do_test 1.2.6 { read_blob aux t1 b 4 } "aux four" +do_test 1.2.7 { read_blob aux t1 c 4 } "\03\04" + +do_test 1.3.1 { read_blob main x1 b 2 } "x main two" +do_test 1.3.2 { read_blob main x1 c 2 } "\00\01\02" +do_test 1.3.3 { read_blob temp x2 b 2 } "x temp two" +do_test 1.3.4 { read_blob temp x2 c 2 } "\00\02\02" +do_test 1.3.6 { read_blob aux x3 b 2 } "x aux two" +do_test 1.3.7 { read_blob aux x3 c 2 } "\00\03\02" + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-27234-05761 Parameter zDb is not the filename that +# contains the database, but rather the symbolic name of the database. +# For attached databases, this is the name that appears after the AS +# keyword in the ATTACH statement. For the main database file, the +# database name is "main". For TEMP tables, the database name is "temp". +# +# The test cases immediately above demonstrate that the database name +# for the main db, for TEMP tables and for those in attached databases +# is correct. The following tests check that filenames cannot be +# used as well. +# +do_test 2.1 { + list [catch { sqlite3_blob_open db "test.db" t1 b 1 0 B } msg] $msg +} {1 SQLITE_ERROR} +do_test 2.2 { + list [catch { sqlite3_blob_open db "test.db2" t1 b 1 0 B } msg] $msg +} {1 SQLITE_ERROR} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-50854-53979 If the flags parameter is non-zero, then +# the BLOB is opened for read and write access. +# +# EVIDENCE-OF: R-03922-41160 If the flags parameter is zero, the BLOB is +# opened for read-only access. +# +foreach {tn iRow flags} { + 1 1 0 + 2 2 1 + 3 3 -1 + 4 4 2147483647 + 5 5 -2147483648 +} { + do_test 3.$tn.1 { + sqlite3_blob_open db main x1 c $iRow $flags B + set n [sqlite3_blob_bytes $B] + sqlite3_blob_read $B 0 $n + } [binary format ccc 0 1 $iRow] + + if {$flags==0} { + # Blob was opened for read-only access - writing returns an error. + do_test 3.$tn.2 { + list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg + } {1 SQLITE_READONLY} + + do_execsql_test 3.$tn.3 { + SELECT c FROM x1 WHERE a=$iRow; + } [binary format ccc 0 1 $iRow] + } else { + # Blob was opened for read/write access - writing succeeds + do_test 3.$tn.4 { + list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg + } {0 {}} + + do_execsql_test 3.$tn.5 { + SELECT c FROM x1 WHERE a=$iRow; + } {xxx} + } + + sqlite3_blob_close $B +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 4.0 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES('abcd', 152); + INSERT INTO t1 VALUES(NULL, X'00010203'); + INSERT INTO t1 VALUES('', 154.2); + + CREATE TABLE t2(x PRIMARY KEY, y) WITHOUT ROWID; + INSERT INTO t2 VALUES(1, 'blob'); + + CREATE TABLE t3(a PRIMARY KEY, b, c, d, e, f, UNIQUE(e, f)); + INSERT INTO t3 VALUES('aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff'); + CREATE INDEX t3b ON t3(b); + + CREATE TABLE p1(x PRIMARY KEY); + INSERT INTO p1 VALUES('abc'); + + CREATE TABLE c1(a INTEGER PRIMARY KEY, b REFERENCES p1); + INSERT INTO c1 VALUES(45, 'abc'); +} + +proc test_blob_open {tn zDb zTab zCol iRow flags errcode errmsg} { + global B + set B "0x1234" + + if {$errcode=="SQLITE_OK"} { + set expected "0 {}" + } else { + set expected "1 $errcode" + } + + set ::res [list [ + catch { sqlite3_blob_open db $zDb $zTab $zCol $iRow $flags B } msg + ] $msg] + do_test 4.$tn.1 { set ::res } $expected + + # EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this + # function sets the database connection error code and message + # accessible via sqlite3_errcode() and sqlite3_errmsg() and related + # functions. + # + # This proc (test_blob_open) is used below to test various error and + # non-error conditions. But never SQLITE_MISUSE conditions. So these + # test cases are considered as partly verifying the requirement above. + # See below for a test of the SQLITE_MISUSE case. + # + do_test 4.$tn.2 { + sqlite3_errcode db + } $errcode + do_test 4.$tn.3 { + sqlite3_errmsg db + } $errmsg + + # EVIDENCE-OF: R-31086-35521 On success, SQLITE_OK is returned and the + # new BLOB handle is stored in *ppBlob. Otherwise an error code is + # returned and, unless the error code is SQLITE_MISUSE, *ppBlob is set + # to NULL. + # + do_test 4.$tn.4 { + expr {$B == "0"} + } [expr {$errcode != "SQLITE_OK"}] + + # EVIDENCE-OF: R-63421-15521 This means that, provided the API is not + # misused, it is always safe to call sqlite3_blob_close() on *ppBlob + # after this function it returns. + do_test 4.$tn.5 { + sqlite3_blob_close $B + } {} +} + +# EVIDENCE-OF: R-31204-44780 Database zDb does not exist +test_blob_open 1 nosuchdb t1 x 1 0 SQLITE_ERROR "no such table: nosuchdb.t1" + +# EVIDENCE-OF: R-28676-08005 Table zTable does not exist within database zDb +test_blob_open 2 main tt1 x 1 0 SQLITE_ERROR "no such table: main.tt1" + +# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table +test_blob_open 3 main t2 y 1 0 SQLITE_ERROR \ + "cannot open table without rowid: t2" + +# EVIDENCE-OF: R-56376-21261 Column zColumn does not exist +test_blob_open 4 main t1 z 2 0 SQLITE_ERROR "no such column: \"z\"" + +# EVIDENCE-OF: R-28258-23166 Row iRow is not present in the table +test_blob_open 5 main t1 y 6 0 SQLITE_ERROR "no such rowid: 6" + +# EVIDENCE-OF: R-11683-62380 The specified column of row iRow contains a +# value that is not a TEXT or BLOB value +test_blob_open 6 main t1 x 2 0 SQLITE_ERROR "cannot open value of type null" +test_blob_open 7 main t1 y 1 0 SQLITE_ERROR "cannot open value of type integer" +test_blob_open 8 main t1 y 3 0 SQLITE_ERROR "cannot open value of type real" + +# EVIDENCE-OF: R-34146-30782 Column zColumn is part of an index, PRIMARY +# KEY or UNIQUE constraint and the blob is being opened for read/write +# access +# +# Test cases 8.1.* show that such columns can be opened for read-access. +# Tests 8.2.* show that read-write access is different. Columns "c" and "c" +# are not part of an index, PK or UNIQUE constraint, so they work in both +# cases. +# +test_blob_open 8.1.1 main t3 a 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.2 main t3 b 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.3 main t3 c 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.4 main t3 d 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.5 main t3 e 1 0 SQLITE_OK "not an error" +test_blob_open 8.1.6 main t3 f 1 0 SQLITE_OK "not an error" + +set cannot "cannot open indexed column for writing" +test_blob_open 8.2.1 main t3 a 1 8 SQLITE_ERROR $cannot +test_blob_open 8.2.2 main t3 b 1 8 SQLITE_ERROR $cannot +test_blob_open 8.2.3 main t3 c 1 8 SQLITE_OK "not an error" +test_blob_open 8.2.4 main t3 d 1 8 SQLITE_OK "not an error" +test_blob_open 8.2.5 main t3 e 1 8 SQLITE_ERROR $cannot +test_blob_open 8.2.6 main t3 f 1 8 SQLITE_ERROR $cannot + +# EVIDENCE-OF: R-50117-55204 Foreign key constraints are enabled, column +# zColumn is part of a child key definition and the blob is being opened +# for read/write access +# +# 9.1: FK disabled, read-only access. +# 9.2: FK disabled, read-only access. +# 9.3: FK enabled, read/write access. +# 9.4: FK enabled, read/write access. +# +test_blob_open 9.1 main c1 b 45 0 SQLITE_OK "not an error" +test_blob_open 9.2 main c1 b 45 1 SQLITE_OK "not an error" +execsql { PRAGMA foreign_keys = ON } +test_blob_open 9.3 main c1 b 45 0 SQLITE_OK "not an error" +test_blob_open 9.4 main c1 b 45 1 SQLITE_ERROR \ + "cannot open foreign key column for writing" + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this +# function sets the database connection error code and message +# accessible via sqlite3_errcode() and sqlite3_errmsg() and related +# functions. +# +# This requirement is partially verified by the many uses of test +# command [test_blob_open] above. All that is left is to verify the +# SQLITE_MISUSE case. +# +# SQLITE_MISUSE is only returned if SQLITE_ENABLE_API_ARMOR is defined +# during compilation. +# +ifcapable api_armor { + sqlite3_blob_open db main t1 x 1 0 B + + do_test 10.1.1 { + list [catch {sqlite3_blob_open $B main t1 x 1 0 B2} msg] $msg + } {1 SQLITE_MISUSE} + do_test 10.1.2 { + list [sqlite3_errcode db] [sqlite3_errmsg db] + } {SQLITE_OK {not an error}} + sqlite3_blob_close $B + + do_test 10.2.1 { + list [catch {sqlite3_blob_open db main {} x 1 0 B} msg] $msg + } {1 SQLITE_MISUSE} + do_test 10.2.2 { + list [sqlite3_errcode db] [sqlite3_errmsg db] + } {SQLITE_OK {not an error}} +} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-50542-62589 If the row that a BLOB handle points to is +# modified by an UPDATE, DELETE, or by ON CONFLICT side-effects then the +# BLOB handle is marked as "expired". This is true if any column of the +# row is changed, even a column other than the one the BLOB handle is +# open on. +# +# EVIDENCE-OF: R-48367-20048 Calls to sqlite3_blob_read() and +# sqlite3_blob_write() for an expired BLOB handle fail with a return +# code of SQLITE_ABORT. +# +# 11.2: read-only handle, DELETE. +# 11.3: read-only handle, UPDATE. +# 11.4: read-only handle, REPLACE. +# 11.5: read/write handle, DELETE. +# 11.6: read/write handle, UPDATE. +# 11.7: read/write handle, REPLACE. +# +do_execsql_test 11.1 { + CREATE TABLE b1(a INTEGER PRIMARY KEY, b, c UNIQUE); + INSERT INTO b1 VALUES(1, '1234567890', 1); + INSERT INTO b1 VALUES(2, '1234567890', 2); + INSERT INTO b1 VALUES(3, '1234567890', 3); + INSERT INTO b1 VALUES(4, '1234567890', 4); + INSERT INTO b1 VALUES(5, '1234567890', 5); + INSERT INTO b1 VALUES(6, '1234567890', 6); + + CREATE TABLE b2(a INTEGER PRIMARY KEY, b, c UNIQUE); + INSERT INTO b2 VALUES(1, '1234567890', 1); + INSERT INTO b2 VALUES(2, '1234567890', 2); + INSERT INTO b2 VALUES(3, '1234567890', 3); + INSERT INTO b2 VALUES(4, '1234567890', 4); + INSERT INTO b2 VALUES(5, '1234567890', 5); + INSERT INTO b2 VALUES(6, '1234567890', 6); +} + +do_test 11.2.1 { + sqlite3_blob_open db main b1 b 2 0 B + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.2.2 { + # Deleting a different row does not invalidate the blob handle. + execsql { DELETE FROM b1 WHERE a = 1 } + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.2.3 { + execsql { DELETE FROM b1 WHERE a = 2 } + list [catch { sqlite3_blob_read $B 0 10 } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.2.4 { + sqlite3_blob_close $B +} {} + +do_test 11.3.1 { + sqlite3_blob_open db main b1 b 3 0 B + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.3.2 { + # Updating a different row + execsql { UPDATE b1 SET c = 42 WHERE a=4 } + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.3.3 { + execsql { UPDATE b1 SET c = 43 WHERE a=3 } + list [catch { sqlite3_blob_read $B 0 10 } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.3.4 { + sqlite3_blob_close $B +} {} + +do_test 11.4.1 { + sqlite3_blob_open db main b1 b 6 0 B + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.4.2 { + # Replace a different row + execsql { INSERT OR REPLACE INTO b1 VALUES(10, 'abcdefghij', 5) } + sqlite3_blob_read $B 0 10 +} {1234567890} +do_test 11.4.3 { + execsql { INSERT OR REPLACE INTO b1 VALUES(11, 'abcdefghij', 6) } + list [catch { sqlite3_blob_read $B 0 10 } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.4.4 { + sqlite3_blob_close $B +} {} + +do_test 11.4.1 { + sqlite3_blob_open db main b2 b 2 1 B + sqlite3_blob_write $B 0 "abcdefghij" +} {} +do_test 11.4.2 { + # Deleting a different row does not invalidate the blob handle. + execsql { DELETE FROM b2 WHERE a = 1 } + sqlite3_blob_write $B 0 "ABCDEFGHIJ" +} {} +do_test 11.4.3 { + execsql { DELETE FROM b2 WHERE a = 2 } + list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.4.4 { + sqlite3_blob_close $B +} {} + +do_test 11.5.1 { + sqlite3_blob_open db main b2 b 3 1 B + sqlite3_blob_write $B 0 "abcdefghij" +} {} +do_test 11.5.2 { + # Updating a different row + execsql { UPDATE b2 SET c = 42 WHERE a=4 } + sqlite3_blob_write $B 0 "ABCDEFGHIJ" +} {} +do_test 11.5.3 { + execsql { UPDATE b2 SET c = 43 WHERE a=3 } + list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.5.4 { + sqlite3_blob_close $B +} {} + +do_test 11.6.1 { + sqlite3_blob_open db main b2 b 6 1 B + sqlite3_blob_write $B 0 "abcdefghij" +} {} +do_test 11.6.2 { + # Replace a different row + execsql { INSERT OR REPLACE INTO b2 VALUES(10, 'abcdefghij', 5) } + sqlite3_blob_write $B 0 "ABCDEFGHIJ" +} {} +do_test 11.6.3 { + execsql { INSERT OR REPLACE INTO b2 VALUES(11, 'abcdefghij', 6) } + list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg +} {1 SQLITE_ABORT} +do_test 11.6.4 { + sqlite3_blob_close $B +} {} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-45408-40694 Changes written into a BLOB prior to the +# BLOB expiring are not rolled back by the expiration of the BLOB. Such +# changes will eventually commit if the transaction continues to +# completion. +# +do_execsql_test 12.1 { + CREATE TABLE b3(x INTEGER PRIMARY KEY, y TEXT, z INTEGER); + INSERT INTO b3 VALUES(22, '..........', NULL); +} +do_test 12.2 { + sqlite3_blob_open db main b3 y 22 1 B + sqlite3_blob_write $B 0 "xxxxx" 5 +} {} +do_execsql_test 12.3 { + UPDATE b3 SET z = 'not null'; +} +do_test 12.4 { + list [catch {sqlite3_blob_write $B 5 "xxxxx" 5} msg] $msg +} {1 SQLITE_ABORT} +do_execsql_test 12.5 { + SELECT * FROM b3; +} {22 xxxxx..... {not null}} +do_test 12.5 { + sqlite3_blob_close $B +} {} +do_execsql_test 12.6 { + SELECT * FROM b3; +} {22 xxxxx..... {not null}} + +#------------------------------------------------------------------------- +# EVIDENCE-OF: R-58813-55036 The sqlite3_bind_zeroblob() and +# sqlite3_result_zeroblob() interfaces and the built-in zeroblob SQL +# function may be used to create a zero-filled blob to read or write +# using the incremental-blob interface. +# +do_execsql_test 13.1 { + CREATE TABLE c2(i INTEGER PRIMARY KEY, j); + INSERT INTO c2 VALUES(10, zeroblob(24)); +} + +do_test 13.2 { + set stmt [sqlite3_prepare_v2 db "INSERT INTO c2 VALUES(11, ?)" -1] + sqlite3_bind_zeroblob $stmt 1 45 + sqlite3_step $stmt + sqlite3_finalize $stmt +} {SQLITE_OK} + +# The blobs can be read: +# +do_test 13.3.1 { + sqlite3_blob_open db main c2 j 10 1 B + sqlite3_blob_open db main c2 j 11 1 B2 + list [sqlite3_blob_bytes $B] [sqlite3_blob_bytes $B2] +} {24 45} +do_test 13.3.2 { + sqlite3_blob_read $B 0 24 +} [string repeat [binary format c 0] 24] +do_test 13.3.3 { + sqlite3_blob_read $B2 0 45 +} [string repeat [binary format c 0] 45] + +# And also written: +# +do_test 13.4.1 { + sqlite3_blob_write $B 0 [string repeat [binary format c 1] 24] +} {} +do_test 13.4.2 { + sqlite3_blob_write $B2 0 [string repeat [binary format c 1] 45] +} {} +do_test 13.5 { + sqlite3_blob_close $B + sqlite3_blob_close $B2 + execsql { SELECT j FROM c2 } +} [list \ + [string repeat [binary format c 1] 24] \ + [string repeat [binary format c 1] 45] \ +] + + +finish_test + diff --git a/test/fkey7.test b/test/fkey7.test index c2682edbe5..6c646a9a7f 100644 --- a/test/fkey7.test +++ b/test/fkey7.test @@ -50,5 +50,22 @@ do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par} do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par} do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1} +ifcapable incrblob { + do_execsql_test 2.0 { + CREATE TABLE pX(x PRIMARY KEY); + CREATE TABLE cX(a INTEGER PRIMARY KEY, b REFERENCES pX); + } + + do_catchsql_test 2.1 { + INSERT INTO cX VALUES(11, zeroblob(40)); + } {1 {FOREIGN KEY constraint failed}} + + do_test 2.2 { + set stmt [sqlite3_prepare_v2 db "INSERT INTO cX VALUES(11, ?)" -1] + sqlite3_bind_zeroblob $stmt 1 45 + sqlite3_step $stmt + sqlite3_finalize $stmt + } {SQLITE_CONSTRAINT} +} finish_test diff --git a/test/without_rowid5.test b/test/without_rowid5.test index 45e047befe..d163d9c1bc 100644 --- a/test/without_rowid5.test +++ b/test/without_rowid5.test @@ -185,8 +185,7 @@ do_execsql_test without_rowid5-5.9 { # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # -# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail -# for a WITHOUT ROWID table. +# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table # do_execsql_test without_rowid5-6.1 { CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID; From 4ace5362c250de7d712ef107275427aaa8c2c304 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Nov 2014 14:42:28 +0000 Subject: [PATCH 43/71] Shorten over-length source code lines in shell.c. FossilOrigin-Name: 7f3819f6422badd344c1264b0cd2f2c7afe077df --- manifest | 16 ++++---- manifest.uuid | 2 +- src/shell.c | 100 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 76 insertions(+), 42 deletions(-) diff --git a/manifest b/manifest index e08707974e..5e62c4081e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\stest\sfile\se_blobopen.test,\scontaining\stests\sfor\ssqlite3_blob_open(). -D 2014-11-07T14:41:11.404 +C Shorten\sover-length\ssource\scode\slines\sin\sshell.c. +D 2014-11-10T14:42:28.114 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,7 +228,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 0500307f63e3675dc4ab21112c6086b4d146fc08 +F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd F src/sqlite.h.in 5abfd7d6c9bd2054105820de5ce12b1e491b1dc9 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d @@ -452,7 +452,7 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 -F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 w test/e_blob.test +F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579 F test/e_createtable.test c7e67b49e6cf92473c8fb30ab26143e9e2128cf7 F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a @@ -1213,7 +1213,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P b45bc80bb16f07192d84fd14433bb724a84d4146 -R 0ead7b89f3ed1286937ae097bba351c9 -U dan -Z d785e78de9d268050b7beac3067db32e +P ecbccd0e594d22b3ae7fabc8037951dc49570bc3 +R 1a35da25c621486ba7906429ccbf946c +U drh +Z 427c2830707548878070627d5502fc48 diff --git a/manifest.uuid b/manifest.uuid index 6227627e36..541a9c512c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ecbccd0e594d22b3ae7fabc8037951dc49570bc3 \ No newline at end of file +7f3819f6422badd344c1264b0cd2f2c7afe077df \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index a33e65b1f8..bbd37c7a04 100644 --- a/src/shell.c +++ b/src/shell.c @@ -172,7 +172,8 @@ static HANDLE hProcess; static FILETIME ftKernelBegin; static FILETIME ftUserBegin; static sqlite3_int64 ftWallBegin; -typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); +typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, + LPFILETIME, LPFILETIME); static GETPROCTIMES getProcessTimesAddr = NULL; /* @@ -183,15 +184,16 @@ static int hasTimer(void){ if( getProcessTimesAddr ){ return 1; } else { - /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions. - ** See if the version we are running on has it, and if it does, save off - ** a pointer to it and the current process handle. + /* GetProcessTimes() isn't supported in WIN95 and some other Windows + ** versions. See if the version we are running on has it, and if it + ** does, save off a pointer to it and the current process handle. */ hProcess = GetCurrentProcess(); if( hProcess ){ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); if( NULL != hinstLib ){ - getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); + getProcessTimesAddr = + (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); if( NULL != getProcessTimesAddr ){ return 1; } @@ -208,7 +210,8 @@ static int hasTimer(void){ static void beginTimer(void){ if( enableTimer && getProcessTimesAddr ){ FILETIME ftCreation, ftExit; - getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit, + &ftKernelBegin,&ftUserBegin); ftWallBegin = timeOfDay(); } } @@ -227,7 +230,7 @@ static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; sqlite3_int64 ftWallEnd = timeOfDay(); - getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); printf("Run Time: real %.3f user %f sys %f\n", (ftWallEnd - ftWallBegin)*0.001, timeDiff(&ftUserBegin, &ftUserEnd), @@ -726,7 +729,13 @@ static void interrupt_handler(int NotUsed){ ** This is the callback routine that the shell ** invokes for each row of a query result. */ -static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ +static int shell_callback( + void *pArg, + int nArg, /* Number of result columns */ + char **azArg, /* Text of each result column */ + char **azCol, /* Column names */ + int *aiType /* Column types */ +){ int i; ShellState *p = (ShellState*)pArg; @@ -1105,57 +1114,77 @@ static int display_stats( iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr); + fprintf(pArg->out, + "Memory Used: %d (max %d) bytes\n", + iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); + fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", + iCur, iHiwtr); if( pArg->shellFlgs & SHFLG_Pagecache ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); + fprintf(pArg->out, + "Number of Pcache Pages Used: %d (max %d) pages\n", + iCur, iHiwtr); } iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); + fprintf(pArg->out, + "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", + iCur, iHiwtr); if( pArg->shellFlgs & SHFLG_Scratch ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); + fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", + iCur, iHiwtr); } iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); + fprintf(pArg->out, + "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", + iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr); + fprintf(pArg->out, "Largest Allocation: %d bytes\n", + iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr); + fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", + iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr); + fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", + iHiwtr); #ifdef YYTRACKMAXSTACKDEPTH iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr); + fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", + iCur, iHiwtr); #endif } if( pArg && pArg->out && db ){ if( pArg->shellFlgs & SHFLG_Lookaside ){ iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, + &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", + iCur, iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, + &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, + &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, + &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); } iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; + fprintf(pArg->out, "Pager Heap Usage: %d bytes\n",iCur); + iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); fprintf(pArg->out, "Page cache hits: %d\n", iCur); iHiwtr = iCur = -1; @@ -1166,18 +1195,19 @@ static int display_stats( fprintf(pArg->out, "Page cache writes: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); + fprintf(pArg->out, "Schema Heap Usage: %d bytes\n",iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); + fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",iCur); } if( pArg && pArg->out && db && pArg->pStmt ){ - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, + bReset); fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); fprintf(pArg->out, "Sort Operations: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur); @@ -1221,7 +1251,8 @@ static void display_scanstats( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain); rEstLoop *= rEst; - fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", + fprintf(pArg->out, + " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst ); } @@ -1271,7 +1302,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", "NextIfOpen", "PrevIfOpen", 0 }; - const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 }; + const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", + "Rewind", 0 }; const char *azGoto[] = { "Goto", 0 }; /* Try to figure out if this is really an EXPLAIN statement. If this @@ -1384,7 +1416,8 @@ static int shell_exec( /* Show the EXPLAIN QUERY PLAN if .eqp is on */ if( pArg && pArg->autoEQP ){ sqlite3_stmt *pExplain; - char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt)); + char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", + sqlite3_sql(pStmt)); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ @@ -3335,7 +3368,7 @@ static int do_meta_command(char *zLine, ShellState *p){ for(i=0; iout, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); + fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:""); } fprintf(p->out, "\n"); } @@ -3805,7 +3838,8 @@ static char *find_home_dir(void){ static char *home_dir = NULL; if( home_dir ) return home_dir; -#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL) +#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \ + && !defined(__RTP__) && !defined(_WRS_KERNEL) { struct passwd *pwent; uid_t uid = getuid(); From 1728bcb07f9e6784bdf5c223ffe2c035011f9123 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Nov 2014 16:49:56 +0000 Subject: [PATCH 44/71] Add the eval() SQL function extension in ext/misc/eval.c. FossilOrigin-Name: 27cf665b957f2c0ced403e3032099e80c295598f --- Makefile.in | 1 + Makefile.msc | 1 + ext/misc/eval.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ main.mk | 1 + manifest | 20 ++++---- manifest.uuid | 2 +- src/test1.c | 2 + test/misc8.test | 41 +++++++++++++++++ 8 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 ext/misc/eval.c create mode 100644 test/misc8.test diff --git a/Makefile.in b/Makefile.in index a2213e89e5..646cb39756 100644 --- a/Makefile.in +++ b/Makefile.in @@ -394,6 +394,7 @@ TESTSRC = \ TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ + $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ diff --git a/Makefile.msc b/Makefile.msc index 4173eaae27..4aaa2894a7 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -863,6 +863,7 @@ TESTSRC = \ TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ + $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\misc\ieee754.c \ diff --git a/ext/misc/eval.c b/ext/misc/eval.c new file mode 100644 index 0000000000..a5e297ad38 --- /dev/null +++ b/ext/misc/eval.c @@ -0,0 +1,119 @@ +/* +** 2014-11-10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This SQLite extension implements SQL function eval() which runs +** SQL statements recursively. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include + +/* +** Structure used to accumulate the output +*/ +struct EvalResult { + char *z; /* Accumulated output */ + const char *zSep; /* Separator */ + int szSep; /* Size of the separator string */ + int nAlloc; /* Number of bytes allocated for z[] */ + int nUsed; /* Number of bytes of z[] actually used */ +}; + +/* +** Callback from sqlite_exec() for the eval() function. +*/ +static int callback(void *pCtx, int argc, char **argv, char **colnames){ + struct EvalResult *p = (struct EvalResult*)pCtx; + int i; + for(i=0; inUsed+p->szSep+1 > p->nAlloc ){ + char *zNew; + p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; + zNew = sqlite3_realloc(p->z, p->nAlloc); + if( zNew==0 ){ + sqlite3_free(p->z); + memset(p, 0, sizeof(*p)); + return 1; + } + p->z = zNew; + } + if( p->nUsed>0 ){ + memcpy(&p->z[p->nUsed], p->zSep, p->szSep); + p->nUsed += p->szSep; + } + memcpy(&p->z[p->nUsed], z, sz); + p->nUsed += sz; + } + return 0; +} + +/* +** Implementation of the eval(X) and eval(X,Y) SQL functions. +** +** Evaluate the SQL text in X. Return the results, using string +** Y as the separator. If Y is omitted, use a single space character. +*/ +static void sqlEvalFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zSql; + sqlite3 *db; + char *zErr = 0; + int rc; + struct EvalResult x; + + memset(&x, 0, sizeof(x)); + x.zSep = " "; + zSql = (const char*)sqlite3_value_text(argv[0]); + if( zSql==0 ) return; + if( argc>1 ){ + x.zSep = (const char*)sqlite3_value_text(argv[1]); + if( x.zSep==0 ) return; + } + x.szSep = (int)strlen(x.zSep); + db = sqlite3_context_db_handle(context); + rc = sqlite3_exec(db, zSql, callback, &x, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else if( x.zSep==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(x.z); + }else{ + sqlite3_result_text(context, x.z, x.nUsed, sqlite3_free); + } +} + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_eval_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, + sqlEvalFunc, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, + sqlEvalFunc, 0, 0); + } + return rc; +} diff --git a/main.mk b/main.mk index c8bf72b48b..cac996864d 100644 --- a/main.mk +++ b/main.mk @@ -281,6 +281,7 @@ TESTSRC = \ TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ + $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ diff --git a/manifest b/manifest index 5e62c4081e..7f7fe158b9 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Shorten\sover-length\ssource\scode\slines\sin\sshell.c. -D 2014-11-10T14:42:28.114 +C Add\sthe\seval()\sSQL\sfunction\sextension\sin\sext/misc/eval.c. +D 2014-11-10T16:49:56.620 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a +F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc e31dee24038965fb6269d6d61073fd6b7e331dec +F Makefile.msc 788f1288633a0c3c3cbbe0f3e4827d033f7ba530 F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0 F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8 F VERSION d846487aff892625eb8e75960234e7285f0462fe @@ -109,6 +109,7 @@ F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c 678056a4bfcd83c4e82dea81d37543cd1d6dbee1 F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012 F ext/misc/compress.c 76e45655f4046e756064ab10c62e18f2eb846b9f +F ext/misc/eval.c 04e630bde869aa1fec6b993d40591f963be2f868 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e @@ -151,7 +152,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 3fececc835c5c23637c3e0af970e27a81a9ba476 +F main.mk 084976077a4aa3bd985154b5423e7aed88e4a2e9 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -237,7 +238,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228 -F src/test1.c cce6ad0effe8c66a62d2634d9714ffdc7372ef11 +F src/test1.c 6b0469b8e06c77b1de1d3e4a3834cf26edea9cc7 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -729,6 +730,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 +F test/misc8.test e538d122d5faacadbaa6fc02403f1e1427df684f F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 @@ -1213,7 +1215,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ecbccd0e594d22b3ae7fabc8037951dc49570bc3 -R 1a35da25c621486ba7906429ccbf946c +P 7f3819f6422badd344c1264b0cd2f2c7afe077df +R a579eb1c0cce07efa12ad49b9c702f07 U drh -Z 427c2830707548878070627d5502fc48 +Z 4009c695bea2e084a946ee86095e7182 diff --git a/manifest.uuid b/manifest.uuid index 541a9c512c..f90ad54213 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7f3819f6422badd344c1264b0cd2f2c7afe077df \ No newline at end of file +27cf665b957f2c0ced403e3032099e80c295598f \ No newline at end of file diff --git a/src/test1.c b/src/test1.c index e7a5929323..ca3b54a513 100644 --- a/src/test1.c +++ b/src/test1.c @@ -6260,6 +6260,7 @@ static int tclLoadStaticExtensionCmd( ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); + extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); @@ -6275,6 +6276,7 @@ static int tclLoadStaticExtensionCmd( } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, + { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, diff --git a/test/misc8.test b/test/misc8.test new file mode 100644 index 0000000000..06ee314b60 --- /dev/null +++ b/test/misc8.test @@ -0,0 +1,41 @@ +# 2014-11-10 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# The focus of this script is testing the "eval.c" loadable extension. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +load_static_extension db eval +do_execsql_test misc8-1.0 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(1,2,3),(4,5,6); + SELECT quote(eval('SELECT * FROM t1 ORDER BY a','-abc-')); +} {'1-abc-2-abc-3-abc-4-abc-5-abc-6'} +do_execsql_test misc8-1.1 { + SELECT quote(eval('SELECT * FROM t1 ORDER BY a')); +} {{'1 2 3 4 5 6'}} +do_catchsql_test misc8-1.2 { + SELECT quote(eval('SELECT d FROM t1 ORDER BY a')); +} {1 {no such column: d}} +do_execsql_test misc8-1.3 { + INSERT INTO t1 VALUES(7,null,9); + SELECT eval('SELECT * FROM t1 ORDER BY a',','); +} {1,2,3,4,5,6,7,,9} +do_catchsql_test misc8-1.4 { + BEGIN; + INSERT INTO t1 VALUES(10,11,12); + SELECT coalesce(b, eval('ROLLBACK')) FROM t1 ORDER BY a; +} {1 {abort due to ROLLBACK}} + + +finish_test From 923c4b35be963675b00b33a1af34dda0e6688dfa Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 10 Nov 2014 17:53:03 +0000 Subject: [PATCH 45/71] Add test file e_blobwrite.test, containing tests for the sqlite3_blob_write() interface. FossilOrigin-Name: 1df77e5f1bd82de4dc92fe28359c3e56ab3f9ed4 --- manifest | 17 ++-- manifest.uuid | 2 +- src/sqlite.h.in | 25 +++--- src/vdbeblob.c | 3 +- test/e_blobwrite.test | 204 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 22 deletions(-) create mode 100644 test/e_blobwrite.test diff --git a/manifest b/manifest index 7f7fe158b9..d14dec8c51 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\seval()\sSQL\sfunction\sextension\sin\sext/misc/eval.c. -D 2014-11-10T16:49:56.620 +C Add\stest\sfile\se_blobwrite.test,\scontaining\stests\sfor\sthe\ssqlite3_blob_write()\sinterface. +D 2014-11-10T17:53:03.345 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,7 +230,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd -F src/sqlite.h.in 5abfd7d6c9bd2054105820de5ce12b1e491b1dc9 +F src/sqlite.h.in 5531c4c69ee0a351c2aa5ad9f3f0f2424a57a9f4 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 71b0bf1a7fc55b5cb374f7579fd140e730a6e0f4 @@ -296,7 +296,7 @@ F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 F src/vdbeaux.c 9b0a251b6dfab349dd6c6efb40062eb7386b26f5 -F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef +F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 @@ -454,6 +454,7 @@ F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 +F test/e_blobwrite.test 615b405f29feb2cfb5a1f03dab7933258294fa26 F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579 F test/e_createtable.test c7e67b49e6cf92473c8fb30ab26143e9e2128cf7 F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a @@ -1215,7 +1216,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7f3819f6422badd344c1264b0cd2f2c7afe077df -R a579eb1c0cce07efa12ad49b9c702f07 -U drh -Z 4009c695bea2e084a946ee86095e7182 +P 27cf665b957f2c0ced403e3032099e80c295598f +R 37c32da8fb4d2f1d3e3ebc03749cb035 +U dan +Z 2886cb98deb64368f4cf93641ea335c8 diff --git a/manifest.uuid b/manifest.uuid index f90ad54213..719ea3ef1b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -27cf665b957f2c0ced403e3032099e80c295598f \ No newline at end of file +1df77e5f1bd82de4dc92fe28359c3e56ab3f9ed4 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index bed64bfae2..b5585defd6 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5821,21 +5821,27 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /* ** CAPI3REF: Write Data Into A BLOB Incrementally ** -** ^This function is used to write data into an open [BLOB handle] from a -** caller-supplied buffer. ^N bytes of data are copied from the buffer Z -** into the open BLOB, starting at offset iOffset. +** ^(This function is used to write data into an open [BLOB handle] from a +** caller-supplied buffer. N bytes of data are copied from the buffer Z +** into the open BLOB, starting at offset iOffset.)^ +** +** ^(On success, sqlite3_blob_write() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** ^Unless SQLITE_MISUSE is returned, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), ** this function returns [SQLITE_READONLY]. ** -** ^This function may only modify the contents of the BLOB; it is +** This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is written. ^If N is -** less than zero [SQLITE_ERROR] is returned and no data is written. -** The size of the BLOB (and hence the maximum value of N+iOffset) -** can be determined using the [sqlite3_blob_bytes()] interface. +** [SQLITE_ERROR] is returned and no data is written. The size of the +** BLOB (and hence the maximum value of N+iOffset) can be determined +** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less +** than zero [SQLITE_ERROR] is returned and no data is written. ** ** ^An attempt to write to an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred @@ -5844,9 +5850,6 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); ** have been overwritten by the statement that expired the BLOB handle ** or by other independent statements. ** -** ^(On success, sqlite3_blob_write() returns SQLITE_OK. -** Otherwise, an [error code] or an [extended error code] is returned.)^ -** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 0cf2b0652b..cf1eb59054 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -376,7 +376,6 @@ static int blobReadWrite( if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */ rc = SQLITE_ERROR; - sqlite3Error(db, SQLITE_ERROR); }else if( v==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. @@ -394,10 +393,10 @@ static int blobReadWrite( sqlite3VdbeFinalize(v); p->pStmt = 0; }else{ - db->errCode = rc; v->rc = rc; } } + sqlite3Error(db, rc); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; diff --git a/test/e_blobwrite.test b/test/e_blobwrite.test new file mode 100644 index 0000000000..a0d33336de --- /dev/null +++ b/test/e_blobwrite.test @@ -0,0 +1,204 @@ +# 2014 October 30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobwrite + +#-------------------------------------------------------------------------- +# EVIDENCE-OF: R-62898-22698 This function is used to write data into an +# open BLOB handle from a caller-supplied buffer. N bytes of data are +# copied from the buffer Z into the open BLOB, starting at offset +# iOffset. +# +set dots [string repeat . 40] +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, t TEXT); + INSERT INTO t1 VALUES(-1, $dots); + INSERT INTO t1 VALUES(-2, $dots); + INSERT INTO t1 VALUES(-3, $dots); + INSERT INTO t1 VALUES(-4, $dots); + INSERT INTO t1 VALUES(-5, $dots); + INSERT INTO t1 VALUES(-6, $dots); +} + +proc blob_write_test {tn id iOffset blob nData final} { + sqlite3_blob_open db main t1 t $id 1 B + + # EVIDENCE-OF: R-45864-01884 On success, sqlite3_blob_write() returns + # SQLITE_OK. Otherwise, an error code or an extended error code is + # returned. + # + # This block tests the SQLITE_OK case in the requirement above (the + # Tcl sqlite3_blob_write() wrapper uses an empty string in place of + # "SQLITE_OK"). The error cases are tested by the "blob_write_error_test" + # tests below. + # + set res [sqlite3_blob_write $B $iOffset $blob $nData] + uplevel [list do_test $tn.1 [list set {} $res] {}] + + sqlite3_blob_close $B + uplevel [list do_execsql_test $tn.3 "SELECT t FROM t1 WHERE a=$id" $final] +} + +set blob "0123456789012345678901234567890123456789" +blob_write_test 1.1 -1 0 $blob 10 { 0123456789.............................. } +blob_write_test 1.2 -2 8 $blob 10 { ........0123456789...................... } +blob_write_test 1.3 -3 8 $blob 1 { ........0............................... } +blob_write_test 1.4 -4 18 $blob 22 { ..................0123456789012345678901 } +blob_write_test 1.5 -5 18 $blob 0 { ........................................ } +blob_write_test 1.6 -6 0 $blob 40 { 0123456789012345678901234567890123456789 } + + +proc blob_write_error_test {tn B iOffset blob nData errcode errmsg} { + + # In cases where the underlying sqlite3_blob_write() function returns + # SQLITE_OK, the Tcl wrapper returns an empty string. If the underlying + # function returns an error, the Tcl wrapper throws an exception with + # the error code as the Tcl exception message. + # + if {$errcode=="SQLITE_OK"} { + set ret "" + set isError 0 + } else { + set ret $errcode + set isError 1 + } + + set cmd [list sqlite3_blob_write $B $iOffset $blob $nData] + uplevel [list do_test $tn.1 [subst -nocommands { + list [catch {$cmd} msg] [set msg] + }] [list $isError $ret]] + + # EVIDENCE-OF: R-34782-18311 Unless SQLITE_MISUSE is returned, this + # function sets the database connection error code and message + # accessible via sqlite3_errcode() and sqlite3_errmsg() and related + # functions. + # + if {$errcode == "SQLITE_MISUSE"} { error "test proc misuse!" } + uplevel [list do_test $tn.2 [list sqlite3_errcode db] $errcode] + uplevel [list do_test $tn.3 [list sqlite3_errmsg db] $errmsg] +} + +do_execsql_test 2.0 { + CREATE TABLE t2(a TEXT, b INTEGER PRIMARY KEY); + INSERT INTO t2 VALUES($dots, 43); + INSERT INTO t2 VALUES($dots, 44); + INSERT INTO t2 VALUES($dots, 45); +} + +# EVIDENCE-OF: R-63341-57517 If the BLOB handle passed as the first +# argument was not opened for writing (the flags parameter to +# sqlite3_blob_open() was zero), this function returns SQLITE_READONLY. +# +sqlite3_blob_open db main t2 a 43 0 B +blob_write_error_test 2.1 $B 0 $blob 10 \ + SQLITE_READONLY {attempt to write a readonly database} +sqlite3_blob_close $B + +# EVIDENCE-OF: R-29804-27366 If offset iOffset is less than N bytes from +# the end of the BLOB, SQLITE_ERROR is returned and no data is written. +# +sqlite3_blob_open db main t2 a 44 3 B +blob_write_error_test 2.2.1 $B 31 $blob 10 \ + SQLITE_ERROR {SQL logic error or missing database} + +# Make a successful write to the blob handle. This shows that the +# sqlite3_errcode() and sqlite3_errmsg() values are set even if the +# blob_write() call succeeds (see requirement in the [blob_write_error_test] +# proc). +blob_write_error_test 2.2.1 $B 30 $blob 10 SQLITE_OK {not an error} + +# EVIDENCE-OF: R-58570-38916 If N or iOffset are less than zero +# SQLITE_ERROR is returned and no data is written. +# +blob_write_error_test 2.2.2 $B 31 $blob -1 \ + SQLITE_ERROR {SQL logic error or missing database} +blob_write_error_test 2.2.3 $B 20 $blob 10 SQLITE_OK {not an error} +blob_write_error_test 2.2.4 $B -1 $blob 10 \ + SQLITE_ERROR {SQL logic error or missing database} +sqlite3_blob_close $B + +# EVIDENCE-OF: R-20958-54138 An attempt to write to an expired BLOB +# handle fails with an error code of SQLITE_ABORT. +# +do_test 2.3 { + sqlite3_blob_open db main t2 a 43 0 B + execsql { DELETE FROM t2 WHERE b=43 } +} {} +blob_write_error_test 2.3.1 $B 5 $blob 5 \ + SQLITE_ABORT {callback requested query abort} +do_test 2.3.2 { + execsql { SELECT 1, 2, 3 } + sqlite3_errcode db +} {SQLITE_OK} +blob_write_error_test 2.3.3 $B 5 $blob 5 \ + SQLITE_ABORT {callback requested query abort} +sqlite3_blob_close $B + +# EVIDENCE-OF: R-08382-59936 Writes to the BLOB that occurred before the +# BLOB handle expired are not rolled back by the expiration of the +# handle, though of course those changes might have been overwritten by +# the statement that expired the BLOB handle or by other independent +# statements. +# +# 3.1.*: not rolled back, +# 3.2.*: overwritten. +# +do_execsql_test 3.0 { + CREATE TABLE t3(i INTEGER PRIMARY KEY, j TEXT, k TEXT); + INSERT INTO t3 VALUES(1, $dots, $dots); + INSERT INTO t3 VALUES(2, $dots, $dots); + SELECT * FROM t3 WHERE i=1; +} { + 1 + ........................................ + ........................................ +} +sqlite3_blob_open db main t3 j 1 1 B +blob_write_error_test 3.1.1 $B 5 $blob 10 SQLITE_OK {not an error} +do_execsql_test 3.1.2 { + UPDATE t3 SET k = 'xyz' WHERE i=1; + SELECT * FROM t3 WHERE i=1; +} { + 1 .....0123456789......................... xyz +} +blob_write_error_test 3.1.3 $B 15 $blob 10 \ + SQLITE_ABORT {callback requested query abort} +sqlite3_blob_close $B +do_execsql_test 3.1.4 { + SELECT * FROM t3 WHERE i=1; +} { + 1 .....0123456789......................... xyz +} + +sqlite3_blob_open db main t3 j 2 1 B +blob_write_error_test 3.2.1 $B 5 $blob 10 SQLITE_OK {not an error} +do_execsql_test 3.2.2 { + UPDATE t3 SET j = 'xyz' WHERE i=2; + SELECT * FROM t3 WHERE i=2; +} { + 2 xyz ........................................ +} +blob_write_error_test 3.2.3 $B 15 $blob 10 \ + SQLITE_ABORT {callback requested query abort} +sqlite3_blob_close $B +do_execsql_test 3.2.4 { + SELECT * FROM t3 WHERE i=2; +} { + 2 xyz ........................................ +} + + + +finish_test + From de58f4fe7f33438a9d1b41666bb35a578d156885 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 10 Nov 2014 19:16:59 +0000 Subject: [PATCH 46/71] New test cases for deleting content out from under a SELECT statement. FossilOrigin-Name: 8289c3e9b47f7c2a606a88839f6bf615f8904ac2 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/misc8.test | 11 +++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d14dec8c51..762ded40f6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\sfile\se_blobwrite.test,\scontaining\stests\sfor\sthe\ssqlite3_blob_write()\sinterface. -D 2014-11-10T17:53:03.345 +C New\stest\scases\sfor\sdeleting\scontent\sout\sfrom\sunder\sa\sSELECT\sstatement. +D 2014-11-10T19:16:59.654 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -731,7 +731,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 -F test/misc8.test e538d122d5faacadbaa6fc02403f1e1427df684f +F test/misc8.test 2439b3576628bacab12cd6c73abed65de0979fd7 F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 @@ -1216,7 +1216,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 27cf665b957f2c0ced403e3032099e80c295598f -R 37c32da8fb4d2f1d3e3ebc03749cb035 -U dan -Z 2886cb98deb64368f4cf93641ea335c8 +P 1df77e5f1bd82de4dc92fe28359c3e56ab3f9ed4 +R 4b8ad408c58c17649b0e1468e9b897aa +U drh +Z 1daa82bfd52bfa0c612ccd059afbb463 diff --git a/manifest.uuid b/manifest.uuid index 719ea3ef1b..7f7352c14d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1df77e5f1bd82de4dc92fe28359c3e56ab3f9ed4 \ No newline at end of file +8289c3e9b47f7c2a606a88839f6bf615f8904ac2 \ No newline at end of file diff --git a/test/misc8.test b/test/misc8.test index 06ee314b60..da8f86970e 100644 --- a/test/misc8.test +++ b/test/misc8.test @@ -36,6 +36,17 @@ do_catchsql_test misc8-1.4 { INSERT INTO t1 VALUES(10,11,12); SELECT coalesce(b, eval('ROLLBACK')) FROM t1 ORDER BY a; } {1 {abort due to ROLLBACK}} +do_catchsql_test misc8-1.5 { + INSERT INTO t1 VALUES(10,11,12); + SELECT a, coalesce(b, eval('SELECT ''bam''')), c + FROM t1 + ORDER BY rowid; +} {0 {1 2 3 4 5 6 7 bam 9 10 11 12}} +do_catchsql_test misc8-1.6 { + SELECT a, coalesce(b, eval('DELETE FROM t1; SELECT ''bam''')), c + FROM t1 + ORDER BY rowid; +} {0 {1 2 3 4 5 6 7 bam {}}} finish_test From 47b7fc784347f2817c7669b245e5c4d65e6a3747 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 11 Nov 2014 01:33:57 +0000 Subject: [PATCH 47/71] Experimental changes that permit read operations to continue after a ROLLBACK, as long as the schema is unchanged. FossilOrigin-Name: fa6e6a9ae276cad60e9a4abc1bc23cf2809ea786 --- manifest | 41 ++++++++++++++++++---------------- manifest.uuid | 2 +- src/backup.c | 2 +- src/btree.c | 46 ++++++++++++++++++++++----------------- src/btree.h | 4 ++-- src/main.c | 9 +++++--- src/vdbe.c | 11 +++++++--- src/wal.c | 3 +-- test/capi3.test | 6 ++--- test/capi3c.test | 6 ++--- test/misc8.test | 13 +++++++++-- test/rollback.test | 4 ++-- test/savepoint.test | 2 +- test/savepoint7.test | 6 +++-- test/tkt-f777251dc7a.test | 4 +++- test/trans3.test | 2 +- 16 files changed, 95 insertions(+), 66 deletions(-) diff --git a/manifest b/manifest index 762ded40f6..5ef3b08ad7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sfor\sdeleting\scontent\sout\sfrom\sunder\sa\sSELECT\sstatement. -D 2014-11-10T19:16:59.654 +C Experimental\schanges\sthat\spermit\sread\soperations\sto\scontinue\safter\sa\nROLLBACK,\sas\slong\sas\sthe\sschema\sis\sunchanged. +D 2014-11-11T01:33:57.231 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -170,11 +170,11 @@ F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb F src/analyze.c afbcca663c3f3625340b8e30d440cd7a97ded6bc F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 -F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136 +F src/backup.c 86b311af1ad35decd1f2f0cee457d344acb83c3b F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 4a126e2066076872ab6f37f9ad116eb5f651cd38 -F src/btree.h 49b408be9c1cd41249076898e0673711071205d8 +F src/btree.c eaef0003bbfe740c62189355dabc818fc3a98999 +F src/btree.h d24fc2f3bc53be220b79b95800bdb2ee207b1089 F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -195,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c f88ed28716cbbada0f3d81479e6d43823b553de6 +F src/main.c d3310d5ed56e246bf1589e47eeaca8be582bd4b8 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -291,7 +291,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c -F src/vdbe.c d5dab22208e36e5689e9fb553aea3613921054ec +F src/vdbe.c c71d819bb34269c3dbccd92e6bb308f0ec025b5d F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 @@ -301,7 +301,7 @@ F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 -F src/wal.c 825c948066c7604a07d56e67958cdab210749016 +F src/wal.c fa090966140602f03a621f87d82ee69e66ca63b5 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/where.c 3862a1173ae2716bde12f1ab3fb649f1d85b05c2 @@ -381,9 +381,9 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738 -F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5 +F test/capi3.test f0718f4f90d0efdc980119bfbdf1d7f1541ee5ef F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 -F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32 +F test/capi3c.test fdc0d67a2cb8e8fc400d5b7735e330161ea057a2 F test/capi3d.test c84af0c49267f9c3fbf4c1c46aa647646023811e F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 @@ -731,7 +731,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 -F test/misc8.test 2439b3576628bacab12cd6c73abed65de0979fd7 +F test/misc8.test e838ec20c9c988bc94812fdb89af26409c20931b F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 @@ -794,18 +794,18 @@ F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180 F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a -F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c +F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 -F test/savepoint.test 51d3900dc071a7c2ad4248578a5925631b476313 +F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7 F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 -F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 +F test/savepoint7.test 1c8f26b1e2a4221b0214e222ce12a97a59918eb2 F test/scanstatus.test a6dd739bc4d9638e8f5c2493b518057f2b681655 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 @@ -954,7 +954,7 @@ F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30 F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00 F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9 -F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2 +F test/tkt-f777251dc7a.test 6295d235a03c82160549da4841a83dc8e758932f F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035 @@ -1049,7 +1049,7 @@ F test/trace.test 73a5508100f7fccfbc3f8018d5f6963ed478eea0 F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 -F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 +F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03 F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6 @@ -1216,7 +1216,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 1df77e5f1bd82de4dc92fe28359c3e56ab3f9ed4 -R 4b8ad408c58c17649b0e1468e9b897aa +P 8289c3e9b47f7c2a606a88839f6bf615f8904ac2 +R 703cbe5a59d81119b89af85a339f9302 +T *branch * read-after-rollback +T *sym-read-after-rollback * +T -sym-trunk * U drh -Z 1daa82bfd52bfa0c612ccd059afbb463 +Z dd5cfd6556a10d97eb1c5e11a770b9f2 diff --git a/manifest.uuid b/manifest.uuid index 7f7352c14d..0b7de2e6e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8289c3e9b47f7c2a606a88839f6bf615f8904ac2 \ No newline at end of file +fa6e6a9ae276cad60e9a4abc1bc23cf2809ea786 \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index da4303e5fd..57f7f447ea 100644 --- a/src/backup.c +++ b/src/backup.c @@ -607,7 +607,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK); + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; diff --git a/src/btree.c b/src/btree.c index 8b4a2a4f3b..70fae7c707 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2213,7 +2213,7 @@ int sqlite3BtreeClose(Btree *p){ ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ - sqlite3BtreeRollback(p, SQLITE_OK); + sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree @@ -3506,27 +3506,28 @@ int sqlite3BtreeCommit(Btree *p){ /* ** This routine sets the state to CURSOR_FAULT and the error -** code to errCode for every cursor on BtShared that pBtree -** references. +** code to errCode for every cursor on any BtShared that pBtree +** references. Or if the writeOnly flag is set to 1, then only +** trip write cursors and leave read cursors unchanged. ** -** Every cursor is tripped, including cursors that belong -** to other database connections that happen to be sharing -** the cache with pBtree. +** Every cursor is a candidate to be tripped, including cursors +** that belong to other database connections that happen to be +** sharing the cache with pBtree. ** -** This routine gets called when a rollback occurs. -** All cursors using the same cache must be tripped -** to prevent them from trying to use the btree after -** the rollback. The rollback may have deleted tables -** or moved root pages, so it is not sufficient to -** save the state of the cursor. The cursor must be -** invalidated. +** This routine gets called when a rollback occurs. The writeOnly +** flag is set to 1 if the transaction did not make any schema +** changes, in which case the read cursors can continue operating. +** If schema changes did occur in the transaction, then both read +** and write cursors must both be tripped. */ -void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ +void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); if( pBtree==0 ) return; sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; + if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ) continue; sqlite3BtreeClearCursor(p); p->eState = CURSOR_FAULT; p->skipNext = errCode; @@ -3539,27 +3540,32 @@ void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ } /* -** Rollback the transaction in progress. All cursors will be -** invalided by this operation. Any attempt to use a cursor -** that was open at the beginning of this operation will result -** in an error. +** Rollback the transaction in progress. +** +** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). +** Only write cursors are tripped if writeOnly is true but all cursors are +** tripped if writeOnly is false. Any attempt to use +** a tripped cursor will result in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeRollback(Btree *p, int tripCode){ +int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; + assert( writeOnly==1 || writeOnly==0 ); + assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); sqlite3BtreeEnter(p); if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); + if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ - sqlite3BtreeTripAllCursors(p, tripCode); + sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); } btreeIntegrity(p); diff --git a/src/btree.h b/src/btree.h index 63337b1946..a6093a5edd 100644 --- a/src/btree.h +++ b/src/btree.h @@ -83,7 +83,7 @@ int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); -int sqlite3BtreeRollback(Btree*,int); +int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); @@ -116,7 +116,7 @@ int sqlite3BtreeIncrVacuum(Btree *); int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); -void sqlite3BtreeTripAllCursors(Btree*, int); +void sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); diff --git a/src/main.c b/src/main.c index ae3753c139..f223b71f74 100644 --- a/src/main.c +++ b/src/main.c @@ -1111,13 +1111,15 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ /* ** Rollback all database files. If tripCode is not SQLITE_OK, then -** any open cursors are invalidated ("tripped" - as in "tripping a circuit +** any write cursors are invalidated ("tripped" - as in "tripping a circuit ** breaker") and made to return tripCode if there are any further -** attempts to use that cursor. +** attempts to use that cursor. Read cursors remain open and valid +** but are "saved" in case the table pages are moved around. */ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; + int schemaChange; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); @@ -1128,6 +1130,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); + schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; @@ -1135,7 +1138,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ if( sqlite3BtreeIsInTrans(p) ){ inTrans = 1; } - sqlite3BtreeRollback(p, tripCode); + sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); diff --git a/src/vdbe.c b/src/vdbe.c index f80e7787af..715862e73c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2825,11 +2825,16 @@ case OP_Savepoint: { db->isTransactionSavepoint = 0; rc = p->rc; }else{ + int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ + isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT); + sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, + isSchemaChange==0); } + }else{ + isSchemaChange = 0; } for(ii=0; iinDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); @@ -2837,7 +2842,7 @@ case OP_Savepoint: { goto abort_due_to_error; } } - if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ + if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); @@ -3234,7 +3239,7 @@ case OP_OpenWrite: { || p->readOnly==0 ); if( p->expired ){ - rc = SQLITE_ABORT; + rc = SQLITE_ABORT_ROLLBACK; break; } diff --git a/src/wal.c b/src/wal.c index d2ed293a4d..6fed8f3c6c 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2506,7 +2506,7 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); for(iFrame=pWal->hdr.mxFrame+1; - ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; + rc==SQLITE_OK && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number @@ -2525,7 +2525,6 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ } if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } - assert( rc==SQLITE_OK ); return rc; } diff --git a/test/capi3.test b/test/capi3.test index cbaa5c5e5b..9f3d6f6916 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -912,7 +912,7 @@ do_test capi3-11.9.3 { } 1 do_test capi3-11.10 { sqlite3_step $STMT -} {SQLITE_ERROR} +} {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. @@ -921,11 +921,11 @@ ifcapable !autoreset { } do_test capi3-11.11 { sqlite3_step $STMT -} {SQLITE_ROW} +} {SQLITE_DONE} do_test capi3-11.12 { sqlite3_step $STMT sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} diff --git a/test/capi3c.test b/test/capi3c.test index 6388717e00..6ab3bc24f6 100644 --- a/test/capi3c.test +++ b/test/capi3c.test @@ -863,7 +863,7 @@ do_test capi3c-11.9.3 { } 1 do_test capi3c-11.10 { sqlite3_step $STMT -} {SQLITE_ABORT} +} {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. @@ -872,11 +872,11 @@ ifcapable !autoreset { } do_test capi3c-11.11 { sqlite3_step $STMT -} {SQLITE_ROW} +} {SQLITE_DONE} do_test capi3c-11.12 { sqlite3_step $STMT sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3c-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} diff --git a/test/misc8.test b/test/misc8.test index da8f86970e..8c0c126a61 100644 --- a/test/misc8.test +++ b/test/misc8.test @@ -34,8 +34,9 @@ do_execsql_test misc8-1.3 { do_catchsql_test misc8-1.4 { BEGIN; INSERT INTO t1 VALUES(10,11,12); - SELECT coalesce(b, eval('ROLLBACK')) FROM t1 ORDER BY a; -} {1 {abort due to ROLLBACK}} + SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam'';')), c + FROM t1 ORDER BY a; +} {0 {1 2 3 4 5 6 7 bam 9}} do_catchsql_test misc8-1.5 { INSERT INTO t1 VALUES(10,11,12); SELECT a, coalesce(b, eval('SELECT ''bam''')), c @@ -47,6 +48,14 @@ do_catchsql_test misc8-1.6 { FROM t1 ORDER BY rowid; } {0 {1 2 3 4 5 6 7 bam {}}} +do_catchsql_test misc8-1.7 { + INSERT INTO t1 VALUES(1,2,3),(4,5,6),(7,null,9); + BEGIN; + CREATE TABLE t2(x); + SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam''')), c + FROM t1 + ORDER BY rowid; +} {1 {abort due to ROLLBACK}} finish_test diff --git a/test/rollback.test b/test/rollback.test index c339c5d7d6..7abafece61 100644 --- a/test/rollback.test +++ b/test/rollback.test @@ -60,11 +60,11 @@ ifcapable conflict { # do_test rollback-1.5 { sqlite3_step $STMT - } {SQLITE_ERROR} + } {SQLITE_ROW} # Restart the SELECT statement # - do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_ABORT} + do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } else { do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } diff --git a/test/savepoint.test b/test/savepoint.test index 9362c8fe19..8055e61d9e 100644 --- a/test/savepoint.test +++ b/test/savepoint.test @@ -315,7 +315,7 @@ ifcapable incrblob { do_test savepoint-5.3.2.3 { set rc [catch {seek $fd 0; read $fd} res] set rc - } {1} + } {0} do_test savepoint-5.3.3 { catchsql {RELEASE def} } {0 {}} diff --git a/test/savepoint7.test b/test/savepoint7.test index bc99187d27..908ec571f5 100644 --- a/test/savepoint7.test +++ b/test/savepoint7.test @@ -30,6 +30,7 @@ do_test savepoint7-1.1 { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; + CREATE TABLE IF NOT EXISTS t3(xyz); INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } @@ -46,7 +47,7 @@ do_test savepoint7-1.2 { RELEASE x2; } } - db eval {SELECT * FROM t2} + db eval {SELECT * FROM t2;} } {1 2 3 4 5 6 7 8 9} do_test savepoint7-1.3 { @@ -65,7 +66,7 @@ do_test savepoint7-1.3 { # queries in outer contexts. # do_test savepoint7-2.1 { - db eval {DELETE FROM t2; SAVEPOINT x1;} + db eval {DELETE FROM t2; SAVEPOINT x1; CREATE TABLE t4(abc);} set rc [catch { db eval {SELECT * FROM t1} { db eval { @@ -85,6 +86,7 @@ do_test savepoint7-2.2 { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; + CREATE TABLE t5(pqr); INSERT INTO t2 VALUES($a,$b,$c); ROLLBACK TO x2; } diff --git a/test/tkt-f777251dc7a.test b/test/tkt-f777251dc7a.test index af6f71ad96..f814d246bf 100644 --- a/test/tkt-f777251dc7a.test +++ b/test/tkt-f777251dc7a.test @@ -38,8 +38,10 @@ proc force_rollback {} { db function force_rollback force_rollback do_test tkt-f7772-1.2 { +breakpoint catchsql { BEGIN IMMEDIATE; + CREATE TABLE xyzzy(abc); SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2; } } {1 {abort due to ROLLBACK}} @@ -67,7 +69,7 @@ do_test tkt-f7772-2.2 { catchsql { SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2 } -} {1 {callback requested query abort}} +} {1 {abort due to ROLLBACK}} do_test tkt-f7772-2.3 { sqlite3_get_autocommit db } {1} diff --git a/test/trans3.test b/test/trans3.test index d5b316bec8..e828442415 100644 --- a/test/trans3.test +++ b/test/trans3.test @@ -52,7 +52,7 @@ do_test trans3-1.4 { db eval {SELECT * FROM t1} } {1 2 3 4} do_test trans3-1.5 { - db eval BEGIN + db eval {BEGIN; CREATE TABLE xyzzy(abc);} db eval {INSERT INTO t1 VALUES(5);} set ::ecode {} set x [catch { From 43f4066e102d096958e3d3211a4e44b98d6d83df Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 11 Nov 2014 12:20:35 +0000 Subject: [PATCH 48/71] Add new test file e_blobclose.test, containing tests for sqlite3_blob_close(). FossilOrigin-Name: 5a1eac2419b1462e6f21595a3fff26d9cc49d203 --- manifest | 15 ++-- manifest.uuid | 2 +- src/sqlite.h.in | 30 ++++---- test/e_blobclose.test | 171 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 24 deletions(-) create mode 100644 test/e_blobclose.test diff --git a/manifest b/manifest index 762ded40f6..089246851e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sfor\sdeleting\scontent\sout\sfrom\sunder\sa\sSELECT\sstatement. -D 2014-11-10T19:16:59.654 +C Add\snew\stest\sfile\se_blobclose.test,\scontaining\stests\sfor\ssqlite3_blob_close(). +D 2014-11-11T12:20:35.141 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,7 +230,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd -F src/sqlite.h.in 5531c4c69ee0a351c2aa5ad9f3f0f2424a57a9f4 +F src/sqlite.h.in 0e6612f84936cca29166f2c66068e0227a13fdf6 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 71b0bf1a7fc55b5cb374f7579fd140e730a6e0f4 @@ -453,6 +453,7 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 +F test/e_blobclose.test df756753f571bc30e42e3a6cba2807576e49e716 F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 F test/e_blobwrite.test 615b405f29feb2cfb5a1f03dab7933258294fa26 F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579 @@ -1216,7 +1217,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 1df77e5f1bd82de4dc92fe28359c3e56ab3f9ed4 -R 4b8ad408c58c17649b0e1468e9b897aa -U drh -Z 1daa82bfd52bfa0c612ccd059afbb463 +P 8289c3e9b47f7c2a606a88839f6bf615f8904ac2 +R 5495040e5aa9cb71b6dcdaffde6bd935 +U dan +Z 0fca1fa0cec9033f254d39e73d650ca5 diff --git a/manifest.uuid b/manifest.uuid index 7f7352c14d..dbade0f26a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8289c3e9b47f7c2a606a88839f6bf615f8904ac2 \ No newline at end of file +5a1eac2419b1462e6f21595a3fff26d9cc49d203 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index b5585defd6..2812bf511d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5754,24 +5754,22 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle ** -** ^Closes an open [BLOB handle]. +** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed +** unconditionally. Even if this routine returns an error code, the +** handle is still closed.)^ ** -** ^Closing a BLOB shall cause the current transaction to commit -** if there are no other BLOBs, no pending prepared statements, and the -** database connection is in [autocommit mode]. -** ^If any writes were made to the BLOB, they might be held in cache -** until the close operation if they will fit. +** ^If the blob handle being closed was opened for read-write access, and if +** the database is in auto-commit mode and there are no other open read-write +** blob handles or active write statements, the current transaction is +** committed. ^If an error occurs while committing the transaction, an error +** code is returned and the transaction rolled back. ** -** ^(Closing the BLOB often forces the changes -** out to disk and so if any I/O errors occur, they will likely occur -** at the time when the BLOB is closed. Any errors that occur during -** closing are reported as a non-zero return value.)^ -** -** ^(The BLOB is closed unconditionally. Even if this routine returns -** an error code, the BLOB is still closed.)^ -** -** ^Calling this routine with a null pointer (such as would be returned -** by a failed call to [sqlite3_blob_open()]) is a harmless no-op. +** Calling this function with an argument that is not a NULL pointer or an +** open blob handle results in undefined behaviour. ^Calling this routine +** with a null pointer (such as would be returned by a failed call to +** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function +** is passed a valid open blob handle, the values returned by the +** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. */ int sqlite3_blob_close(sqlite3_blob *); diff --git a/test/e_blobclose.test b/test/e_blobclose.test new file mode 100644 index 0000000000..a5d432d3b5 --- /dev/null +++ b/test/e_blobclose.test @@ -0,0 +1,171 @@ +# 2014 October 30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobclose + +set dots [string repeat . 40] +do_execsql_test 1.0 { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS); + INSERT INTO x1 VALUES(-1, $dots); + INSERT INTO x1 VALUES(-10, $dots); + INSERT INTO x1 VALUES(-100, $dots); + INSERT INTO x1 VALUES(-1000, $dots); + INSERT INTO x1 VALUES(-10000, $dots); +} + +# EVIDENCE-OF: R-03145-46390 This function closes an open BLOB handle. +# +# It's not clear how to test that a blob handle really is closed. +# Attempting to use a closed blob handle will likely crash the process. +# Assume here that if the SHARED lock on the db file is released, +# the blob handle has been closed. +# +do_execsql_test 1.1 { PRAGMA lock_status } {main unlocked temp closed} +sqlite3_blob_open db main x1 b -1 0 B +do_execsql_test 1.2 { PRAGMA lock_status } {main shared temp closed} +sqlite3_blob_close $B +do_execsql_test 1.3 { PRAGMA lock_status } {main unlocked temp closed} + + +# EVIDENCE-OF: R-34027-00617 If the blob handle being closed was opened +# for read-write access, and if the database is in auto-commit mode and +# there are no other open read-write blob handles or active write +# statements, the current transaction is committed. +# +# 2.1.*: Transaction is not committed if there are other open +# read-write blob handles. +# +# 2.2.*: Transaction is not committed if not in auto-commit mode. +# +# 2.3.*: Active write statements. +# +do_test 2.1.1 { + sqlite3_blob_open db main x1 b -100 1 B1 + sqlite3_blob_open db main x1 b -1000 1 B2 + sqlite3_blob_open db main x1 b -10000 1 B3 + sqlite3_blob_open db main x1 b -10000 0 B4 ;# B4 is read-only! + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.1.2 { + sqlite3_blob_close $B1 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.1.3 { + sqlite3_blob_close $B2 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.1.4 { + sqlite3_blob_close $B3 + execsql { PRAGMA lock_status } +} {main shared temp closed} +do_test 2.1.5 { + sqlite3_blob_close $B4 + execsql { PRAGMA lock_status } +} {main unlocked temp closed} + +do_test 2.2.1 { + sqlite3_blob_open db main x1 b -100 1 B1 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.2.2 { + execsql { BEGIN } + sqlite3_blob_close $B1 + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.2.3 { + execsql { COMMIT } + execsql { PRAGMA lock_status } +} {main unlocked temp closed} + +proc val {} { + sqlite3_blob_close $::B + db eval { PRAGMA lock_status } +} +db func val val +do_test 2.3.1 { + sqlite3_blob_open db main x1 b -100 1 B + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.3.2 { + execsql { INSERT INTO x1 VALUES(15, val()) } + execsql { PRAGMA lock_status } +} {main unlocked temp closed} +do_test 2.3.3 { + execsql { SELECT * FROM x1 WHERE a = 15 } +} {15 {main reserved temp closed}} + +# A reader does not inhibit commit. +do_test 2.3.4 { + sqlite3_blob_open db main x1 b -100 1 B + execsql { PRAGMA lock_status } +} {main reserved temp closed} +do_test 2.3.5 { + execsql { SELECT a, val() FROM x1 LIMIT 1 } +} {-10000 {main shared temp closed}} + + +do_test 3.1 { + sqlite3_blob_open db main x1 b -10 1 B + execsql { + INSERT INTO x1 VALUES(1, 'abc'); + SELECT * FROM x1 WHERE a=1; + } +} {1 abc} +do_test 3.2 { + sqlite3_blob_write $B 0 "abcdefghij" 10 + execsql { SELECT * FROM x1 WHERE a=-10 } +} {-10 abcdefghij..............................} + +do_test 3.3 { + sqlite3 db2 test.db + execsql { BEGIN ; SELECT * FROM x1 } db2 + sqlite3_blob_close $B +} {SQLITE_BUSY} + +# EVIDENCE-OF: R-41959-38737 Otherwise, if this function is passed a +# valid open blob handle, the values returned by the sqlite3_errcode() +# and sqlite3_errmsg() functions are set before returning. +# +do_test 3.4 { + list [sqlite3_errcode db] [sqlite3_errmsg db] +} {SQLITE_BUSY {database is locked}} + +# EVIDENCE-OF: R-37801-37633 The BLOB handle is closed unconditionally. +# Even if this routine returns an error code, the handle is still +# closed. +# +# Test that the lock has been released. Assume this means the handle +# is closed, even though blob_close() returned SQLITE_BUSY. +# +do_execsql_test 3.4 { PRAGMA lock_status } {main unlocked temp closed} + +# EVIDENCE-OF: R-35111-05628 If an error occurs while committing the +# transaction, an error code is returned and the transaction rolled +# back. +# +# Row 1 is removed (it was inserted this transaction) and row -10 +# is restored to its original state. Transaction has been rolled back. +# +do_execsql_test 3.5 { + SELECT * FROM x1 WHERE a IN (1, -10); +} {-10 ........................................} + +# EVIDENCE-OF: R-25894-51060 Calling this routine with a null pointer +# (such as would be returned by a failed call to sqlite3_blob_open()) is +# a harmless no-op. +# +do_test 4.0 { sqlite3_blob_close 0 } {} + +finish_test + From 2d8e3caa2e54c4856db48998ba71a2c56b47e956 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 11 Nov 2014 16:11:04 +0000 Subject: [PATCH 49/71] Add tests for sqlite3_blob_bytes(). FossilOrigin-Name: a066a3832a7c6de65c3016e77e49ac00e09db749 --- manifest | 14 ++++---- manifest.uuid | 2 +- test/e_blobbytes.test | 76 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 test/e_blobbytes.test diff --git a/manifest b/manifest index 51c9f2ee01..c994394f6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Permit\sread\soperations\sto\scontinue\safter\sa\sROLLBACK\sas\slong\sas\sthe\sschema\ndoes\snot\schange. -D 2014-11-11T14:59:31.172 +C Add\stests\sfor\ssqlite3_blob_bytes(). +D 2014-11-11T16:11:04.911 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -453,6 +453,7 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 +F test/e_blobbytes.test 9bea1d3e2b20f3010b04abba58f6ba172301f49f F test/e_blobclose.test df756753f571bc30e42e3a6cba2807576e49e716 F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8 F test/e_blobwrite.test 615b405f29feb2cfb5a1f03dab7933258294fa26 @@ -1217,8 +1218,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 5a1eac2419b1462e6f21595a3fff26d9cc49d203 fa6e6a9ae276cad60e9a4abc1bc23cf2809ea786 -R 90c0902351a625ca12308516be116ef0 -T +closed fa6e6a9ae276cad60e9a4abc1bc23cf2809ea786 -U drh -Z 3e9637efba5697b65ccb54a130a31d2a +P b5df5ac0529f7b0d1e880a7f4a307e7d77b7fa6c +R be9d88d05dd4414f44a05008ae6eba4c +U dan +Z 2fc1cd52a3184d003db0d33d71426d71 diff --git a/manifest.uuid b/manifest.uuid index 699edcd220..0982b7b00f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b5df5ac0529f7b0d1e880a7f4a307e7d77b7fa6c \ No newline at end of file +a066a3832a7c6de65c3016e77e49ac00e09db749 \ No newline at end of file diff --git a/test/e_blobbytes.test b/test/e_blobbytes.test new file mode 100644 index 0000000000..a6283ab852 --- /dev/null +++ b/test/e_blobbytes.test @@ -0,0 +1,76 @@ +# 2014 October 30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix e_blobbytes + +do_execsql_test 1.0 { + CREATE TABLE q1(r INTEGER PRIMARY KEY, s TEXT); + WITH d(a, b) AS ( + SELECT 0, '' + UNION ALL + SELECT a+1, b||'.' FROM d WHERE a<10000 + ) + INSERT INTO q1 SELECT * FROM d; +} + + +# EVIDENCE-OF: R-07796-55423 Returns the size in bytes of the BLOB +# accessible via the successfully opened BLOB handle in its only +# argument. +# +proc check_blob_size {tn rowid bytes} { + uplevel [list do_test $tn [subst -nocommands { + sqlite3_blob_open db main q1 s $rowid 0 B + set res [sqlite3_blob_bytes [set B]] + sqlite3_blob_close [set B] + set res + }] $bytes] +} +check_blob_size 1.1 43 43 +check_blob_size 1.2 391 391 +check_blob_size 1.3 6349 6349 +check_blob_size 1.4 2621 2621 +check_blob_size 1.5 7771 7771 +check_blob_size 1.6 7949 7949 +check_blob_size 1.7 4374 4374 +check_blob_size 1.8 2578 2578 +check_blob_size 1.9 7004 7004 +check_blob_size 1.10 2180 2180 +check_blob_size 1.11 3796 3796 +check_blob_size 1.12 7101 7101 +check_blob_size 1.13 7449 7449 +check_blob_size 1.14 7224 7224 +check_blob_size 1.15 3038 3038 +check_blob_size 1.16 1083 1083 +check_blob_size 1.17 5157 5157 +check_blob_size 1.18 6686 6686 +check_blob_size 1.19 6592 6592 +check_blob_size 1.20 0 0 + + +# EVIDENCE-OF: R-53088-19343 The incremental blob I/O routines can only +# read or overwriting existing blob content; they cannot change the size +# of a blob. +# +# Also demonstrated in other e_blobXXX.test files. +# +do_test 2.1 { + sqlite3_blob_open db main q1 s 86 1 B + list [catch { sqlite3_blob_write $B 86 "1" 1 } msg] $msg +} {1 SQLITE_ERROR} +sqlite3_blob_close $B + +finish_test + + From bfa395d085fbadc6436bb4baf40e96c384c64463 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Tue, 11 Nov 2014 19:07:56 +0000 Subject: [PATCH 50/71] Remove some calls to the 'breakpoint' test command. FossilOrigin-Name: 1412fcc480799ecbd68d44dd18d5bad40e20ccf1 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- test/capi3d.test | 1 - test/corruptH.test | 1 - test/sort2.test | 1 - test/tkt-f777251dc7a.test | 1 - 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index c994394f6f..97192e581d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sfor\ssqlite3_blob_bytes(). -D 2014-11-11T16:11:04.911 +C Remove\ssome\scalls\sto\sthe\s'breakpoint'\stest\scommand. +D 2014-11-11T19:07:56.372 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -384,7 +384,7 @@ F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738 F test/capi3.test f0718f4f90d0efdc980119bfbdf1d7f1541ee5ef F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test fdc0d67a2cb8e8fc400d5b7735e330161ea057a2 -F test/capi3d.test c84af0c49267f9c3fbf4c1c46aa647646023811e +F test/capi3d.test a82b6321c50a1cfc848e386fa2c851893606f68c F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763 @@ -423,7 +423,7 @@ F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 -F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb +F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067 F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243 F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 @@ -860,7 +860,7 @@ F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 F test/sort.test c4400e7533748f6bd7413851ff148645e82b9e2d -F test/sort2.test 269f4f50c6e468cc32b302ae7ff0add8338ec6de +F test/sort2.test 84a92eebf697feee9c6697746918c7d67373eea1 F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2 F test/sort4.test 6c37d85f7cd28d50cce222fcab84ccd771e105cb F test/sort5.test a448240a42b49239edc00f85d6d7ac7a1b261e1f @@ -956,7 +956,7 @@ F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30 F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00 F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9 -F test/tkt-f777251dc7a.test 6295d235a03c82160549da4841a83dc8e758932f +F test/tkt-f777251dc7a.test d1a8fc3eefb7a9e64d19ff24d5c8c94c34a632fb F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035 @@ -1218,7 +1218,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P b5df5ac0529f7b0d1e880a7f4a307e7d77b7fa6c -R be9d88d05dd4414f44a05008ae6eba4c -U dan -Z 2fc1cd52a3184d003db0d33d71426d71 +P a066a3832a7c6de65c3016e77e49ac00e09db749 +R e8fc41a7f82a02ab8618a341f7ef7735 +U mistachkin +Z 90417f4c358533080e79b8017b4e7453 diff --git a/manifest.uuid b/manifest.uuid index 0982b7b00f..f90bf2d8c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a066a3832a7c6de65c3016e77e49ac00e09db749 \ No newline at end of file +1412fcc480799ecbd68d44dd18d5bad40e20ccf1 \ No newline at end of file diff --git a/test/capi3d.test b/test/capi3d.test index fb8abe86d2..1459c5abfe 100644 --- a/test/capi3d.test +++ b/test/capi3d.test @@ -155,7 +155,6 @@ do_execsql_test capi3d-4.1 { } do_test capi3d-4.2.1 { - breakpoint set ::s1 [sqlite3_prepare_v2 db "ROLLBACK" -1 notused] sqlite3_step $::s1 } {SQLITE_DONE} diff --git a/test/corruptH.test b/test/corruptH.test index ee2bb1ee48..5c83cb3b90 100644 --- a/test/corruptH.test +++ b/test/corruptH.test @@ -64,7 +64,6 @@ do_test 1.2 { } {} do_test 1.3 { -breakpoint db eval { PRAGMA secure_delete=1 } list [catch { db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { diff --git a/test/sort2.test b/test/sort2.test index 29001f0099..a4c55c9f24 100644 --- a/test/sort2.test +++ b/test/sort2.test @@ -62,7 +62,6 @@ foreach {tn script} { do_execsql_test $tn.2.4 { PRAGMA integrity_check } {ok} - breakpoint do_execsql_test $tn.3 { PRAGMA cache_size = 5; WITH r(x,y) AS ( diff --git a/test/tkt-f777251dc7a.test b/test/tkt-f777251dc7a.test index f814d246bf..b91e438da5 100644 --- a/test/tkt-f777251dc7a.test +++ b/test/tkt-f777251dc7a.test @@ -38,7 +38,6 @@ proc force_rollback {} { db function force_rollback force_rollback do_test tkt-f7772-1.2 { -breakpoint catchsql { BEGIN IMMEDIATE; CREATE TABLE xyzzy(abc); From 85fabf1444ff49f7f1e2060d0b93d9df6f8f9f6f Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 11 Nov 2014 22:55:26 +0000 Subject: [PATCH 51/71] This is a cherry-pick of version [b5df5ac052]. FossilOrigin-Name: d4b2d5d066891e06f2bf4337902b44b000fa9fd2 --- manifest | 40 ++++++++++++++++------------------ manifest.uuid | 2 +- src/backup.c | 2 +- src/btree.c | 46 ++++++++++++++++++++++----------------- src/btree.h | 4 ++-- src/main.c | 9 +++++--- src/vdbe.c | 11 +++++++--- src/wal.c | 3 +-- test/capi3.test | 6 ++--- test/capi3c.test | 6 ++--- test/rollback.test | 4 ++-- test/savepoint.test | 2 +- test/savepoint7.test | 6 +++-- test/tkt-f777251dc7a.test | 4 +++- test/trans3.test | 2 +- 15 files changed, 81 insertions(+), 66 deletions(-) diff --git a/manifest b/manifest index 8688f8549f..0e3e6a9ff4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s3.8.7.1 -D 2014-10-29T13:59:56.070 +C This\sis\sa\scherry-pick\sof\sversion\s[b5df5ac052]. +D 2014-11-11T22:55:26.891 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -169,11 +169,11 @@ F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb F src/analyze.c 8c322e1ecc08909526dbd5ab4421889d05f2263d F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9 F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2 -F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e +F src/backup.c 8cdfeb0c8a6d8bdad3faefae418eb3dc767051b6 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 1b1123cba0c65caa0baa51e71b8c089e3167c3ed -F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8 +F src/btree.c 944b84f72fd9048acde31400d89439976bf766b0 +F src/btree.h 97c4d0ef860f151e096e97eef78b87f7b4a8d899 F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -194,7 +194,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c bbe872b0ac0007bed0ebe1936fc493b039ad4f51 +F src/main.c 1bdabb62205af168498a17460bdb7533b2a4a915 F src/malloc.c 3c3ac67969612493d435e14b6832793209afd2ec F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 5a1afb571853ddb911d698ac996bc4fd8ddf1eed +F src/vdbe.c 4c77cdf16be330bd5227691919332b42d557e211 F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h e2a060a55ee18a6ab973353a5e2ec7ee569bf787 F src/vdbeapi.c 37a6c6ae284a97bcace365f2f0a225680c0499d9 @@ -299,7 +299,7 @@ F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c cb0c194303fea276b48d7d4b6d970b5a96bde8de -F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 +F src/wal.c 73051f1222321712fa4280c495780ba81d302dad F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/where.c 2947912f1f3d6a7766fe087fd532a5d688d745b1 @@ -378,9 +378,9 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738 -F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5 +F test/capi3.test f0718f4f90d0efdc980119bfbdf1d7f1541ee5ef F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 -F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32 +F test/capi3c.test fdc0d67a2cb8e8fc400d5b7735e330161ea057a2 F test/capi3d.test c84af0c49267f9c3fbf4c1c46aa647646023811e F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 @@ -785,18 +785,18 @@ F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180 F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a -F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c +F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 -F test/savepoint.test 51d3900dc071a7c2ad4248578a5925631b476313 +F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7 F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 -F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 +F test/savepoint7.test 1c8f26b1e2a4221b0214e222ce12a97a59918eb2 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -943,7 +943,7 @@ F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30 F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00 F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9 -F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2 +F test/tkt-f777251dc7a.test 6295d235a03c82160549da4841a83dc8e758932f F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035 @@ -1038,7 +1038,7 @@ F test/trace.test 73a5508100f7fccfbc3f8018d5f6963ed478eea0 F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 -F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 +F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03 F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6 @@ -1204,10 +1204,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 83afe23e553e802c0947c80d0ffdd120423e7c52 -R 5381895dceb9bc7ad4d425f399561cb7 -T +bgcolor * #d0c0ff -T +sym-release * -T +sym-version-3.8.7.1 * +P 3b7b72c4685aa5cf5e675c2c47ebec10d9704221 +Q +b5df5ac0529f7b0d1e880a7f4a307e7d77b7fa6c +R 27a95de33658c36b59b93f043d249813 U drh -Z e5ce942eb65e60b92fcaefcb5b84039b +Z ea313ee60fabf91291f912ad6dcdc285 diff --git a/manifest.uuid b/manifest.uuid index 1787d659c6..983840bd0e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3b7b72c4685aa5cf5e675c2c47ebec10d9704221 \ No newline at end of file +d4b2d5d066891e06f2bf4337902b44b000fa9fd2 \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index 92c6334bde..9fcb669106 100644 --- a/src/backup.c +++ b/src/backup.c @@ -597,7 +597,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK); + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; diff --git a/src/btree.c b/src/btree.c index 758dfe6335..9d7a05157d 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2171,7 +2171,7 @@ int sqlite3BtreeClose(Btree *p){ ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ - sqlite3BtreeRollback(p, SQLITE_OK); + sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree @@ -3464,27 +3464,28 @@ int sqlite3BtreeCommit(Btree *p){ /* ** This routine sets the state to CURSOR_FAULT and the error -** code to errCode for every cursor on BtShared that pBtree -** references. +** code to errCode for every cursor on any BtShared that pBtree +** references. Or if the writeOnly flag is set to 1, then only +** trip write cursors and leave read cursors unchanged. ** -** Every cursor is tripped, including cursors that belong -** to other database connections that happen to be sharing -** the cache with pBtree. +** Every cursor is a candidate to be tripped, including cursors +** that belong to other database connections that happen to be +** sharing the cache with pBtree. ** -** This routine gets called when a rollback occurs. -** All cursors using the same cache must be tripped -** to prevent them from trying to use the btree after -** the rollback. The rollback may have deleted tables -** or moved root pages, so it is not sufficient to -** save the state of the cursor. The cursor must be -** invalidated. +** This routine gets called when a rollback occurs. The writeOnly +** flag is set to 1 if the transaction did not make any schema +** changes, in which case the read cursors can continue operating. +** If schema changes did occur in the transaction, then both read +** and write cursors must both be tripped. */ -void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ +void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); if( pBtree==0 ) return; sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; + if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ) continue; sqlite3BtreeClearCursor(p); p->eState = CURSOR_FAULT; p->skipNext = errCode; @@ -3497,27 +3498,32 @@ void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ } /* -** Rollback the transaction in progress. All cursors will be -** invalided by this operation. Any attempt to use a cursor -** that was open at the beginning of this operation will result -** in an error. +** Rollback the transaction in progress. +** +** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). +** Only write cursors are tripped if writeOnly is true but all cursors are +** tripped if writeOnly is false. Any attempt to use +** a tripped cursor will result in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeRollback(Btree *p, int tripCode){ +int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; + assert( writeOnly==1 || writeOnly==0 ); + assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); sqlite3BtreeEnter(p); if( tripCode==SQLITE_OK ){ rc = tripCode = saveAllCursors(pBt, 0, 0); + if( rc ) writeOnly = 0; }else{ rc = SQLITE_OK; } if( tripCode ){ - sqlite3BtreeTripAllCursors(p, tripCode); + sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); } btreeIntegrity(p); diff --git a/src/btree.h b/src/btree.h index 38abdca1a2..f724269a3e 100644 --- a/src/btree.h +++ b/src/btree.h @@ -83,7 +83,7 @@ int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); -int sqlite3BtreeRollback(Btree*,int); +int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); @@ -116,7 +116,7 @@ int sqlite3BtreeIncrVacuum(Btree *); int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); -void sqlite3BtreeTripAllCursors(Btree*, int); +void sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); diff --git a/src/main.c b/src/main.c index ea03f2639f..46b3ccdf58 100644 --- a/src/main.c +++ b/src/main.c @@ -1016,13 +1016,15 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ /* ** Rollback all database files. If tripCode is not SQLITE_OK, then -** any open cursors are invalidated ("tripped" - as in "tripping a circuit +** any write cursors are invalidated ("tripped" - as in "tripping a circuit ** breaker") and made to return tripCode if there are any further -** attempts to use that cursor. +** attempts to use that cursor. Read cursors remain open and valid +** but are "saved" in case the table pages are moved around. */ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int i; int inTrans = 0; + int schemaChange; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); @@ -1033,6 +1035,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); + schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; @@ -1040,7 +1043,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ if( sqlite3BtreeIsInTrans(p) ){ inTrans = 1; } - sqlite3BtreeRollback(p, tripCode); + sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); diff --git a/src/vdbe.c b/src/vdbe.c index 88fadb023e..6e152cd27e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2822,11 +2822,16 @@ case OP_Savepoint: { db->isTransactionSavepoint = 0; rc = p->rc; }else{ + int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ + isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT); + sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, + isSchemaChange==0); } + }else{ + isSchemaChange = 0; } for(ii=0; iinDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); @@ -2834,7 +2839,7 @@ case OP_Savepoint: { goto abort_due_to_error; } } - if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){ + if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); db->flags = (db->flags | SQLITE_InternChanges); @@ -3231,7 +3236,7 @@ case OP_OpenWrite: { || p->readOnly==0 ); if( p->expired ){ - rc = SQLITE_ABORT; + rc = SQLITE_ABORT_ROLLBACK; break; } diff --git a/src/wal.c b/src/wal.c index c0861d5be7..24540a2cd5 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2506,7 +2506,7 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); for(iFrame=pWal->hdr.mxFrame+1; - ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; + rc==SQLITE_OK && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number @@ -2525,7 +2525,6 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ } if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } - assert( rc==SQLITE_OK ); return rc; } diff --git a/test/capi3.test b/test/capi3.test index cbaa5c5e5b..9f3d6f6916 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -912,7 +912,7 @@ do_test capi3-11.9.3 { } 1 do_test capi3-11.10 { sqlite3_step $STMT -} {SQLITE_ERROR} +} {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. @@ -921,11 +921,11 @@ ifcapable !autoreset { } do_test capi3-11.11 { sqlite3_step $STMT -} {SQLITE_ROW} +} {SQLITE_DONE} do_test capi3-11.12 { sqlite3_step $STMT sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} diff --git a/test/capi3c.test b/test/capi3c.test index 6388717e00..6ab3bc24f6 100644 --- a/test/capi3c.test +++ b/test/capi3c.test @@ -863,7 +863,7 @@ do_test capi3c-11.9.3 { } 1 do_test capi3c-11.10 { sqlite3_step $STMT -} {SQLITE_ABORT} +} {SQLITE_ROW} ifcapable !autoreset { # If SQLITE_OMIT_AUTORESET is defined, then the statement must be # reset() before it can be passed to step() again. @@ -872,11 +872,11 @@ ifcapable !autoreset { } do_test capi3c-11.11 { sqlite3_step $STMT -} {SQLITE_ROW} +} {SQLITE_DONE} do_test capi3c-11.12 { sqlite3_step $STMT sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3c-11.13 { sqlite3_finalize $STMT } {SQLITE_OK} diff --git a/test/rollback.test b/test/rollback.test index c339c5d7d6..7abafece61 100644 --- a/test/rollback.test +++ b/test/rollback.test @@ -60,11 +60,11 @@ ifcapable conflict { # do_test rollback-1.5 { sqlite3_step $STMT - } {SQLITE_ERROR} + } {SQLITE_ROW} # Restart the SELECT statement # - do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_ABORT} + do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } else { do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK} } diff --git a/test/savepoint.test b/test/savepoint.test index 9362c8fe19..8055e61d9e 100644 --- a/test/savepoint.test +++ b/test/savepoint.test @@ -315,7 +315,7 @@ ifcapable incrblob { do_test savepoint-5.3.2.3 { set rc [catch {seek $fd 0; read $fd} res] set rc - } {1} + } {0} do_test savepoint-5.3.3 { catchsql {RELEASE def} } {0 {}} diff --git a/test/savepoint7.test b/test/savepoint7.test index bc99187d27..908ec571f5 100644 --- a/test/savepoint7.test +++ b/test/savepoint7.test @@ -30,6 +30,7 @@ do_test savepoint7-1.1 { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; + CREATE TABLE IF NOT EXISTS t3(xyz); INSERT INTO t2 VALUES($a,$b,$c); RELEASE x2; } @@ -46,7 +47,7 @@ do_test savepoint7-1.2 { RELEASE x2; } } - db eval {SELECT * FROM t2} + db eval {SELECT * FROM t2;} } {1 2 3 4 5 6 7 8 9} do_test savepoint7-1.3 { @@ -65,7 +66,7 @@ do_test savepoint7-1.3 { # queries in outer contexts. # do_test savepoint7-2.1 { - db eval {DELETE FROM t2; SAVEPOINT x1;} + db eval {DELETE FROM t2; SAVEPOINT x1; CREATE TABLE t4(abc);} set rc [catch { db eval {SELECT * FROM t1} { db eval { @@ -85,6 +86,7 @@ do_test savepoint7-2.2 { db eval {SELECT * FROM t1} { db eval { SAVEPOINT x2; + CREATE TABLE t5(pqr); INSERT INTO t2 VALUES($a,$b,$c); ROLLBACK TO x2; } diff --git a/test/tkt-f777251dc7a.test b/test/tkt-f777251dc7a.test index af6f71ad96..f814d246bf 100644 --- a/test/tkt-f777251dc7a.test +++ b/test/tkt-f777251dc7a.test @@ -38,8 +38,10 @@ proc force_rollback {} { db function force_rollback force_rollback do_test tkt-f7772-1.2 { +breakpoint catchsql { BEGIN IMMEDIATE; + CREATE TABLE xyzzy(abc); SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2; } } {1 {abort due to ROLLBACK}} @@ -67,7 +69,7 @@ do_test tkt-f7772-2.2 { catchsql { SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2 } -} {1 {callback requested query abort}} +} {1 {abort due to ROLLBACK}} do_test tkt-f7772-2.3 { sqlite3_get_autocommit db } {1} diff --git a/test/trans3.test b/test/trans3.test index d5b316bec8..e828442415 100644 --- a/test/trans3.test +++ b/test/trans3.test @@ -52,7 +52,7 @@ do_test trans3-1.4 { db eval {SELECT * FROM t1} } {1 2 3 4} do_test trans3-1.5 { - db eval BEGIN + db eval {BEGIN; CREATE TABLE xyzzy(abc);} db eval {INSERT INTO t1 VALUES(5);} set ::ecode {} set x [catch { From 51a205410c5039849bc3179a6a1b1c136494f4da Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Nov 2014 14:07:28 +0000 Subject: [PATCH 52/71] Make sure that NULL results from OP_Column are fully and completely NULL and do not have the MEM_Ephem bit set. Fix for ticket [094d39a4c95ee4]. FossilOrigin-Name: e1017745e183f5d7429ce787ec2feef946a24f0f --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/vdbe.c | 2 +- test/table.test | 18 +++++++++++++++++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 0e3e6a9ff4..e652361975 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C This\sis\sa\scherry-pick\sof\sversion\s[b5df5ac052]. -D 2014-11-11T22:55:26.891 +C Make\ssure\sthat\sNULL\sresults\sfrom\sOP_Column\sare\sfully\sand\scompletely\sNULL\sand\sdo\snot\shave\sthe\sMEM_Ephem\sbit\sset.\sFix\sfor\sticket\s[094d39a4c95ee4]. +D 2014-11-12T14:07:28.525 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 4c77cdf16be330bd5227691919332b42d557e211 +F src/vdbe.c 0b4ffa1aeeb7a10fefc6497dd0159bf5d9828464 F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h e2a060a55ee18a6ab973353a5e2ec7ee569bf787 F src/vdbeapi.c 37a6c6ae284a97bcace365f2f0a225680c0499d9 @@ -873,7 +873,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 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 @@ -1204,8 +1204,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 3b7b72c4685aa5cf5e675c2c47ebec10d9704221 -Q +b5df5ac0529f7b0d1e880a7f4a307e7d77b7fa6c -R 27a95de33658c36b59b93f043d249813 +P d4b2d5d066891e06f2bf4337902b44b000fa9fd2 +Q +42705fd7d892c4fdfb95fbbb468c99569beece25 +R 55a6f98cd186254776492ca00fba4393 U drh -Z ea313ee60fabf91291f912ad6dcdc285 +Z efc3d14840732f527ab6a674cff641f8 diff --git a/manifest.uuid b/manifest.uuid index 983840bd0e..cfac283fb9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d4b2d5d066891e06f2bf4337902b44b000fa9fd2 \ No newline at end of file +e1017745e183f5d7429ce787ec2feef946a24f0f \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 6e152cd27e..9462bd71f8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2298,7 +2298,7 @@ case OP_Column: { pC->payloadSize = pC->szRow = avail = pReg->n; pC->aRow = (u8*)pReg->z; }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ diff --git a/test/table.test b/test/table.test index 656884ca73..69f105aa6c 100644 --- a/test/table.test +++ b/test/table.test @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # -# $Id: table.test,v 1.53 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -773,4 +772,21 @@ do_catchsql_test table-16.7 { INSERT INTO t16 DEFAULT VALUES; } {1 {unknown function: group_concat()}} +# Ticket [https://www.sqlite.org/src/info/094d39a4c95ee4abbc417f04214617675ba15c63] +# describes a assertion fault that occurs on a CREATE TABLE .. AS SELECT statement. +# the following test verifies that the problem has been fixed. +# +do_execsql_test table-17.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a TEXT); + INSERT INTO t1(a) VALUES(1),(2); + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(x TEXT, y TEXT); + INSERT INTO t2(x,y) VALUES(3,4); + DROP TABLE IF EXISTS t3; + CREATE TABLE t3 AS + SELECT a AS p, coalesce(y,a) AS q FROM t1 LEFT JOIN t2 ON a=x; + SELECT p, q, '|' FROM t3 ORDER BY p; +} {1 1 | 2 2 |} + finish_test From 5a2c8c885c722e52b87040330a931d36caf3d4af Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Nov 2014 14:12:28 +0000 Subject: [PATCH 53/71] Fix the %c format character in sqlite3VXPrintf() so that it correctly handles precisions larger than 70. FossilOrigin-Name: 839a6df9f98b90fb593534a62145d9c913540bae --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/printf.c | 33 +++++++++++++++++++-------------- src/sqliteInt.h | 2 +- test/printf2.test | 20 ++++++++++++++++++++ 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index e652361975..a2c5fb1bb8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sthat\sNULL\sresults\sfrom\sOP_Column\sare\sfully\sand\scompletely\sNULL\sand\sdo\snot\shave\sthe\sMEM_Ephem\sbit\sset.\sFix\sfor\sticket\s[094d39a4c95ee4]. -D 2014-11-12T14:07:28.525 +C Fix\sthe\s%c\sformat\scharacter\sin\ssqlite3VXPrintf()\sso\sthat\sit\scorrectly\shandles\sprecisions\slarger\sthan\s70. +D 2014-11-12T14:12:28.051 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -223,7 +223,7 @@ F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a F src/pcache1.c e412cb585f777c840ddce0500eddc5c6043c2bb5 F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196 -F src/printf.c 090fac0f779c93c8a95089a125339686648835e4 +F src/printf.c d83b573624f3f6bc12b800af7fd55ce90be70659 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e @@ -232,7 +232,7 @@ F src/shell.c 18ee8bbe9502d8848072dc2eddd1ea09254ba494 F src/sqlite.h.in 4a5e5158c189d2bcd45c7c4607c2c0eb6d25c153 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h f7812f74f2d0c6041ef6b91a99c5a45f775dd408 +F src/sqliteInt.h c97db3c4d20b34c050a801c93451ef18e4f22de1 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 961d5926e5a8fda611d385ec22c226b8635cd1cb F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb @@ -768,7 +768,7 @@ F test/permutations.test cef25f5e8499a15846eccd06785f17f4180407ab F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 -F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 +F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca @@ -1204,8 +1204,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P d4b2d5d066891e06f2bf4337902b44b000fa9fd2 -Q +42705fd7d892c4fdfb95fbbb468c99569beece25 -R 55a6f98cd186254776492ca00fba4393 +P e1017745e183f5d7429ce787ec2feef946a24f0f +Q +08a27440f19b7fc884464832e6105af1bf008172 +R 3a2fc5ef3a825f22ce8bbd1b4d69c828 U drh -Z efc3d14840732f527ab6a674cff641f8 +Z 3e707181121665e3dbca925048596208 diff --git a/manifest.uuid b/manifest.uuid index cfac283fb9..55a1630790 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e1017745e183f5d7429ce787ec2feef946a24f0f \ No newline at end of file +839a6df9f98b90fb593534a62145d9c913540bae \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 1df287fbb6..387b9e90c1 100644 --- a/src/printf.c +++ b/src/printf.c @@ -212,7 +212,7 @@ void sqlite3VXPrintf( const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ - char *zExtra; /* Malloced memory used by some conversion */ + char *zExtra = 0; /* Malloced memory used by some conversion */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ int nsd; /* Number of significant digits returned */ @@ -329,7 +329,6 @@ void sqlite3VXPrintf( break; } } - zExtra = 0; /* ** At this point, variables are initialized as follows: @@ -620,13 +619,16 @@ void sqlite3VXPrintf( }else{ c = va_arg(ap,int); } - buf[0] = (char)c; - if( precision>=0 ){ - for(idx=1; idx1 ){ + width -= precision-1; + if( width>1 && !flag_leftjustify ){ + sqlite3AppendChar(pAccum, width-1, ' '); + width = 0; + } + sqlite3AppendChar(pAccum, precision-1, c); } + length = 1; + buf[0] = c; bufpt = buf; break; case etSTRING: @@ -727,11 +729,14 @@ void sqlite3VXPrintf( ** the output. */ width -= length; - if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); sqlite3StrAccumAppend(pAccum, bufpt, length); - if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width); + if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); - if( zExtra ) sqlite3_free(zExtra); + if( zExtra ){ + sqlite3_free(zExtra); + zExtra = 0; + } }/* End for loop over the format string */ } /* End of function */ @@ -784,11 +789,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ } /* -** Append N space characters to the given string buffer. +** Append N copies of character c to the given string buffer. */ -void sqlite3AppendSpace(StrAccum *p, int N){ +void sqlite3AppendChar(StrAccum *p, int N, char c){ if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; - while( (N--)>0 ) p->zText[p->nChar++] = ' '; + while( (N--)>0 ) p->zText[p->nChar++] = c; } /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index cba89b03e7..40b79a79b8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3539,7 +3539,7 @@ int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, char*, int, int); void sqlite3StrAccumAppend(StrAccum*,const char*,int); void sqlite3StrAccumAppendAll(StrAccum*,const char*); -void sqlite3AppendSpace(StrAccum*,int); +void sqlite3AppendChar(StrAccum*,int,char); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); diff --git a/test/printf2.test b/test/printf2.test index 4cb1783bfb..21deeb779d 100644 --- a/test/printf2.test +++ b/test/printf2.test @@ -95,5 +95,25 @@ do_execsql_test printf2-2.3 { SELECT printf('%s=(%d/%g/%s)',a) FROM t1 ORDER BY a; } {-1=(0/0/) 1=(0/0/) 1.5=(0/0/) abc=(0/0/)} +# The precision of the %c conversion causes the character to repeat. +# +do_execsql_test printf2-3.1 { + SELECT printf('|%110.100c|','*'); +} {{| ****************************************************************************************************|}} +do_execsql_test printf2-3.2 { + SELECT printf('|%-110.100c|','*'); +} {{|**************************************************************************************************** |}} +do_execsql_test printf2-3.3 { + SELECT printf('|%9.8c|%-9.8c|','*','*'); +} {{| ********|******** |}} +do_execsql_test printf2-3.4 { + SELECT printf('|%8.8c|%-8.8c|','*','*'); +} {|********|********|} +do_execsql_test printf2-3.5 { + SELECT printf('|%7.8c|%-7.8c|','*','*'); +} {|********|********|} + + + finish_test From 80231042527411987a907328722e169e4e1cb47e Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 12 Nov 2014 14:56:02 +0000 Subject: [PATCH 54/71] When a transaction or savepoint rollback occurs, save the positions of all open read-cursors so that they can be restored following the rollback operation. FossilOrigin-Name: dd03a2802f3f276525f3cef9a93f825dd8606626 --- manifest | 19 ++++++------ manifest.uuid | 2 +- src/btree.c | 63 ++++++++++++++++++++++++++------------ src/btree.h | 2 +- src/vdbe.c | 3 +- test/rollback2.test | 74 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 132 insertions(+), 31 deletions(-) create mode 100644 test/rollback2.test diff --git a/manifest b/manifest index 97192e581d..11b9906fa0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\scalls\sto\sthe\s'breakpoint'\stest\scommand. -D 2014-11-11T19:07:56.372 +C When\sa\stransaction\sor\ssavepoint\srollback\soccurs,\ssave\sthe\spositions\sof\sall\sopen\sread-cursors\sso\sthat\sthey\scan\sbe\srestored\sfollowing\sthe\srollback\soperation. +D 2014-11-12T14:56:02.923 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -173,8 +173,8 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 86b311af1ad35decd1f2f0cee457d344acb83c3b F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c eaef0003bbfe740c62189355dabc818fc3a98999 -F src/btree.h d24fc2f3bc53be220b79b95800bdb2ee207b1089 +F src/btree.c d5d991b518fa5bebc64037dfeb98a48051d864d7 +F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -291,7 +291,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c -F src/vdbe.c c71d819bb34269c3dbccd92e6bb308f0ec025b5d +F src/vdbe.c 5e47308836e9bb5fdb4835fdf88eeab071848d3f F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 @@ -797,6 +797,7 @@ F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180 F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea +F test/rollback2.test 552abaab8e721b6060a727d639896427059e51ec F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 @@ -1218,7 +1219,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a066a3832a7c6de65c3016e77e49ac00e09db749 -R e8fc41a7f82a02ab8618a341f7ef7735 -U mistachkin -Z 90417f4c358533080e79b8017b4e7453 +P 1412fcc480799ecbd68d44dd18d5bad40e20ccf1 +R 668a86f911283b47b6c156fecf772681 +U dan +Z cf8e25329461439611751d7913ef3ef9 diff --git a/manifest.uuid b/manifest.uuid index f90bf2d8c8..3369a7ad97 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1412fcc480799ecbd68d44dd18d5bad40e20ccf1 \ No newline at end of file +dd03a2802f3f276525f3cef9a93f825dd8606626 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 70fae7c707..f153a0cc45 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3514,29 +3514,52 @@ int sqlite3BtreeCommit(Btree *p){ ** that belong to other database connections that happen to be ** sharing the cache with pBtree. ** -** This routine gets called when a rollback occurs. The writeOnly -** flag is set to 1 if the transaction did not make any schema -** changes, in which case the read cursors can continue operating. -** If schema changes did occur in the transaction, then both read -** and write cursors must both be tripped. +** This routine gets called when a rollback occurs. If the writeOnly +** flag is true, then only write-cursors need be tripped - read-only +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are +** tripped. In general, writeOnly is false if the transaction being +** rolled back modified the database schema. In this case b-tree root +** pages may be moved or deleted from the database altogether, making +** it unsafe for read cursors to continue. +** +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, +** including all read-cursors are tripped. +** +** SQLITE_OK is returned if successful, or if an error occurs while +** saving a cursor position, an SQLite error code. */ -void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ +int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; + int rc = SQLITE_OK; + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); - if( pBtree==0 ) return; - sqlite3BtreeEnter(pBtree); - for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; - if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ) continue; - sqlite3BtreeClearCursor(p); - p->eState = CURSOR_FAULT; - p->skipNext = errCode; - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; + if( pBtree ){ + sqlite3BtreeEnter(pBtree); + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + int i; + if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ + if( p->eState==CURSOR_VALID ){ + int rc = saveCursorPosition(p); + if( rc!=SQLITE_OK ){ + (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); + break; + } + } + }else{ + sqlite3BtreeClearCursor(p); + p->eState = CURSOR_FAULT; + p->skipNext = errCode; + } + for(i=0; i<=p->iPage; i++){ + releasePage(p->apPage[i]); + p->apPage[i] = 0; + } } + sqlite3BtreeLeave(pBtree); } - sqlite3BtreeLeave(pBtree); + return rc; } /* @@ -3565,7 +3588,9 @@ int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ rc = SQLITE_OK; } if( tripCode ){ - sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); + if( rc2!=SQLITE_OK ) rc = rc2; } btreeIntegrity(p); diff --git a/src/btree.h b/src/btree.h index a6093a5edd..281e57dafd 100644 --- a/src/btree.h +++ b/src/btree.h @@ -116,7 +116,7 @@ int sqlite3BtreeIncrVacuum(Btree *); int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); -void sqlite3BtreeTripAllCursors(Btree*, int, int); +int sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); diff --git a/src/vdbe.c b/src/vdbe.c index 715862e73c..e4cbeb6565 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2830,8 +2830,9 @@ case OP_Savepoint: { if( p1==SAVEPOINT_ROLLBACK ){ isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, + rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, isSchemaChange==0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ isSchemaChange = 0; diff --git a/test/rollback2.test b/test/rollback2.test new file mode 100644 index 0000000000..9637f0c0e5 --- /dev/null +++ b/test/rollback2.test @@ -0,0 +1,74 @@ +# 2014 November 12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix rollback2 + +proc int2hex {i} { format %.2X $i } +db func int2hex int2hex + +do_execsql_test 1.0 { + SELECT int2hex(0), int2hex(100), int2hex(255) +} {00 64 FF} +do_execsql_test 1.1 { + CREATE TABLE t1(i, h); + CREATE INDEX i1 ON t1(h); + WITH data(a, b) AS ( + SELECT 1, int2hex(1) + UNION ALL + SELECT a+1, int2hex(a+1) FROM data WHERE a<40 + ) + INSERT INTO t1 SELECT * FROM data; +} {} + + +proc do_rollback_test {tn args} { + set A(-setup) "" + set A(-select) "" + set A(-result) "" + set A(-rollback) ROLLBACK + + array set O $args + foreach k [array names O] { + if {[info exists A($k)]==0} { error "unknown option: $k" } + set A($k) $O($k) + } + + for {set iRollback 0} 1 {incr iRollback} { + catch { db eval ROLLBACK } + set res [list] + db eval $A(-setup) + + set i 0 + db eval $A(-select) x { + if {$i==$iRollback} { db eval $A(-rollback) } + foreach k $x(*) { lappend res $x($k) } + incr i + } + + do_test $tn.$iRollback [list set {} $res] [list {*}$A(-result)] + if {$i < $iRollback} break + } +} + +do_rollback_test 2 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + +finish_test + From d7b06909ad144b993f59e3a67d214b5ad27149fe Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 12 Nov 2014 17:45:37 +0000 Subject: [PATCH 55/71] Add further tests for rollback operations in the presence of ongoing selects. FossilOrigin-Name: eaf3aae014f59c8d37aa20aa31d54cf13f9e86fc --- manifest | 13 +++--- manifest.uuid | 2 +- test/rollback2.test | 87 ++++++++++++++++++++++++++++++++++++++++- test/rollbackfault.test | 84 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 9 deletions(-) create mode 100644 test/rollbackfault.test diff --git a/manifest b/manifest index 11b9906fa0..dddb788b2d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sa\stransaction\sor\ssavepoint\srollback\soccurs,\ssave\sthe\spositions\sof\sall\sopen\sread-cursors\sso\sthat\sthey\scan\sbe\srestored\sfollowing\sthe\srollback\soperation. -D 2014-11-12T14:56:02.923 +C Add\sfurther\stests\sfor\srollback\soperations\sin\sthe\spresence\sof\songoing\sselects. +D 2014-11-12T17:45:37.113 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -797,7 +797,8 @@ F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180 F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea -F test/rollback2.test 552abaab8e721b6060a727d639896427059e51ec +F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 +F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65 F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 @@ -1219,7 +1220,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 1412fcc480799ecbd68d44dd18d5bad40e20ccf1 -R 668a86f911283b47b6c156fecf772681 +P dd03a2802f3f276525f3cef9a93f825dd8606626 +R c0a8c133338658022754212d7071964f U dan -Z cf8e25329461439611751d7913ef3ef9 +Z c8dc7391cf2e61af731936b53ad2fd87 diff --git a/manifest.uuid b/manifest.uuid index 3369a7ad97..634cdcad8d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd03a2802f3f276525f3cef9a93f825dd8606626 \ No newline at end of file +eaf3aae014f59c8d37aa20aa31d54cf13f9e86fc \ No newline at end of file diff --git a/test/rollback2.test b/test/rollback2.test index 9637f0c0e5..4d42dda5d6 100644 --- a/test/rollback2.test +++ b/test/rollback2.test @@ -9,6 +9,9 @@ # #*********************************************************************** # +# This file containst tests to verify that ROLLBACK or ROLLBACK TO +# operations interact correctly with ongoing SELECT statements. +# set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -16,7 +19,6 @@ set ::testprefix rollback2 proc int2hex {i} { format %.2X $i } db func int2hex int2hex - do_execsql_test 1.0 { SELECT int2hex(0), int2hex(100), int2hex(255) } {00 64 FF} @@ -32,6 +34,17 @@ do_execsql_test 1.1 { } {} +# do_rollback_test ID SWITCHES +# +# where SWITCHES are: +# +# -setup SQL script to open transaction and begin writing. +# -select SELECT to execute after -setup script +# -result Expected result of -select statement +# -rollback Use this SQL command ("ROLLBACK" or "ROLLBACK TO ...") to +# rollback the transaction in the middle of the -select statment +# execution. +# proc do_rollback_test {tn args} { set A(-setup) "" set A(-select) "" @@ -61,7 +74,7 @@ proc do_rollback_test {tn args} { } } -do_rollback_test 2 -setup { +do_rollback_test 2.1 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; } -select { @@ -70,5 +83,75 @@ do_rollback_test 2 -setup { 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 } +do_rollback_test 2.2 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%4)==1; + SAVEPOINT one; + DELETE FROM t1 WHERE (i%2)==1; +} -rollback { + ROLLBACK TO one; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + +#-------------------------------------------------------------------- +# Try with some index scans +# +do_eqp_test 3.1 { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; +} {0 0 0 {SCAN TABLE t1 USING INDEX i1}} +do_rollback_test 3.2 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; +} -result { + 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 +} +do_rollback_test 3.3 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%4)==1; + SAVEPOINT one; + DELETE FROM t1 WHERE (i%2)==1; +} -rollback { + ROLLBACK TO one; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; +} -result { + 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 +} + +#-------------------------------------------------------------------- +# Now with some index scans that feature overflow keys. +# +set leader [string repeat "abcdefghij" 70] +do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; } + +do_eqp_test 4.2 { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; +} {0 0 0 {SCAN TABLE t1 USING INDEX i1}} +do_rollback_test 4.3 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} +do_rollback_test 4.4 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%4)==1; + SAVEPOINT one; + DELETE FROM t1 WHERE (i%2)==1; +} -rollback { + ROLLBACK TO one; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + finish_test diff --git a/test/rollbackfault.test b/test/rollbackfault.test new file mode 100644 index 0000000000..f248d0758d --- /dev/null +++ b/test/rollbackfault.test @@ -0,0 +1,84 @@ +# 2014-11-12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test that errors encountered during a ROLLBACK operation correctly +# affect ongoing SQL statements. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set testprefix rollbackfault + + +proc int2hex {i} { format %.2X $i } +db func int2hex int2hex +do_execsql_test 1.0 { + SELECT int2hex(0), int2hex(100), int2hex(255) +} {00 64 FF} +do_execsql_test 1.1 { + CREATE TABLE t1(i, h); + CREATE INDEX i1 ON t1(h); + WITH data(a, b) AS ( + SELECT 1, int2hex(1) + UNION ALL + SELECT a+1, int2hex(a+1) FROM data WHERE a<40 + ) + INSERT INTO t1 SELECT * FROM data; +} {} + +foreach f {oom ioerr} { + do_faultsim_test 1.2 -faults $f* -prep { + set sql1 { SELECT i FROM t1 WHERE (i%2)==0 } + set sql2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h } + set ::s1 [sqlite3_prepare db $sql1 -1 dummy] + set ::s2 [sqlite3_prepare db $sql2 -1 dummy] + + for {set i 0} {$i < 10} {incr i} { sqlite3_step $::s1 } + for {set i 0} {$i < 3} {incr i} { sqlite3_step $::s2 } + + execsql { + BEGIN; DELETE FROM t1 WHERE (i%2) + } + } -body { + execsql { ROLLBACK } + } -test { + + set res1 [list] + set res2 [list] + while {"SQLITE_ROW" == [sqlite3_step $::s1]} { + lappend res1 [sqlite3_column_text $::s1 0] + } + while {"SQLITE_ROW" == [sqlite3_step $::s2]} { + lappend res2 [sqlite3_column_text $::s2 0] + } + set rc1 [sqlite3_finalize $::s1] + set rc2 [sqlite3_finalize $::s2] + + catchsql { ROLLBACK } + + if {$rc1=="SQLITE_OK" && $rc2=="SQLITE_OK" + && $res1=="22 24 26 28 30 32 34 36 38 40" + && $res2=="8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40" + } { + # This is Ok. + } elseif {$rc1!="SQLITE_OK" && $rc2!="SQLITE_OK" && $res1=="" &&$res2==""} { + # Also Ok. + } else { + error "statements don't look right" + } + } +} + + +finish_test + + From 6f9c5669e2d54fb4e480b2f1f39fba6907560cc1 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 13 Nov 2014 13:42:39 +0000 Subject: [PATCH 56/71] When a transaction or savepoint rollback occurs, save the positions of all open read-cursors so that they can be restored following the rollback operation. Cherry-pick of check-in [dd03a2802f3f27] FossilOrigin-Name: 402780a9c8df9e7ea898bdca49c1191042fe387a --- manifest | 19 ++++++------ manifest.uuid | 2 +- src/btree.c | 63 ++++++++++++++++++++++++++------------ src/btree.h | 2 +- src/vdbe.c | 3 +- test/rollback2.test | 74 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 132 insertions(+), 31 deletions(-) create mode 100644 test/rollback2.test diff --git a/manifest b/manifest index a2c5fb1bb8..1d9fe4d78f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\s%c\sformat\scharacter\sin\ssqlite3VXPrintf()\sso\sthat\sit\scorrectly\shandles\sprecisions\slarger\sthan\s70. -D 2014-11-12T14:12:28.051 +C When\sa\stransaction\sor\ssavepoint\srollback\soccurs,\ssave\sthe\spositions\sof\sall\sopen\sread-cursors\sso\sthat\sthey\scan\sbe\srestored\sfollowing\sthe\srollback\soperation.\s\sCherry-pick\sof\scheck-in\s[dd03a2802f3f27] +D 2014-11-13T13:42:39.738 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,8 +172,8 @@ F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2 F src/backup.c 8cdfeb0c8a6d8bdad3faefae418eb3dc767051b6 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 944b84f72fd9048acde31400d89439976bf766b0 -F src/btree.h 97c4d0ef860f151e096e97eef78b87f7b4a8d899 +F src/btree.c 2c15850c5c9a26b10cdf92f9a29c74e299dc3674 +F src/btree.h a4afc6b06f5a1dd2076d15aa168baec44fc0121b F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 0b4ffa1aeeb7a10fefc6497dd0159bf5d9828464 +F src/vdbe.c a6b604364c7cbb079c083418e7359d1d665f2ef0 F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h e2a060a55ee18a6ab973353a5e2ec7ee569bf787 F src/vdbeapi.c 37a6c6ae284a97bcace365f2f0a225680c0499d9 @@ -786,6 +786,7 @@ F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180 F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea +F test/rollback2.test 552abaab8e721b6060a727d639896427059e51ec F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 @@ -1204,8 +1205,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e1017745e183f5d7429ce787ec2feef946a24f0f -Q +08a27440f19b7fc884464832e6105af1bf008172 -R 3a2fc5ef3a825f22ce8bbd1b4d69c828 +P 839a6df9f98b90fb593534a62145d9c913540bae +Q +dd03a2802f3f276525f3cef9a93f825dd8606626 +R 0801523eb21d9763755a3afd3e84ae8b U drh -Z 3e707181121665e3dbca925048596208 +Z 995ce8d43edc83cec464fe7495c36085 diff --git a/manifest.uuid b/manifest.uuid index 55a1630790..38b0ca2922 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -839a6df9f98b90fb593534a62145d9c913540bae \ No newline at end of file +402780a9c8df9e7ea898bdca49c1191042fe387a \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9d7a05157d..41e097af53 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3472,29 +3472,52 @@ int sqlite3BtreeCommit(Btree *p){ ** that belong to other database connections that happen to be ** sharing the cache with pBtree. ** -** This routine gets called when a rollback occurs. The writeOnly -** flag is set to 1 if the transaction did not make any schema -** changes, in which case the read cursors can continue operating. -** If schema changes did occur in the transaction, then both read -** and write cursors must both be tripped. +** This routine gets called when a rollback occurs. If the writeOnly +** flag is true, then only write-cursors need be tripped - read-only +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are +** tripped. In general, writeOnly is false if the transaction being +** rolled back modified the database schema. In this case b-tree root +** pages may be moved or deleted from the database altogether, making +** it unsafe for read cursors to continue. +** +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, +** including all read-cursors are tripped. +** +** SQLITE_OK is returned if successful, or if an error occurs while +** saving a cursor position, an SQLite error code. */ -void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ +int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ BtCursor *p; + int rc = SQLITE_OK; + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); - if( pBtree==0 ) return; - sqlite3BtreeEnter(pBtree); - for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; - if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ) continue; - sqlite3BtreeClearCursor(p); - p->eState = CURSOR_FAULT; - p->skipNext = errCode; - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; + if( pBtree ){ + sqlite3BtreeEnter(pBtree); + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + int i; + if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ + if( p->eState==CURSOR_VALID ){ + int rc = saveCursorPosition(p); + if( rc!=SQLITE_OK ){ + (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); + break; + } + } + }else{ + sqlite3BtreeClearCursor(p); + p->eState = CURSOR_FAULT; + p->skipNext = errCode; + } + for(i=0; i<=p->iPage; i++){ + releasePage(p->apPage[i]); + p->apPage[i] = 0; + } } + sqlite3BtreeLeave(pBtree); } - sqlite3BtreeLeave(pBtree); + return rc; } /* @@ -3523,7 +3546,9 @@ int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ rc = SQLITE_OK; } if( tripCode ){ - sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); + if( rc2!=SQLITE_OK ) rc = rc2; } btreeIntegrity(p); diff --git a/src/btree.h b/src/btree.h index f724269a3e..fabedd9a53 100644 --- a/src/btree.h +++ b/src/btree.h @@ -116,7 +116,7 @@ int sqlite3BtreeIncrVacuum(Btree *); int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTableOfCursor(BtCursor*); -void sqlite3BtreeTripAllCursors(Btree*, int, int); +int sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); diff --git a/src/vdbe.c b/src/vdbe.c index 9462bd71f8..1ad8aab753 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2827,8 +2827,9 @@ case OP_Savepoint: { if( p1==SAVEPOINT_ROLLBACK ){ isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, + rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, isSchemaChange==0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ isSchemaChange = 0; diff --git a/test/rollback2.test b/test/rollback2.test new file mode 100644 index 0000000000..9637f0c0e5 --- /dev/null +++ b/test/rollback2.test @@ -0,0 +1,74 @@ +# 2014 November 12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix rollback2 + +proc int2hex {i} { format %.2X $i } +db func int2hex int2hex + +do_execsql_test 1.0 { + SELECT int2hex(0), int2hex(100), int2hex(255) +} {00 64 FF} +do_execsql_test 1.1 { + CREATE TABLE t1(i, h); + CREATE INDEX i1 ON t1(h); + WITH data(a, b) AS ( + SELECT 1, int2hex(1) + UNION ALL + SELECT a+1, int2hex(a+1) FROM data WHERE a<40 + ) + INSERT INTO t1 SELECT * FROM data; +} {} + + +proc do_rollback_test {tn args} { + set A(-setup) "" + set A(-select) "" + set A(-result) "" + set A(-rollback) ROLLBACK + + array set O $args + foreach k [array names O] { + if {[info exists A($k)]==0} { error "unknown option: $k" } + set A($k) $O($k) + } + + for {set iRollback 0} 1 {incr iRollback} { + catch { db eval ROLLBACK } + set res [list] + db eval $A(-setup) + + set i 0 + db eval $A(-select) x { + if {$i==$iRollback} { db eval $A(-rollback) } + foreach k $x(*) { lappend res $x($k) } + incr i + } + + do_test $tn.$iRollback [list set {} $res] [list {*}$A(-result)] + if {$i < $iRollback} break + } +} + +do_rollback_test 2 -setup { + BEGIN; + DELETE FROM t1 WHERE (i%2)==1; +} -select { + SELECT i FROM t1 WHERE (i%2)==0 +} -result { + 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 +} + +finish_test + From fad01993b7f9a5d519dd5d344dd5e4c8a44ccc06 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 13 Nov 2014 14:18:25 +0000 Subject: [PATCH 57/71] Have calls to sqlite3_backup_init() fail if there is already a read or read-write transaction open on the destination database. FossilOrigin-Name: 169b5505498c0a7ee2b5dbb2ba13c41dfaa7c62f --- manifest | 15 ++++++----- manifest.uuid | 2 +- src/backup.c | 27 ++++++++++++++++---- test/backup.test | 1 + test/backup5.test | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 test/backup5.test diff --git a/manifest b/manifest index dddb788b2d..4f0d48c405 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sfurther\stests\sfor\srollback\soperations\sin\sthe\spresence\sof\songoing\sselects. -D 2014-11-12T17:45:37.113 +C Have\scalls\sto\ssqlite3_backup_init()\sfail\sif\sthere\sis\salready\sa\sread\sor\sread-write\stransaction\sopen\son\sthe\sdestination\sdatabase. +D 2014-11-13T14:18:25.531 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -170,7 +170,7 @@ F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb F src/analyze.c afbcca663c3f3625340b8e30d440cd7a97ded6bc F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 -F src/backup.c 86b311af1ad35decd1f2f0cee457d344acb83c3b +F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 F src/btree.c d5d991b518fa5bebc64037dfeb98a48051d864d7 @@ -353,9 +353,10 @@ F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 F test/backcompat.test 19a1f337c68419b020a7481dd272a472c4ad8ef4 -F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62 +F test/backup.test b79299a536a4c6d919094786595b95be56d02014 F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4 +F test/backup5.test ee5da6d7fe5082f5b9b0bbfa31d016f52412a2e4 F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f @@ -1220,7 +1221,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P dd03a2802f3f276525f3cef9a93f825dd8606626 -R c0a8c133338658022754212d7071964f +P eaf3aae014f59c8d37aa20aa31d54cf13f9e86fc +R cf416376a3614eef6301ba322bd3cc43 U dan -Z c8dc7391cf2e61af731936b53ad2fd87 +Z 499ccc085277a0250fd3c5f22e93f6be diff --git a/manifest.uuid b/manifest.uuid index 634cdcad8d..73dcaa8447 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eaf3aae014f59c8d37aa20aa31d54cf13f9e86fc \ No newline at end of file +169b5505498c0a7ee2b5dbb2ba13c41dfaa7c62f \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index 57f7f447ea..e3f869035e 100644 --- a/src/backup.c +++ b/src/backup.c @@ -122,6 +122,20 @@ static int setDestPgsz(sqlite3_backup *p){ return rc; } +/* +** Check that there is no open read-transaction on the b-tree passed as the +** second argument. If there is not, return SQLITE_OK. Otherwise, if there +** is an open read-transaction, return SQLITE_ERROR and leave an error +** message in database handle db. +*/ +static int checkReadTransaction(sqlite3 *db, Btree *p){ + if( sqlite3BtreeIsInReadTrans(p) ){ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + /* ** Create an sqlite3_backup process to copy the contents of zSrcDb from ** connection handle pSrcDb to zDestDb in pDestDb. If successful, return @@ -181,12 +195,15 @@ sqlite3_backup *sqlite3_backup_init( p->iNext = 1; p->isAttached = 0; - if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){ + if( 0==p->pSrc || 0==p->pDest + || setDestPgsz(p)==SQLITE_NOMEM + || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + ){ /* One (or both) of the named databases did not exist or an OOM - ** error was hit. The error has already been written into the - ** pDestDb handle. All that is left to do here is free the - ** sqlite3_backup structure. - */ + ** error was hit. Or there is a transaction open on the destination + ** database. The error has already been written into the pDestDb + ** handle. All that is left to do here is free the sqlite3_backup + ** structure. */ sqlite3_free(p); p = 0; } diff --git a/test/backup.test b/test/backup.test index 444619c68c..3b1e1db9e5 100644 --- a/test/backup.test +++ b/test/backup.test @@ -217,6 +217,7 @@ foreach nPagePerStep {1 200} { INSERT INTO ${file_dest}.t1 VALUES(1, randstr(1000,1000)) " $db_dest } + execsql COMMIT $db_dest } # Backup the source database. diff --git a/test/backup5.test b/test/backup5.test new file mode 100644 index 0000000000..c789adfa69 --- /dev/null +++ b/test/backup5.test @@ -0,0 +1,65 @@ +# 2014 November 13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix backup5 + +forcedelete test2.db + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + INSERT INTO t2 VALUES(1, 1); + INSERT INTO t2 VALUES(2, 2); + INSERT INTO t2 VALUES(3, 3); +} + +do_test 1.1 { + forcecopy test.db test.db2 + db eval { + DROP TABLE t2; + INSERT INTO t1 VALUES(zeroblob(1000), zeroblob(1000)); + INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000)); + } +} {} + +do_test 1.2 { + sqlite3 db2 test.db2 + set stmt [sqlite3_prepare_v2 db2 "SELECT * FROM t2" -1 dummy] + sqlite3_step $stmt +} {SQLITE_ROW} + +do_test 1.3 { + list [catch { sqlite3_backup B db2 main db main } msg] $msg +} {1 {sqlite3_backup_init() failed}} + +do_test 1.4 { + sqlite3_errmsg db2 +} {destination database is in use} + +do_test 1.5 { + sqlite3_reset $stmt + sqlite3_backup B db2 main db main + B step 200 + B finish +} {SQLITE_OK} + +do_test 1.6 { + list [sqlite3_step $stmt] [sqlite3_finalize $stmt] +} {SQLITE_ERROR SQLITE_ERROR} + +do_test 1.7 { + sqlite3_errmsg db2 +} {no such table: t2} + +finish_test From 8ac1a67eff83ed80083e94deb70a366cf1a9568e Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 13 Nov 2014 14:30:56 +0000 Subject: [PATCH 58/71] Modify the documentation for sqlite3_backup_init() to indicate that it will fail if there is already a read or read-write transaction open on the destination database. FossilOrigin-Name: ef03a203351a6002e2b1075139717e4234c816cd --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 4f0d48c405..7a15358036 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\scalls\sto\ssqlite3_backup_init()\sfail\sif\sthere\sis\salready\sa\sread\sor\sread-write\stransaction\sopen\son\sthe\sdestination\sdatabase. -D 2014-11-13T14:18:25.531 +C Modify\sthe\sdocumentation\sfor\ssqlite3_backup_init()\sto\sindicate\sthat\sit\swill\sfail\sif\sthere\sis\salready\sa\sread\sor\sread-write\stransaction\sopen\son\sthe\sdestination\sdatabase. +D 2014-11-13T14:30:56.983 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,7 +230,7 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd -F src/sqlite.h.in 0e6612f84936cca29166f2c66068e0227a13fdf6 +F src/sqlite.h.in 0c5c0df7e4e436dfc5592511325bf4a96f6a638d F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 71b0bf1a7fc55b5cb374f7579fd140e730a6e0f4 @@ -1221,7 +1221,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P eaf3aae014f59c8d37aa20aa31d54cf13f9e86fc -R cf416376a3614eef6301ba322bd3cc43 +P 169b5505498c0a7ee2b5dbb2ba13c41dfaa7c62f +R 91cc925fca98dfe2ae31ca6f9eebcf27 U dan -Z 499ccc085277a0250fd3c5f22e93f6be +Z 09c231773b0ef1121faa87d2329ad833 diff --git a/manifest.uuid b/manifest.uuid index 73dcaa8447..018b18d5f0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -169b5505498c0a7ee2b5dbb2ba13c41dfaa7c62f \ No newline at end of file +ef03a203351a6002e2b1075139717e4234c816cd \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2812bf511d..4427f39d06 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6848,6 +6848,10 @@ typedef struct sqlite3_backup sqlite3_backup; ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** +** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if +** there is already a read or read-write transaction open on the +** destination database. +** ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is ** returned and an error code and error message are stored in the ** destination [database connection] D. From dd715f7c57f78f96fa00f8cb299d082f59ddbfb5 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 14 Nov 2014 15:28:33 +0000 Subject: [PATCH 59/71] Do not automatically remove the DISTINCT keyword from "a IN (SELECT DISTINCT ...)" expressions. Fix for [db87229497]. FossilOrigin-Name: 55e453aadbb676dda07f0fa537d39ce184ef636c --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 1 - test/in5.test | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 7a15358036..1b20e13d73 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Modify\sthe\sdocumentation\sfor\ssqlite3_backup_init()\sto\sindicate\sthat\sit\swill\sfail\sif\sthere\sis\salready\sa\sread\sor\sread-write\stransaction\sopen\son\sthe\sdestination\sdatabase. -D 2014-11-13T14:30:56.983 +C Do\snot\sautomatically\sremove\sthe\sDISTINCT\skeyword\sfrom\s"a\sIN\s(SELECT\sDISTINCT\s...)"\sexpressions.\sFix\sfor\s[db87229497]. +D 2014-11-14T15:28:33.929 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -182,7 +182,7 @@ F src/complete.c c4ba6e0626bb94bc77a0861735f3382fcf7cc818 F src/ctime.c df19848891c8a553c80e6f5a035e768280952d1a F src/date.c 93594514aae68de117ca4a2a0d6cc63eddf26744 F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417 -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 @@ -627,7 +627,7 @@ F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 -F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 +F test/in5.test 1de657472fa9ac2924be25c2c959ac5ca1aae554 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 @@ -1221,7 +1221,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 169b5505498c0a7ee2b5dbb2ba13c41dfaa7c62f -R 91cc925fca98dfe2ae31ca6f9eebcf27 +P ef03a203351a6002e2b1075139717e4234c816cd +R bb54553354aa14551393c5e5701542c8 U dan -Z 09c231773b0ef1121faa87d2329ad833 +Z f91e19e3f2d1e58cdccd86465c86ab70 diff --git a/manifest.uuid b/manifest.uuid index 018b18d5f0..c5dbef8e09 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef03a203351a6002e2b1075139717e4234c816cd \ No newline at end of file +55e453aadbb676dda07f0fa537d39ce184ef636c \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 13a9cb46fd..25f0be400f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1857,7 +1857,6 @@ int sqlite3CodeSubselect( assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); - pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); diff --git a/test/in5.test b/test/in5.test index 8a43b8d44a..67d212589d 100644 --- a/test/in5.test +++ b/test/in5.test @@ -12,6 +12,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix in5 do_test in5-1.1 { execsql { @@ -135,4 +136,51 @@ do_test in5-5.3 { }] } {0} +#------------------------------------------------------------------------- +# At one point SQLite was removing the DISTINCT keyword from expressions +# similar to: +# +# IN (SELECT DISTINCT FROM...) +# +# However, there are a few obscure cases where this is incorrect. For +# example, if the SELECT features a LIMIT clause, or if the collation +# sequence or affinity used by the DISTINCT does not match the one used +# by the IN(...) expression. +# +do_execsql_test 6.1.1 { + CREATE TABLE t1(a COLLATE nocase); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('ONE'); +} +do_execsql_test 6.1.2 { + SELECT count(*) FROM t1 WHERE a COLLATE BINARY IN (SELECT DISTINCT a FROM t1) +} {1} + +do_execsql_test 6.2.1 { + CREATE TABLE t3(a, b); + INSERT INTO t3 VALUES(1, 1); + INSERT INTO t3 VALUES(1, 2); + INSERT INTO t3 VALUES(1, 3); + INSERT INTO t3 VALUES(2, 4); + INSERT INTO t3 VALUES(2, 5); + INSERT INTO t3 VALUES(2, 6); + INSERT INTO t3 VALUES(3, 7); + INSERT INTO t3 VALUES(3, 8); + INSERT INTO t3 VALUES(3, 9); +} +do_execsql_test 6.2.2 { + SELECT count(*) FROM t3 WHERE b IN (SELECT DISTINCT a FROM t3 LIMIT 5); +} {3} +do_execsql_test 6.2.3 { + SELECT count(*) FROM t3 WHERE b IN (SELECT a FROM t3 LIMIT 5); +} {2} + +do_execsql_test 6.3.1 { + CREATE TABLE x1(a); + CREATE TABLE x2(b); + INSERT INTO x1 VALUES(1), (1), (2); + INSERT INTO x2 VALUES(1), (2); + SELECT count(*) FROM x2 WHERE b IN (SELECT DISTINCT a FROM x1 LIMIT 2); +} {2} + finish_test From 0a9d9d566e24d05afcfdd15368eccb8683331ecc Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 14 Nov 2014 15:42:23 +0000 Subject: [PATCH 60/71] Do not automatically remove the DISTINCT keyword from "a IN (SELECT DISTINCT ...)" expressions. Fix for [db87229497]. FossilOrigin-Name: 98457a57d642b35917eb9ad8f70065e273aad206 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/expr.c | 1 - test/in5.test | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 1d9fe4d78f..a2350554db 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sa\stransaction\sor\ssavepoint\srollback\soccurs,\ssave\sthe\spositions\sof\sall\sopen\sread-cursors\sso\sthat\sthey\scan\sbe\srestored\sfollowing\sthe\srollback\soperation.\s\sCherry-pick\sof\scheck-in\s[dd03a2802f3f27] -D 2014-11-13T13:42:39.738 +C Do\snot\sautomatically\sremove\sthe\sDISTINCT\skeyword\sfrom\s"a\sIN\s(SELECT\sDISTINCT\s...)"\sexpressions.\sFix\sfor\s[db87229497]. +D 2014-11-14T15:42:23.965 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -181,7 +181,7 @@ F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14 F src/ctime.c bb434068b5308a857b181c2d204a320ff0d6c638 F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036 F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417 -F src/expr.c fc204d08af06437ddaffe5a1b1f1f6f9e1a55d6d +F src/expr.c 1891cb50510a31e96de8a54579e7d3aef60f0094 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee @@ -616,7 +616,7 @@ F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 -F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 +F test/in5.test 1de657472fa9ac2924be25c2c959ac5ca1aae554 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 @@ -1205,8 +1205,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 839a6df9f98b90fb593534a62145d9c913540bae -Q +dd03a2802f3f276525f3cef9a93f825dd8606626 -R 0801523eb21d9763755a3afd3e84ae8b +P 402780a9c8df9e7ea898bdca49c1191042fe387a +Q +55e453aadbb676dda07f0fa537d39ce184ef636c +R 0bf0d6ff158ba2352191f711d5e9a856 U drh -Z 995ce8d43edc83cec464fe7495c36085 +Z fc11fd8e7149b148ee2e3386efe4bde7 diff --git a/manifest.uuid b/manifest.uuid index 38b0ca2922..8df489121d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -402780a9c8df9e7ea898bdca49c1191042fe387a \ No newline at end of file +98457a57d642b35917eb9ad8f70065e273aad206 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 1ad9a879a3..881cfd4344 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1836,7 +1836,6 @@ int sqlite3CodeSubselect( assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); - pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); diff --git a/test/in5.test b/test/in5.test index 8a43b8d44a..67d212589d 100644 --- a/test/in5.test +++ b/test/in5.test @@ -12,6 +12,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix in5 do_test in5-1.1 { execsql { @@ -135,4 +136,51 @@ do_test in5-5.3 { }] } {0} +#------------------------------------------------------------------------- +# At one point SQLite was removing the DISTINCT keyword from expressions +# similar to: +# +# IN (SELECT DISTINCT FROM...) +# +# However, there are a few obscure cases where this is incorrect. For +# example, if the SELECT features a LIMIT clause, or if the collation +# sequence or affinity used by the DISTINCT does not match the one used +# by the IN(...) expression. +# +do_execsql_test 6.1.1 { + CREATE TABLE t1(a COLLATE nocase); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('ONE'); +} +do_execsql_test 6.1.2 { + SELECT count(*) FROM t1 WHERE a COLLATE BINARY IN (SELECT DISTINCT a FROM t1) +} {1} + +do_execsql_test 6.2.1 { + CREATE TABLE t3(a, b); + INSERT INTO t3 VALUES(1, 1); + INSERT INTO t3 VALUES(1, 2); + INSERT INTO t3 VALUES(1, 3); + INSERT INTO t3 VALUES(2, 4); + INSERT INTO t3 VALUES(2, 5); + INSERT INTO t3 VALUES(2, 6); + INSERT INTO t3 VALUES(3, 7); + INSERT INTO t3 VALUES(3, 8); + INSERT INTO t3 VALUES(3, 9); +} +do_execsql_test 6.2.2 { + SELECT count(*) FROM t3 WHERE b IN (SELECT DISTINCT a FROM t3 LIMIT 5); +} {3} +do_execsql_test 6.2.3 { + SELECT count(*) FROM t3 WHERE b IN (SELECT a FROM t3 LIMIT 5); +} {2} + +do_execsql_test 6.3.1 { + CREATE TABLE x1(a); + CREATE TABLE x2(b); + INSERT INTO x1 VALUES(1), (1), (2); + INSERT INTO x2 VALUES(1), (2); + SELECT count(*) FROM x2 WHERE b IN (SELECT DISTINCT a FROM x1 LIMIT 2); +} {2} + finish_test From 302f583aa4dc6a77ca9042dca3143a3bf8a134f0 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 17 Nov 2014 15:22:08 +0000 Subject: [PATCH 61/71] Update a couple of test cases to account for the fact that ROLLBACK does not always abort all running SELECT statements. FossilOrigin-Name: eba171e980fa4491dfee9d7e4df50c87a0ebbf87 --- manifest | 17 ++++++++--------- manifest.uuid | 2 +- test/ioerr2.test | 8 +++++++- test/shared_err.test | 8 +++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index a2350554db..27ecc3c872 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sautomatically\sremove\sthe\sDISTINCT\skeyword\sfrom\s"a\sIN\s(SELECT\sDISTINCT\s...)"\sexpressions.\sFix\sfor\s[db87229497]. -D 2014-11-14T15:42:23.965 +C Update\sa\scouple\sof\stest\scases\sto\saccount\sfor\sthe\sfact\sthat\sROLLBACK\sdoes\snot\salways\sabort\sall\srunning\sSELECT\sstatements. +D 2014-11-17T15:22:08.993 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -648,7 +648,7 @@ F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844 F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8 F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d -F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d +F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26 F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 @@ -830,7 +830,7 @@ F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956 F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538 F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21 F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 -F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa +F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 F test/shell1.test d60946b5fde4d85fe06db7331dfe89011f564350 F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3 @@ -1205,8 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 402780a9c8df9e7ea898bdca49c1191042fe387a -Q +55e453aadbb676dda07f0fa537d39ce184ef636c -R 0bf0d6ff158ba2352191f711d5e9a856 -U drh -Z fc11fd8e7149b148ee2e3386efe4bde7 +P 98457a57d642b35917eb9ad8f70065e273aad206 +R d8acddabccfe794436f7272593be21d9 +U dan +Z 30deb4af13a2947d821f81a6f506118a diff --git a/manifest.uuid b/manifest.uuid index 8df489121d..bf9ab0f15d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -98457a57d642b35917eb9ad8f70065e273aad206 \ No newline at end of file +eba171e980fa4491dfee9d7e4df50c87a0ebbf87 \ No newline at end of file diff --git a/test/ioerr2.test b/test/ioerr2.test index 5150ace3ab..c08c3453f3 100644 --- a/test/ioerr2.test +++ b/test/ioerr2.test @@ -112,6 +112,12 @@ foreach bPersist [list 0 1] { } } +# When this test was written, an IO error within the UPDATE statement caused +# a rollback, which tripped all read-cursors, causing the outer SELECT to +# fail with "abort due to ROLLBACK". Now, the loop continues until the UPDATE +# is run successfully. At this point the next IO error occurs within the +# SELECT - throwing the "disk I/O error" that the test case now expects. +# do_test ioerr2-5 { execsql { CREATE TABLE t2 AS SELECT * FROM t1; @@ -130,7 +136,7 @@ do_test ioerr2-5 { } } msg] list $rc $msg -} {1 {abort due to ROLLBACK}} +} {1 {disk I/O error}} ;# used to be "{1 {abort due to ROLLBACK}}" if {$::tcl_platform(platform) == "unix"} { # Cause the call to xAccess used by [pragma temp_store_directory] to diff --git a/test/shared_err.test b/test/shared_err.test index 17add94bb7..96e5ee4540 100644 --- a/test/shared_err.test +++ b/test/shared_err.test @@ -446,9 +446,15 @@ do_malloc_test shared_err-8 -tclprep { } {1} db2 close } + +# When this test case was written, OOM errors in write statements would +# cause transaction rollback, which would trip cursors in other statements, +# aborting them. This no longer happens. +# do_test shared_malloc-8.X { # Test that one or more queries were aborted due to the malloc() failure. - expr $::aborted>=1 + # expr $::aborted>=1 + expr $::aborted==0 } {1} # This test is designed to catch a specific bug that was present during From 13835c41e824eb2b6a7d504c4df2066fe4ad6c52 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 17 Nov 2014 15:32:47 +0000 Subject: [PATCH 62/71] Fix a bug in the sqlite3TripAllCursors() routine that prevents it from reporting errors. It is unknown at this time whether or not this omission can result in any incorrect result in an actual query. FossilOrigin-Name: 42588207ff5451cb785c394633e1ab631fb82f01 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/btree.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 27ecc3c872..a0d49916be 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sa\scouple\sof\stest\scases\sto\saccount\sfor\sthe\sfact\sthat\sROLLBACK\sdoes\snot\salways\sabort\sall\srunning\sSELECT\sstatements. -D 2014-11-17T15:22:08.993 +C Fix\sa\sbug\sin\sthe\ssqlite3TripAllCursors()\sroutine\sthat\sprevents\sit\sfrom\nreporting\serrors.\s\sIt\sis\sunknown\sat\sthis\stime\swhether\sor\snot\sthis\somission\scan\nresult\sin\sany\sincorrect\sresult\sin\san\sactual\squery. +D 2014-11-17T15:32:47.066 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,7 +172,7 @@ F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2 F src/backup.c 8cdfeb0c8a6d8bdad3faefae418eb3dc767051b6 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 2c15850c5c9a26b10cdf92f9a29c74e299dc3674 +F src/btree.c 2087125172421c78fc0c02f953b7d660f2a2598e F src/btree.h a4afc6b06f5a1dd2076d15aa168baec44fc0121b F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919 @@ -1205,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 98457a57d642b35917eb9ad8f70065e273aad206 -R d8acddabccfe794436f7272593be21d9 -U dan -Z 30deb4af13a2947d821f81a6f506118a +P eba171e980fa4491dfee9d7e4df50c87a0ebbf87 +R c97ad964463de041aa0a8f758aac4ee1 +U drh +Z ed993b1ef595900db9792d9ac234a3c7 diff --git a/manifest.uuid b/manifest.uuid index bf9ab0f15d..7891ecfbd0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eba171e980fa4491dfee9d7e4df50c87a0ebbf87 \ No newline at end of file +42588207ff5451cb785c394633e1ab631fb82f01 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 41e097af53..111870548b 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3499,7 +3499,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID ){ - int rc = saveCursorPosition(p); + rc = saveCursorPosition(p); if( rc!=SQLITE_OK ){ (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); break; From 77b1deec400c40676dfca2986dbf659af548c40f Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 17 Nov 2014 17:13:06 +0000 Subject: [PATCH 63/71] When a SELECT statement is terminated by a ROLLBACK TO operation, make the error message be "abort due to ROLLBACK" rather than "callback requested query abort". FossilOrigin-Name: 34fc4a082c192830e48f643549c04a4f91912b8b --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbe.c | 3 ++- test/savepoint7.test | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index a0d49916be..93ef894b6e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\sin\sthe\ssqlite3TripAllCursors()\sroutine\sthat\sprevents\sit\sfrom\nreporting\serrors.\s\sIt\sis\sunknown\sat\sthis\stime\swhether\sor\snot\sthis\somission\scan\nresult\sin\sany\sincorrect\sresult\sin\san\sactual\squery. -D 2014-11-17T15:32:47.066 +C When\sa\sSELECT\sstatement\sis\sterminated\sby\sa\sROLLBACK\sTO\soperation,\smake\sthe\nerror\smessage\sbe\s"abort\sdue\sto\sROLLBACK"\srather\sthan\s\n"callback\srequested\squery\sabort". +D 2014-11-17T17:13:06.964 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c a6b604364c7cbb079c083418e7359d1d665f2ef0 +F src/vdbe.c 3e8f9787d9a5fe24077f7af0baa2d11042471f12 F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h e2a060a55ee18a6ab973353a5e2ec7ee569bf787 F src/vdbeapi.c 37a6c6ae284a97bcace365f2f0a225680c0499d9 @@ -797,7 +797,7 @@ F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 -F test/savepoint7.test 1c8f26b1e2a4221b0214e222ce12a97a59918eb2 +F test/savepoint7.test db3db281486c925095f305aad09fe806e5188ff3 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1205,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P eba171e980fa4491dfee9d7e4df50c87a0ebbf87 -R c97ad964463de041aa0a8f758aac4ee1 +P 42588207ff5451cb785c394633e1ab631fb82f01 +R dfbcaabb48c2f5c435e2c7179a62bd27 U drh -Z ed993b1ef595900db9792d9ac234a3c7 +Z c435b7b174ccd5699f4e15dc48114455 diff --git a/manifest.uuid b/manifest.uuid index 7891ecfbd0..d4b77b5f9f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42588207ff5451cb785c394633e1ab631fb82f01 \ No newline at end of file +34fc4a082c192830e48f643549c04a4f91912b8b \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 1ad8aab753..9a8db1a638 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2827,7 +2827,8 @@ case OP_Savepoint: { if( p1==SAVEPOINT_ROLLBACK ){ isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; for(ii=0; iinDb; ii++){ - rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT, + rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, + SQLITE_ABORT_ROLLBACK, isSchemaChange==0); if( rc!=SQLITE_OK ) goto abort_due_to_error; } diff --git a/test/savepoint7.test b/test/savepoint7.test index 908ec571f5..d8a02f1f80 100644 --- a/test/savepoint7.test +++ b/test/savepoint7.test @@ -78,7 +78,7 @@ do_test savepoint7-2.1 { } msg] db eval {RELEASE x1} list $rc $msg [db eval {SELECT * FROM t2}] -} {1 {callback requested query abort} {}} +} {1 {abort due to ROLLBACK} {}} do_test savepoint7-2.2 { db eval {DELETE FROM t2;} @@ -93,6 +93,6 @@ do_test savepoint7-2.2 { } } msg] list $rc $msg [db eval {SELECT * FROM t2}] -} {1 {callback requested query abort} {}} +} {1 {abort due to ROLLBACK} {}} finish_test From d816e00d13e0f1bb4704086760e0a394a61e9981 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 17 Nov 2014 19:25:15 +0000 Subject: [PATCH 64/71] Improved comments on the BtCursor.skipNext field. No changes to code. FossilOrigin-Name: e956e7db057d1112badf5e0671cea95201385b44 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/btreeInt.h | 10 ++++++++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 93ef894b6e..d851cc2e87 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sa\sSELECT\sstatement\sis\sterminated\sby\sa\sROLLBACK\sTO\soperation,\smake\sthe\nerror\smessage\sbe\s"abort\sdue\sto\sROLLBACK"\srather\sthan\s\n"callback\srequested\squery\sabort". -D 2014-11-17T17:13:06.964 +C Improved\scomments\son\sthe\sBtCursor.skipNext\sfield.\s\sNo\schanges\sto\scode. +D 2014-11-17T19:25:15.092 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -174,7 +174,7 @@ F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 F src/btree.c 2087125172421c78fc0c02f953b7d660f2a2598e F src/btree.h a4afc6b06f5a1dd2076d15aa168baec44fc0121b -F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 +F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14 @@ -1205,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 42588207ff5451cb785c394633e1ab631fb82f01 -R dfbcaabb48c2f5c435e2c7179a62bd27 +P 34fc4a082c192830e48f643549c04a4f91912b8b +R b667da582f38b5593e8a936d8e9b63b7 U drh -Z c435b7b174ccd5699f4e15dc48114455 +Z 1e479ba79d4cbfb8037d6ba7f0cc99ff diff --git a/manifest.uuid b/manifest.uuid index d4b77b5f9f..a049e1fe86 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -34fc4a082c192830e48f643549c04a4f91912b8b \ No newline at end of file +e956e7db057d1112badf5e0671cea95201385b44 \ No newline at end of file diff --git a/src/btreeInt.h b/src/btreeInt.h index 2368e6c884..a28a6a297e 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -489,6 +489,11 @@ struct CellInfo { ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. +** +** skipNext meaning: +** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op. +** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op. +** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ @@ -501,7 +506,8 @@ struct BtCursor { void *pKey; /* Saved key that was cursor last known position */ Pgno pgnoRoot; /* The root page of this tree */ int nOvflAlloc; /* Allocated size of aOverflow[] array */ - int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ + int skipNext; /* Prev() is noop if negative. Next() is noop if positive. + ** Error code if eState==CURSOR_FAULT */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 hints; /* As configured by CursorSetHints() */ @@ -547,7 +553,7 @@ struct BtCursor { ** on a different connection that shares the BtShared cache with this ** cursor. The error has left the cache in an inconsistent state. ** Do nothing else with this cursor. Any attempt to use the cursor -** should return the error code stored in BtCursor.skip +** should return the error code stored in BtCursor.skipNext */ #define CURSOR_INVALID 0 #define CURSOR_VALID 1 From 2b8669a9da3296ce0ca99da34f9b158ee1eb4d1e Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 17 Nov 2014 19:42:48 +0000 Subject: [PATCH 65/71] Avoid calling sqlite3BtreeKeysize() on a b-tree cursor in SKIPNEXT or SKIPPREV state. FossilOrigin-Name: 54e7d3fcb1ab21c03ffef1af93ae029a2901098a --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbe.c | 4 ++++ test/misc8.test | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 1b20e13d73..12a819fd2f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sautomatically\sremove\sthe\sDISTINCT\skeyword\sfrom\s"a\sIN\s(SELECT\sDISTINCT\s...)"\sexpressions.\sFix\sfor\s[db87229497]. -D 2014-11-14T15:28:33.929 +C Avoid\scalling\ssqlite3BtreeKeysize()\son\sa\sb-tree\scursor\sin\sSKIPNEXT\sor\sSKIPPREV\sstate. +D 2014-11-17T19:42:48.262 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -291,7 +291,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c -F src/vdbe.c 5e47308836e9bb5fdb4835fdf88eeab071848d3f +F src/vdbe.c 5d3991d723f00ef86263f4d494e105faba5a5abd F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 @@ -734,7 +734,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2 -F test/misc8.test e838ec20c9c988bc94812fdb89af26409c20931b +F test/misc8.test fc2754d38892f7dac30c22db3616c2764f117d66 F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912 F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 @@ -1221,7 +1221,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ef03a203351a6002e2b1075139717e4234c816cd -R bb54553354aa14551393c5e5701542c8 +P 55e453aadbb676dda07f0fa537d39ce184ef636c +R 6cd25f6196e6f786753b0fb88328cee1 U dan -Z f91e19e3f2d1e58cdccd86465c86ab70 +Z f594bfe54166ed1c0f3ae7a5a057ba04 diff --git a/manifest.uuid b/manifest.uuid index c5dbef8e09..e3e77af8a0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -55e453aadbb676dda07f0fa537d39ce184ef636c \ No newline at end of file +54e7d3fcb1ab21c03ffef1af93ae029a2901098a \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index e4cbeb6565..78c5511e5a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -4408,6 +4408,10 @@ case OP_Rowid: { /* out2-prerelease */ assert( pC->pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; + if( pC->nullRow ){ + pOut->flags = MEM_Null; + break; + } rc = sqlite3BtreeKeySize(pC->pCursor, &v); assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ } diff --git a/test/misc8.test b/test/misc8.test index 8c0c126a61..3ff52e56f1 100644 --- a/test/misc8.test +++ b/test/misc8.test @@ -58,4 +58,41 @@ do_catchsql_test misc8-1.7 { } {1 {abort due to ROLLBACK}} +reset_db + +proc dbeval {sql} { db eval $sql } +db func eval dbeval + +do_execsql_test misc8-2.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER) WITHOUT ROWID; + CREATE TABLE t2(c INTEGER PRIMARY KEY, d INTEGER, x BLOB); + INSERT INTO t1 VALUES(0,0); + INSERT INTO t1 VALUES(10,10); + INSERT INTO t2 VALUES(1,1,zeroblob(200)); + INSERT INTO t2 VALUES(2,2,zeroblob(200)); + INSERT INTO t2 VALUES(3,3,zeroblob(200)); + INSERT INTO t2 VALUES(4,4,zeroblob(200)); + INSERT INTO t2 VALUES(5,5,zeroblob(200)); + INSERT INTO t2 VALUES(6,6,zeroblob(200)); + INSERT INTO t2 VALUES(7,7,zeroblob(200)); + INSERT INTO t2 VALUES(8,8,zeroblob(200)); + INSERT INTO t2 VALUES(9,9,zeroblob(200)); + INSERT INTO t2 VALUES(10,10,zeroblob(200)); + SELECT a, c, eval( + printf('DELETE FROM t2 WHERE c=%d AND %d>5', a+c, a+c) + ) FROM t1, t2; +} { + 0 1 {} 10 1 {} + 0 2 {} 10 2 {} + 0 3 {} 10 3 {} + 0 4 {} 10 4 {} + 0 5 {} 10 5 {} + 0 6 {} 10 {} {} + 0 7 {} 10 {} {} + 0 8 {} 10 {} {} + 0 9 {} 10 {} {} + 0 10 {} 10 {} {} +} + + finish_test From 756d3b3e9d597a3bd04666f4909f43b4da07965e Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 17 Nov 2014 19:44:44 +0000 Subject: [PATCH 66/71] Avoid calling sqlite3BtreeKeysize() on a b-tree cursor in SKIPNEXT or SKIPPREV state. FossilOrigin-Name: 2f2ecb994889acb783616acb7307f8fed962d213 --- manifest | 15 ++++++++------- manifest.uuid | 2 +- src/vdbe.c | 4 ++++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d851cc2e87..55c07fe240 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\scomments\son\sthe\sBtCursor.skipNext\sfield.\s\sNo\schanges\sto\scode. -D 2014-11-17T19:25:15.092 +C Avoid\scalling\ssqlite3BtreeKeysize()\son\sa\sb-tree\scursor\sin\sSKIPNEXT\sor\sSKIPPREV\sstate. +D 2014-11-17T19:44:44.917 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a -F src/vdbe.c 3e8f9787d9a5fe24077f7af0baa2d11042471f12 +F src/vdbe.c 8bc291aa00646d07dab33047520960ea454c5a2f F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327 F src/vdbeInt.h e2a060a55ee18a6ab973353a5e2ec7ee569bf787 F src/vdbeapi.c 37a6c6ae284a97bcace365f2f0a225680c0499d9 @@ -1205,7 +1205,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 34fc4a082c192830e48f643549c04a4f91912b8b -R b667da582f38b5593e8a936d8e9b63b7 -U drh -Z 1e479ba79d4cbfb8037d6ba7f0cc99ff +P e956e7db057d1112badf5e0671cea95201385b44 +Q +54e7d3fcb1ab21c03ffef1af93ae029a2901098a +R b1492d8f4cbcc74596556f240b662de2 +U dan +Z 45bbf8c9451b95c29c15305e9bbd4586 diff --git a/manifest.uuid b/manifest.uuid index a049e1fe86..bec82c6bb3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e956e7db057d1112badf5e0671cea95201385b44 \ No newline at end of file +2f2ecb994889acb783616acb7307f8fed962d213 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 9a8db1a638..366c7a0166 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -4405,6 +4405,10 @@ case OP_Rowid: { /* out2-prerelease */ assert( pC->pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; + if( pC->nullRow ){ + pOut->flags = MEM_Null; + break; + } rc = sqlite3BtreeKeySize(pC->pCursor, &v); assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ } From c5352b996a590c7a9ab8233545c3cb40d3ce125c Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 17 Nov 2014 20:33:07 +0000 Subject: [PATCH 67/71] Remove code from sqlite3BtreeKeySize() made unreachable by the previous check-in. FossilOrigin-Name: 57c4aa988c8eda3cc513c1e5df5804d88bee99a0 --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/btree.c | 10 +++------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 55c07fe240..d98c6b6486 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\scalling\ssqlite3BtreeKeysize()\son\sa\sb-tree\scursor\sin\sSKIPNEXT\sor\sSKIPPREV\sstate. -D 2014-11-17T19:44:44.917 +C Remove\scode\sfrom\ssqlite3BtreeKeySize()\smade\sunreachable\sby\sthe\sprevious\ncheck-in. +D 2014-11-17T20:33:07.735 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,7 +172,7 @@ F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2 F src/backup.c 8cdfeb0c8a6d8bdad3faefae418eb3dc767051b6 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 2087125172421c78fc0c02f953b7d660f2a2598e +F src/btree.c c961588f01bd95d37b90359220c640f9763a3f58 F src/btree.h a4afc6b06f5a1dd2076d15aa168baec44fc0121b F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919 @@ -1205,8 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e956e7db057d1112badf5e0671cea95201385b44 -Q +54e7d3fcb1ab21c03ffef1af93ae029a2901098a -R b1492d8f4cbcc74596556f240b662de2 -U dan -Z 45bbf8c9451b95c29c15305e9bbd4586 +P 2f2ecb994889acb783616acb7307f8fed962d213 +R 3350d2f69701d38a07608c1007a483bc +U drh +Z df1a082a18c57f32c53583132171df67 diff --git a/manifest.uuid b/manifest.uuid index bec82c6bb3..2223a6ffff 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f2ecb994889acb783616acb7307f8fed962d213 \ No newline at end of file +57c4aa988c8eda3cc513c1e5df5804d88bee99a0 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 111870548b..7ea66e0d3b 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3883,13 +3883,9 @@ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ assert( cursorHoldsMutex(pCur) ); - assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); - if( pCur->eState!=CURSOR_VALID ){ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nKey; - } + assert( pCur->eState==CURSOR_VALID ); + getCellInfo(pCur); + *pSize = pCur->info.nKey; return SQLITE_OK; } From 4429c20b866e038b155d17a347686abc6102d455 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 18 Nov 2014 02:44:32 +0000 Subject: [PATCH 68/71] Add an ALWAYS() to an always-true conditional in the WAL rollback logic. FossilOrigin-Name: c5eae8a60d474131fbfa4d0c2b459005267e8be4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wal.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d98c6b6486..e7e986f7fe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\scode\sfrom\ssqlite3BtreeKeySize()\smade\sunreachable\sby\sthe\sprevious\ncheck-in. -D 2014-11-17T20:33:07.735 +C Add\san\sALWAYS()\sto\san\salways-true\sconditional\sin\sthe\sWAL\srollback\slogic. +D 2014-11-18T02:44:32.636 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -299,7 +299,7 @@ F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 975aeffa99acb0991b2f288d30294756bff41438 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c cb0c194303fea276b48d7d4b6d970b5a96bde8de -F src/wal.c 73051f1222321712fa4280c495780ba81d302dad +F src/wal.c 095d41f7114d7a8699207f5313488aa88372d540 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/where.c 2947912f1f3d6a7766fe087fd532a5d688d745b1 @@ -1205,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 2f2ecb994889acb783616acb7307f8fed962d213 -R 3350d2f69701d38a07608c1007a483bc +P 57c4aa988c8eda3cc513c1e5df5804d88bee99a0 +R f70435983903607c251f8514c7f3013d U drh -Z df1a082a18c57f32c53583132171df67 +Z f0ae269a66dc8c4b111d5661661171ab diff --git a/manifest.uuid b/manifest.uuid index 2223a6ffff..3ceeab2cdb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -57c4aa988c8eda3cc513c1e5df5804d88bee99a0 \ No newline at end of file +c5eae8a60d474131fbfa4d0c2b459005267e8be4 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index 24540a2cd5..d134a8b52a 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2506,7 +2506,7 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); for(iFrame=pWal->hdr.mxFrame+1; - rc==SQLITE_OK && iFrame<=iMax; + ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number From bb8f92529401b09dbc6e9df4ba3e38ae3a0789f3 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 18 Nov 2014 12:28:52 +0000 Subject: [PATCH 69/71] Increment the version number to 3.8.7.2 FossilOrigin-Name: 945a9e687fdfee5f7103d85d131024e85d594ac3 --- VERSION | 2 +- configure | 18 +++++++++--------- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/VERSION b/VERSION index f53c1ed56b..6df6debe9d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.7.1 +3.8.7.2 diff --git a/configure b/configure index d253f21a7d..1aedcaf4d3 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlite 3.8.7.1. +# Generated by GNU Autoconf 2.62 for sqlite 3.8.7.2. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.8.7.1' -PACKAGE_STRING='sqlite 3.8.7.1' +PACKAGE_VERSION='3.8.7.2' +PACKAGE_STRING='sqlite 3.8.7.2' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. @@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.8.7.1 to adapt to many kinds of systems. +\`configure' configures sqlite 3.8.7.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1548,7 +1548,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.7.1:";; + short | recursive ) echo "Configuration of sqlite 3.8.7.2:";; esac cat <<\_ACEOF @@ -1664,7 +1664,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.7.1 +sqlite configure 3.8.7.2 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.8.7.1, which was +It was created by sqlite $as_me 3.8.7.2, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ @@ -14021,7 +14021,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.8.7.1, which was +This file was extended by sqlite $as_me 3.8.7.2, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14074,7 +14074,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -sqlite config.status 3.8.7.1 +sqlite config.status 3.8.7.2 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/manifest b/manifest index e7e986f7fe..00bcf54505 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Add\san\sALWAYS()\sto\san\salways-true\sconditional\sin\sthe\sWAL\srollback\slogic. -D 2014-11-18T02:44:32.636 +C Increment\sthe\sversion\snumber\sto\s3.8.7.2 +D 2014-11-18T12:28:52.482 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.msc e31dee24038965fb6269d6d61073fd6b7e331dec F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0 F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8 -F VERSION 5cc0baaee7eeee3238f0f7b5871398d17f79d0cd +F VERSION 3978bf46d1599bc324ae171a99c4e8fca7481822 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure 56fe985cf0e59cd594f9b929099d0be40260e667 x +F configure 135207dac9b9ff35a91cdb17871322c26fa5de73 x F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 @@ -1205,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 57c4aa988c8eda3cc513c1e5df5804d88bee99a0 -R f70435983903607c251f8514c7f3013d +P c5eae8a60d474131fbfa4d0c2b459005267e8be4 +R 876a331fea8d7e2c7f47a110195c3ecb U drh -Z f0ae269a66dc8c4b111d5661661171ab +Z 48596521afe0080c14cc5d1c64dcfe43 diff --git a/manifest.uuid b/manifest.uuid index 3ceeab2cdb..a62a0bd661 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c5eae8a60d474131fbfa4d0c2b459005267e8be4 \ No newline at end of file +945a9e687fdfee5f7103d85d131024e85d594ac3 \ No newline at end of file From 58f95c43adb7e26452e3136f55ee40a12c479d7d Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 18 Nov 2014 20:16:27 +0000 Subject: [PATCH 70/71] Update a couple of test cases to account for the fact that ROLLBACK does not always abort all running SELECT statements. FossilOrigin-Name: abccda769a3f6b755c3bf70b5fb31a5e16718ef3 --- manifest | 17 +++++++++-------- manifest.uuid | 2 +- test/ioerr2.test | 8 +++++++- test/shared_err.test | 8 +++++++- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 12a819fd2f..267f0a0da9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\scalling\ssqlite3BtreeKeysize()\son\sa\sb-tree\scursor\sin\sSKIPNEXT\sor\sSKIPPREV\sstate. -D 2014-11-17T19:42:48.262 +C Update\sa\scouple\sof\stest\scases\sto\saccount\sfor\sthe\sfact\sthat\sROLLBACK\sdoes\snot\salways\sabort\sall\srunning\sSELECT\sstatements. +D 2014-11-18T20:16:27.742 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -659,7 +659,7 @@ F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844 F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8 F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d -F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d +F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26 F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 @@ -844,7 +844,7 @@ F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956 F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538 F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21 F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 -F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa +F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 F test/shell1.test d60946b5fde4d85fe06db7331dfe89011f564350 F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3 @@ -1221,7 +1221,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 55e453aadbb676dda07f0fa537d39ce184ef636c -R 6cd25f6196e6f786753b0fb88328cee1 -U dan -Z f594bfe54166ed1c0f3ae7a5a057ba04 +P 54e7d3fcb1ab21c03ffef1af93ae029a2901098a +Q +eba171e980fa4491dfee9d7e4df50c87a0ebbf87 +R 07c45ea3d962860999af22ae8c2af8c8 +U drh +Z f4bad3f3683413628206e5a23517cfd8 diff --git a/manifest.uuid b/manifest.uuid index e3e77af8a0..22da5e0eba 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -54e7d3fcb1ab21c03ffef1af93ae029a2901098a \ No newline at end of file +abccda769a3f6b755c3bf70b5fb31a5e16718ef3 \ No newline at end of file diff --git a/test/ioerr2.test b/test/ioerr2.test index 5150ace3ab..c08c3453f3 100644 --- a/test/ioerr2.test +++ b/test/ioerr2.test @@ -112,6 +112,12 @@ foreach bPersist [list 0 1] { } } +# When this test was written, an IO error within the UPDATE statement caused +# a rollback, which tripped all read-cursors, causing the outer SELECT to +# fail with "abort due to ROLLBACK". Now, the loop continues until the UPDATE +# is run successfully. At this point the next IO error occurs within the +# SELECT - throwing the "disk I/O error" that the test case now expects. +# do_test ioerr2-5 { execsql { CREATE TABLE t2 AS SELECT * FROM t1; @@ -130,7 +136,7 @@ do_test ioerr2-5 { } } msg] list $rc $msg -} {1 {abort due to ROLLBACK}} +} {1 {disk I/O error}} ;# used to be "{1 {abort due to ROLLBACK}}" if {$::tcl_platform(platform) == "unix"} { # Cause the call to xAccess used by [pragma temp_store_directory] to diff --git a/test/shared_err.test b/test/shared_err.test index 17add94bb7..96e5ee4540 100644 --- a/test/shared_err.test +++ b/test/shared_err.test @@ -446,9 +446,15 @@ do_malloc_test shared_err-8 -tclprep { } {1} db2 close } + +# When this test case was written, OOM errors in write statements would +# cause transaction rollback, which would trip cursors in other statements, +# aborting them. This no longer happens. +# do_test shared_malloc-8.X { # Test that one or more queries were aborted due to the malloc() failure. - expr $::aborted>=1 + # expr $::aborted>=1 + expr $::aborted==0 } {1} # This test is designed to catch a specific bug that was present during From bea3b976a95b00968d6f3ca496d5c1dfd3104527 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 18 Nov 2014 20:22:05 +0000 Subject: [PATCH 71/71] Fix a bug in the sqlite3TripAllCursors() routine that prevents it from reporting errors. It is unknown at this time whether or not this omission can result in any incorrect result in an actual query. FossilOrigin-Name: 2896f2640ab3e102ee248d20fb68c497817524eb --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/btree.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 267f0a0da9..9cb41e8715 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sa\scouple\sof\stest\scases\sto\saccount\sfor\sthe\sfact\sthat\sROLLBACK\sdoes\snot\salways\sabort\sall\srunning\sSELECT\sstatements. -D 2014-11-18T20:16:27.742 +C Fix\sa\sbug\sin\sthe\ssqlite3TripAllCursors()\sroutine\sthat\sprevents\sit\sfrom\nreporting\serrors.\s\sIt\sis\sunknown\sat\sthis\stime\swhether\sor\snot\sthis\somission\scan\nresult\sin\sany\sincorrect\sresult\sin\san\sactual\squery. +D 2014-11-18T20:22:05.030 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -173,7 +173,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c d5d991b518fa5bebc64037dfeb98a48051d864d7 +F src/btree.c 75edb585cc2c66615e0ea01a48807a7bfae4f2fe F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 @@ -1221,8 +1221,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 54e7d3fcb1ab21c03ffef1af93ae029a2901098a -Q +eba171e980fa4491dfee9d7e4df50c87a0ebbf87 -R 07c45ea3d962860999af22ae8c2af8c8 +P abccda769a3f6b755c3bf70b5fb31a5e16718ef3 +Q +42588207ff5451cb785c394633e1ab631fb82f01 +R be8390e45e84a659cdb889947026b04a U drh -Z f4bad3f3683413628206e5a23517cfd8 +Z 45d41fa50f6cb7c97c28d0b284fe4014 diff --git a/manifest.uuid b/manifest.uuid index 22da5e0eba..922bec9a78 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -abccda769a3f6b755c3bf70b5fb31a5e16718ef3 \ No newline at end of file +2896f2640ab3e102ee248d20fb68c497817524eb \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index f153a0cc45..7a49fb1a79 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3541,7 +3541,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID ){ - int rc = saveCursorPosition(p); + rc = saveCursorPosition(p); if( rc!=SQLITE_OK ){ (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); break;