From f5471925c9345d0e3ef456f03130b5fc65c276b5 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 9 Dec 2014 15:12:11 +0000 Subject: [PATCH 01/22] Add the SQLITE_REVERSE_UNORDERED_SELECTS compile-time option that causes the "PRAGMA reverse_unordered_selects" setting to be on by default. FossilOrigin-Name: 75a803e694d2c4e67579f45d54a0aaf120411a6e --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/main.c | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 0542dbf99d..1a0343a1f1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increase\sthe\sdefault\sminimum\sPMA\ssize\sfor\smulti-threaded\ssorting\sfrom\s10x\nthe\spage\ssize\sto\s250x\sthe\spage\ssize.\s\sProvide\sthe\sSQLITE_SORTER_PMASZ\ncompile-time\soption\sto\schange\sthis\sdefault. -D 2014-12-09T14:42:49.215 +C Add\sthe\sSQLITE_REVERSE_UNORDERED_SELECTS\scompile-time\soption\sthat\scauses\sthe\n"PRAGMA\sreverse_unordered_selects"\ssetting\sto\sbe\son\sby\sdefault. +D 2014-12-09T15:12:11.575 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -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 27c102143048802af53a8e55919ea3f6d9072951 +F src/main.c 378923ed4cb27ca7486062d07b1e67973c8beca7 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -1226,7 +1226,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 e97b7a8b4df784d148fefb9554da0f511e351d9f -R bd26f6a52391b4ad1637a19c173d9967 +P b05340fe3cd5f1676a55023228dc8d1a92de5936 +R 30f0205c6ecccf655d5a50e721435aae U drh -Z c16d1b57c275f469d491c230a3c4e6f8 +Z b3e21bd27e95301a6024ba1e3af7b9e7 diff --git a/manifest.uuid b/manifest.uuid index b381d7ac7e..c8f4fe7627 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b05340fe3cd5f1676a55023228dc8d1a92de5936 \ No newline at end of file +75a803e694d2c4e67579f45d54a0aaf120411a6e \ No newline at end of file diff --git a/src/main.c b/src/main.c index 3cbfe1d36d..7ca5217dfa 100644 --- a/src/main.c +++ b/src/main.c @@ -2742,6 +2742,9 @@ static int openDatabase( #endif #if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS | SQLITE_ForeignKeys +#endif +#if defined(SQLITE_REVERSE_UNORDERED_SELECTS) + | SQLITE_ReverseOrder #endif ; sqlite3HashInit(&db->aCollSeq); From 8c3026ecf33b34f42ea99b0e365cd39e51b3c969 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 9 Dec 2014 19:07:29 +0000 Subject: [PATCH 02/22] Make the sqlite3_table_column_metadata() interface available by default and without requiring the SQLITE_ENABLE_COLUMN_METADATA compile-time option. Other sqlite3_column_* interfaces that have a run-time penalty even if they are unused still require the SQLITE_ENABLE_COLUMN_METADATA option at compile-time. FossilOrigin-Name: 4f7549ff924b8ed8f90fc447cd4be11421453984 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/loadext.c | 1 - src/main.c | 2 -- src/sqlite.h.in | 3 --- src/test1.c | 4 ---- test/colmeta.test | 5 ----- 7 files changed, 11 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index 1a0343a1f1..a3d0a725cf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_REVERSE_UNORDERED_SELECTS\scompile-time\soption\sthat\scauses\sthe\n"PRAGMA\sreverse_unordered_selects"\ssetting\sto\sbe\son\sby\sdefault. -D 2014-12-09T15:12:11.575 +C Make\sthe\ssqlite3_table_column_metadata()\sinterface\savailable\sby\sdefault\sand\nwithout\srequiring\sthe\sSQLITE_ENABLE_COLUMN_METADATA\scompile-time\soption.\nOther\ssqlite3_column_*\sinterfaces\sthat\shave\sa\srun-time\spenalty\seven\sif\sthey\nare\sunused\sstill\srequire\sthe\sSQLITE_ENABLE_COLUMN_METADATA\soption\sat\ncompile-time. +D 2014-12-09T19:07:29.805 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,8 +194,8 @@ F src/insert.c 5b9243a33726008cc4132897d2be371db12a13be F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 -F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c 378923ed4cb27ca7486062d07b1e67973c8beca7 +F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 +F src/main.c ad4c0ed3b4731274aabb91b9158405a48dfaabad F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -230,7 +230,7 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75 F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf -F src/sqlite.h.in 6ec654324cb490ea3d8a7be28b8c7d37fe4ad282 +F src/sqlite.h.in a68ac3ba964e17c446457944b41ad50313a11b21 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f @@ -238,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 ebb8cd3c94a2ac8851b7b0b1349284e73a8b4c7a +F src/test1.c fa655a378b11bf811f0c15c56eb1d232118224cc F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -404,7 +404,7 @@ F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868 F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6 F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 -F test/colmeta.test 087c42997754b8c648819832241daf724f813322 +F test/colmeta.test 63f92e28d87de59430b1a1a9bb43ad7f8d19335e F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b F test/conflict.test 841bcf7cabbfca39c577eb8411ea8601843b46a8 F test/conflict2.test 0d3af4fb534fa1bd020c79960bb56e4d52655f09 @@ -1226,7 +1226,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 b05340fe3cd5f1676a55023228dc8d1a92de5936 -R 30f0205c6ecccf655d5a50e721435aae +P 75a803e694d2c4e67579f45d54a0aaf120411a6e +R 9dd53b5b296f2bafeeb64e18470c82ee U drh -Z b3e21bd27e95301a6024ba1e3af7b9e7 +Z b9a2aab60506af9678a60cdb34c9d56c diff --git a/manifest.uuid b/manifest.uuid index c8f4fe7627..c4f34c586d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -75a803e694d2c4e67579f45d54a0aaf120411a6e \ No newline at end of file +4f7549ff924b8ed8f90fc447cd4be11421453984 \ No newline at end of file diff --git a/src/loadext.c b/src/loadext.c index 2a2afd8654..7b39ff1671 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -34,7 +34,6 @@ # define sqlite3_column_table_name16 0 # define sqlite3_column_origin_name 0 # define sqlite3_column_origin_name16 0 -# define sqlite3_table_column_metadata 0 #endif #ifdef SQLITE_OMIT_AUTHORIZATION diff --git a/src/main.c b/src/main.c index 7ca5217dfa..6d10c15389 100644 --- a/src/main.c +++ b/src/main.c @@ -3149,7 +3149,6 @@ void sqlite3_thread_cleanup(void){ ** Return meta information about a specific column of a database table. ** See comment in sqlite3.h (sqlite.h.in) for details. */ -#ifdef SQLITE_ENABLE_COLUMN_METADATA int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ @@ -3256,7 +3255,6 @@ error_out: sqlite3_mutex_leave(db->mutex); return rc; } -#endif /* ** Sleep for a little while. Return the amount of time slept. diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e889b2670f..66a917e0cd 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5207,9 +5207,6 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** error occurs during this process, or if the requested table or column ** cannot be found, an [error code] is returned and an error message left ** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^ -** -** ^This API is only available if the library was compiled with the -** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined. */ int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ diff --git a/src/test1.c b/src/test1.c index 14ccacd863..9f97c7371f 100644 --- a/src/test1.c +++ b/src/test1.c @@ -1569,7 +1569,6 @@ static int test_libversion_number( ** Usage: sqlite3_table_column_metadata DB dbname tblname colname ** */ -#ifdef SQLITE_ENABLE_COLUMN_METADATA static int test_table_column_metadata( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ @@ -1618,7 +1617,6 @@ static int test_table_column_metadata( return TCL_OK; } -#endif #ifndef SQLITE_OMIT_INCRBLOB @@ -6778,9 +6776,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, -#ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, -#endif #ifndef SQLITE_OMIT_INCRBLOB { "sqlite3_blob_reopen", test_blob_reopen, 0 }, #endif diff --git a/test/colmeta.test b/test/colmeta.test index 3939f8228a..ec5891f058 100644 --- a/test/colmeta.test +++ b/test/colmeta.test @@ -17,11 +17,6 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !columnmetadata { - finish_test - return -} - # Set up a schema in the main and temp test databases. do_test colmeta-0 { execsql { From 80cdfd199b1527881947d48d3d8a73025920dd22 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 9 Dec 2014 19:16:41 +0000 Subject: [PATCH 03/22] Lower the default SQLITE_SORTER_PMASZ value back to 10, where it has been for the past couple of releases. Applications that need a larger value can set one. FossilOrigin-Name: 1ba8911c18f2fe34c20dc42f25a8f3c1c798fa7a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbesort.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index a3d0a725cf..b0f6c74e0a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sthe\ssqlite3_table_column_metadata()\sinterface\savailable\sby\sdefault\sand\nwithout\srequiring\sthe\sSQLITE_ENABLE_COLUMN_METADATA\scompile-time\soption.\nOther\ssqlite3_column_*\sinterfaces\sthat\shave\sa\srun-time\spenalty\seven\sif\sthey\nare\sunused\sstill\srequire\sthe\sSQLITE_ENABLE_COLUMN_METADATA\soption\sat\ncompile-time. -D 2014-12-09T19:07:29.805 +C Lower\sthe\sdefault\sSQLITE_SORTER_PMASZ\svalue\sback\sto\s10,\swhere\sit\shas\sbeen\sfor\nthe\spast\scouple\sof\sreleases.\s\sApplications\sthat\sneed\sa\slarger\svalue\scan\sset\none. +D 2014-12-09T19:16:41.997 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -298,7 +298,7 @@ F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 F src/vdbeaux.c 6f7f39c3fcf0f5923758df8561bb5d843908a553 F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f -F src/vdbesort.c db015e20a77b25eca4d1e125815f4998a3ca1354 +F src/vdbesort.c c150803a3e98fbc68bd07772cbbd4328a0a7212d F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9 F src/wal.c 847692349eb6e1fb8543dbc97e69ddbfa4cc7ea7 @@ -1226,7 +1226,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 75a803e694d2c4e67579f45d54a0aaf120411a6e -R 9dd53b5b296f2bafeeb64e18470c82ee +P 4f7549ff924b8ed8f90fc447cd4be11421453984 +R 07540d2951e499e9ba9f784727d9cc12 U drh -Z b9a2aab60506af9678a60cdb34c9d56c +Z 7254b0c65f796e3de7bb7b37671c0413 diff --git a/manifest.uuid b/manifest.uuid index c4f34c586d..f4de208a5d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4f7549ff924b8ed8f90fc447cd4be11421453984 \ No newline at end of file +1ba8911c18f2fe34c20dc42f25a8f3c1c798fa7a \ No newline at end of file diff --git a/src/vdbesort.c b/src/vdbesort.c index 29ec40c0d1..78ecc1efb9 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -451,7 +451,7 @@ struct SorterRecord { /* The minimum PMA size is set to this value multiplied by the database ** page size in bytes. */ #ifndef SQLITE_SORTER_PMASZ -# define SQLITE_SORTER_PMASZ 250 +# define SQLITE_SORTER_PMASZ 10 #endif /* Maximum number of PMAs that a single MergeEngine can merge */ From 9778bd7292dbf9b4386fab47f16e178c97f20c02 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 9 Dec 2014 20:13:40 +0000 Subject: [PATCH 04/22] Add extra tests to e_walckpt.test. FossilOrigin-Name: 84f9581019961efa31297f8be48427b17bcca857 --- manifest | 16 +-- manifest.uuid | 2 +- src/test1.c | 1 + test/e_walckpt.test | 318 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 301 insertions(+), 36 deletions(-) diff --git a/manifest b/manifest index b0f6c74e0a..0baa94d673 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Lower\sthe\sdefault\sSQLITE_SORTER_PMASZ\svalue\sback\sto\s10,\swhere\sit\shas\sbeen\sfor\nthe\spast\scouple\sof\sreleases.\s\sApplications\sthat\sneed\sa\slarger\svalue\scan\sset\none. -D 2014-12-09T19:16:41.997 +C Add\sextra\stests\sto\se_walckpt.test. +D 2014-12-09T20:13:40.856 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -238,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 fa655a378b11bf811f0c15c56eb1d232118224cc +F src/test1.c f60b9e973cf813fdabb2b67ccbb4a08e9f1d81be F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -478,7 +478,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52 F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a -F test/e_walckpt.test 18de8fca6b74f29bf7d24a2e267eec749b8fec50 +F test/e_walckpt.test 3116a98fa0dd9b2c9e493de7c59730adfe436746 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 @@ -1226,7 +1226,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 4f7549ff924b8ed8f90fc447cd4be11421453984 -R 07540d2951e499e9ba9f784727d9cc12 -U drh -Z 7254b0c65f796e3de7bb7b37671c0413 +P 1ba8911c18f2fe34c20dc42f25a8f3c1c798fa7a +R 3c53b0c88f36488767cc876fe1e6e0b0 +U dan +Z bbcee16517facfe70298aa47dfb20c31 diff --git a/manifest.uuid b/manifest.uuid index f4de208a5d..587f7e93dc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1ba8911c18f2fe34c20dc42f25a8f3c1c798fa7a \ No newline at end of file +84f9581019961efa31297f8be48427b17bcca857 \ No newline at end of file diff --git a/src/test1.c b/src/test1.c index 9f97c7371f..009b88a543 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5712,6 +5712,7 @@ static int test_wal_checkpoint_v2( rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ const char *zErrCode = sqlite3ErrName(rc); + Tcl_ResetResult(interp); Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), 0); return TCL_ERROR; } diff --git a/test/e_walckpt.test b/test/e_walckpt.test index f0edc46bee..e6b6566bed 100644 --- a/test/e_walckpt.test +++ b/test/e_walckpt.test @@ -42,6 +42,38 @@ proc compare_db_hashes {} { set ret } +#------------------------------------------------------------------------- +# All calls to the [sqlite3_wal_checkpoint_v2] command made within this +# file use this wrapper. It's sole purpose is to throw an error if the +# following requirement is violated: +# +# EVIDENCE-OF: R-60567-47780 Unless it returns SQLITE_MISUSE, the +# sqlite3_wal_checkpoint_v2() interface sets the error information that +# is queried by sqlite3_errcode() and sqlite3_errmsg(). +# +proc wal_checkpoint_v2 {db args} { + set rc [catch { + uplevel sqlite3_wal_checkpoint_v2 $db $args + } msg] + + set errcode "SQLITE_OK" + if {$rc} { + set errcode [lindex [split $msg " "] 0] + } elseif { [lindex $msg 0] } { + set errcode "SQLITE_BUSY" + } + + if {$errcode != "SQLITE_MISUSE" && [sqlite3_errcode $db] != $errcode} { + error "sqlite3_errcode mismatch! (1) $errcode!=[sqlite3_errcode $db]" + } + + if {$rc==0} { + return $msg + } else { + error $msg + } +} + # The following tests are run 3 times, each using a different method of # invoking a checkpoint: @@ -63,7 +95,7 @@ proc compare_db_hashes {} { foreach {tn script} { 1 { proc checkpoint {db mode args} { - eval sqlite3_wal_checkpoint_v2 [list $db] [list $mode] $args + eval wal_checkpoint_v2 [list $db] [list $mode] $args } } @@ -90,7 +122,7 @@ foreach {tn script} { error "$rc - [sqlite3_errmsg $db]" } } else { - eval sqlite3_wal_checkpoint_v2 [list $db] [list $mode] $args + eval wal_checkpoint_v2 [list $db] [list $mode] $args } } } @@ -270,36 +302,46 @@ foreach {tn script} { } 2 { - # Close first the reader, then later the writer. + # Close first the reader, then later the writer. Give up before + # closing the [db6] reader. if {$n==5} { catch {db2 eval commit} } if {$n==10} { catch {db3 eval commit} } + if {$n==15} { return 1 } return 0 } 3 { - # Close first the writer, then later the reader. + # Close first the writer, then later the reader. And finally the + # [db6] reader. if {$n==5} { catch {db2 eval commit} } if {$n==10} { catch {db3 eval commit} } + if {$n==15} { catch {db6 eval commit} } return 0 } } } foreach {mode busy_handler_mode} { - passive 1 - full 1 - full 2 - full 3 + passive 1 + full 1 full 2 full 3 + restart 1 restart 2 restart 3 + truncate 1 truncate 2 truncate 3 } { + set tp "$tn.$mode.$busy_handler_mode" set ::sync_counter 0 + # Set up a callback function for xSync and xWrite calls made during + # the checkpoint. + # + set ::checkpoint_ongoing 0 proc tvfs_callback {method args} { + if {$::checkpoint_ongoing==0} return + set tail [file tail [lindex $args 0]] if {$method == "xSync" && $tail == "test.db"} { incr ::sync_counter } - if {$method == "xWrite" && $tail=="test.db"} { if {$::write_ok < 0} { set ::write_ok [expr ![catch {db5 eval { BEGIN IMMEDIATE }}]] @@ -308,6 +350,14 @@ foreach {tn script} { if {$::read_ok < 0} { set ::read_ok [expr ![catch {db5 eval { SELECT * FROM t1 }}]] } + + # If one has not already been opened, open a read-transaction using + # connection [db6] + catch { db6 eval { BEGIN ; SELECT * FROM sqlite_master } } msg + } + if {$method == "xShmLock" } { + set details [lindex $args 2] + if {$details == "0 1 lock exclusive"} { set ::seen_writer_lock 1 } } } @@ -318,7 +368,7 @@ foreach {tn script} { #tvfs filter xSync tvfs script tvfs_callback - do_execsql_test $tn.4.$mode.0 { + do_execsql_test $tp.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); PRAGMA journal_mode = wal; @@ -328,7 +378,7 @@ foreach {tn script} { } {wal} # Open a reader on the current database snapshot. - do_test $tn.4.$mode.1 { + do_test $tp.1 { sqlite3 db2 test.db -vfs tvfs execsql { BEGIN; @@ -338,7 +388,7 @@ foreach {tn script} { # Open a writer. Write a transaction. Then begin, but do not commit, # a second transaction. - do_test $tn.4.$mode.2 { + do_test $tp.2 { sqlite3 db3 test.db -vfs tvfs execsql { INSERT INTO t2 VALUES(7, 8); @@ -349,6 +399,7 @@ foreach {tn script} { } {1 2 3 4 5 6 7 8 9 10} sqlite3 db5 test.db -vfs tvfs + sqlite3 db6 test.db -vfs tvfs # Register a busy-handler with connection [db]. # @@ -357,11 +408,15 @@ foreach {tn script} { set ::busy_handler_counter 0 set ::read_ok -1 set ::write_ok -1 + set ::seen_writer_lock 0 - do_test $tn.4.$mode.3 { + set ::checkpoint_ongoing 1 + do_test $tp.3 { checkpoint db $mode main set {} {} } {} + set ::checkpoint_ongoing 0 + set ::did_restart_blocking [expr {[catch {db6 eval commit}]}] if { $mode=="passive" } { # EVIDENCE-OF: R-16333-64433 Checkpoint as many frames as possible @@ -381,15 +436,15 @@ foreach {tn script} { # EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked # in the SQLITE_CHECKPOINT_PASSIVE mode. # - # It's not. Test case "$tn.4.$mode.6". + # It's not. Test case "$tp.6". # - do_test $tn.4.$mode.4 { + do_test $tp.4 { forcecopy test.db abc.db sqlite3 db4 abc.db db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } } {1 2 3 4 5 6} - do_test $tn.4.$mode.5 { set ::sync_counter } 0 - do_test $tn.4.$mode.6 { set ::busy_handler_counter } 0 + do_test $tp.5 { set ::sync_counter } 0 + do_test $tp.6 { set ::busy_handler_counter } 0 db4 close db2 eval COMMIT @@ -405,26 +460,53 @@ foreach {tn script} { # Also, because the checkpoint finishes this time, the db is synced. # Which is part of R-16333-64433 above. # - do_test $tn.4.$mode.7 { + set ::checkpoint_ongoing 1 + do_test $tp.7 { checkpoint db $mode main forcecopy test.db abc.db sqlite3 db4 abc.db db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } } {1 2 3 4 5 6 7 8 9 10} - do_test $tn.4.$mode.6 { set ::sync_counter } 1 - do_test $tn.4.$mode.7 { set ::busy_handler_counter } 0 + set ::checkpoint_ongoing 0 + do_test $tp.7 { set ::sync_counter } 1 + do_test $tp.8 { set ::busy_handler_counter } 0 db4 close } - if { $mode=="full" } { + if { $mode=="full" || $mode=="restart" || $mode=="truncate" } { + + # EVIDENCE-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and + # TRUNCATE modes also obtain the exclusive "writer" lock on the + # database file. + # + # Or at least attempts to obtain. + # + do_test $tp.9 { + set ::seen_writer_lock + } {1} + if {$busy_handler_mode==2 || $busy_handler_mode==3} { # EVIDENCE-OF: R-59171-47567 This mode blocks (it invokes the # busy-handler callback) until there is no database writer and all # readers are reading from the most recent database snapshot. # - # Show that both the reader and writer have finished: + # The test below shows that both the reader and writer have + # finished: # - do_test $tn.4.$mode.7 { + # Also restated by the following two. That both busy_handler_mode + # values 2 and 3 work show that both of the following are true - as + # they release the reader and writer transactions in different + # orders. + # + # EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained + # immediately, and a busy-handler is configured, it is invoked and the + # writer lock retried until either the busy-handler returns 0 or the + # lock is successfully obtained. + # + # EVIDENCE-OF: R-48107-00250 The busy-handler is also invoked while + # waiting for database readers as described above. + # + do_test $tp.7 { list [catchsql COMMIT db2] [catchsql COMMIT db3] } [list \ {1 {cannot commit - no transaction is active}} \ @@ -434,27 +516,79 @@ foreach {tn script} { # EVIDENCE-OF: R-29177-48281 It then checkpoints all frames in the log # file and syncs the database file. # - do_test $tn.4.$mode.8 { + do_test $tp.8 { forcecopy test.db abc.db sqlite3 db4 abc.db db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } } {1 2 3 4 5 6 7 8 9 10} - do_test $tn.4.$mode.9 { set ::sync_counter } 1 + do_test $tp.9 { set ::sync_counter } 1 db4 close # EVIDENCE-OF: R-51867-44713 This mode blocks new database writers # while it is pending, but new database readers are allowed to continue # unimpeded. - do_test $tn.4.$mode.10 { + # + # EVIDENCE-OF: R-47276-58266 Like SQLITE_CHECKPOINT_FULL, this mode + # blocks new database writer attempts while it is pending, but does not + # impede readers. + # + # The first of the above two refers to "full" mode. The second + # to "restart". + # + do_test $tp.10.1 { list $::write_ok $::read_ok } {0 1} + # EVIDENCE-OF: R-12410-31217 This mode works the same way as + # SQLITE_CHECKPOINT_FULL with the addition that after checkpointing the + # log file it blocks (calls the busy-handler callback) until all + # readers are reading from the database file only. + # + # The stuff above passed, so the first part of this requirement + # is met. The second part is tested below. If the checkpoint mode + # was "restart" or "truncate", then the busy-handler will have + # been called to block on wal-file readers. + # + do_test $tp.11 { + set ::did_restart_blocking + } [expr {($mode=="restart"||$mode=="truncate")&&$busy_handler_mode==3}] + + # EVIDENCE-OF: R-44699-57140 This mode works the same way as + # SQLITE_CHECKPOINT_RESTART with the addition that it also truncates + # the log file to zero bytes just prior to a successful return. + if {$mode=="truncate" && $busy_handler_mode==3} { + do_test $tp.12 { + file size test.db-wal + } 0 + } + } elseif {$busy_handler_mode==1} { + + # EVIDENCE-OF: R-34519-06271 SQLITE_BUSY is returned in this case. + if {$tn!=2} { + # ($tn==2) is the loop that uses "PRAGMA wal_checkpoint" + do_test $tp.13 { sqlite3_errcode db } {SQLITE_BUSY} + } + + # EVIDENCE-OF: R-49155-63541 If the busy-handler returns 0 before the + # writer lock is obtained or while waiting for database readers, the + # checkpoint operation proceeds from that point in the same way as + # SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible + # without blocking any further. + do_test $tp.14 { + forcecopy test.db abc.db + sqlite3 db4 abc.db + db4 eval { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } + } {1 2 3 4 5 6} + do_test $tp.15 { set ::sync_counter } 0 + do_test $tp.16 { set ::busy_handler_counter } 1 + db4 close } } db2 close db3 close db5 close + db6 close } db close @@ -480,9 +614,139 @@ foreach {tn mode res} { 8 1000000 {1 {SQLITE_MISUSE - not an error}} } { do_test 4.$tn { - list [catch "sqlite3_wal_checkpoint_v2 db $mode" msg] $msg + list [catch "wal_checkpoint_v2 db $mode" msg] $msg } $res } +db close + +foreach tn {1 2 3} { + forcedelete test.db test.db2 test.db3 + testvfs tvfs + + sqlite3 db test.db -vfs tvfs + execsql { + ATTACH 'test.db2' AS aux2; + ATTACH 'test.db3' AS aux3; + PRAGMA main.journal_mode = WAL; + PRAGMA aux2.journal_mode = WAL; + PRAGMA aux3.journal_mode = WAL; + + CREATE TABLE main.t1(x,y); + CREATE TABLE aux2.t2(x,y); + CREATE TABLE aux3.t3(x,y); + + INSERT INTO t1 VALUES('a', 'b'); + INSERT INTO t2 VALUES('a', 'b'); + INSERT INTO t3 VALUES('a', 'b'); + } + sqlite3 db2 test.db2 -vfs tvfs + + switch -- $tn { + 1 { + # EVIDENCE-OF: R-41299-52117 If no error (SQLITE_BUSY or otherwise) is + # encountered while processing the attached databases, SQLITE_OK is + # returned. + do_test 5.$tn.1 { + lindex [wal_checkpoint_v2 db truncate] 0 + } {0} ;# 0 -> SQLITE_OK + do_test 5.$tn.2 { + list [expr [file size test.db-wal]==0] \ + [expr [file size test.db2-wal]==0] \ + [expr [file size test.db3-wal]==0] + } {1 1 1} + } + + 2 { + # EVIDENCE-OF: R-38578-34175 If an SQLITE_BUSY error is encountered when + # processing one or more of the attached WAL databases, the operation is + # still attempted on any remaining attached databases and SQLITE_BUSY is + # returned at the end. + db2 eval { BEGIN; INSERT INTO t2 VALUES('d', 'e'); } + do_test 5.$tn.1 { + lindex [wal_checkpoint_v2 db truncate] 0 + } {1} ;# 1 -> SQLITE_BUSY + do_test 5.$tn.2 { + list [expr [file size test.db-wal]==0] \ + [expr [file size test.db2-wal]==0] \ + [expr [file size test.db3-wal]==0] + } {1 0 1} + db2 eval ROLLBACK + } + + 3 { + # EVIDENCE-OF: R-38049-07913 If any other error occurs while processing + # an attached database, processing is abandoned and the error code is + # returned to the caller immediately. + tvfs filter xWrite + tvfs script inject_ioerr + proc inject_ioerr {method file args} { + if {[file tail $file]=="test.db2"} { + return "SQLITE_IOERR" + } + return 0 + } + do_test 5.$tn.1 { + list [catch { wal_checkpoint_v2 db truncate } msg] $msg + } {1 {SQLITE_IOERR - disk I/O error}} + do_test 5.$tn.2 { + list [expr [file size test.db-wal]==0] \ + [expr [file size test.db2-wal]==0] \ + [expr [file size test.db3-wal]==0] + } {1 0 0} + tvfs script "" + } + } + + db close + db2 close +} + +reset_db +sqlite3 db2 test.db + +do_test 6.1 { + execsql { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } + file size test.db-wal +} [wal_file_size 3 1024] + +do_test 6.2 { + db2 eval { BEGIN; SELECT * FROM t1; } + db eval { INSERT INTO t1 VALUES(3, 4) } + file size test.db-wal +} [wal_file_size 4 1024] + +# At this point the log file contains 4 frames. 3 of which it should +# be possible to checkpoint. +# +# EVIDENCE-OF: R-16642-42503 If pnLog is not NULL, then *pnLog is set to +# the total number of frames in the log file or to -1 if the checkpoint +# could not run because of an error or because the database is not in +# WAL mode. +# +# EVIDENCE-OF: R-10514-25250 If pnCkpt is not NULL,then *pnCkpt is set +# to the total number of checkpointed frames in the log file (including +# any that were already checkpointed before the function was called) or +# to -1 if the checkpoint could not run due to an error or because the +# database is not in WAL mode. +# +do_test 6.4 { + lrange [wal_checkpoint_v2 db passive] 1 2 +} {4 3} + +# EVIDENCE-OF: R-37257-17813 Note that upon successful completion of an +# SQLITE_CHECKPOINT_TRUNCATE, the log file will have been truncated to +# zero bytes and so both *pnLog and *pnCkpt will be set to zero. +# +do_test 6.5 { + db2 eval COMMIT + wal_checkpoint_v2 db truncate +} {0 0 0} + finish_test + From 45d1b2063995f504a0722ac0fe5b65e7443f345d Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 9 Dec 2014 22:24:42 +0000 Subject: [PATCH 05/22] Fix the sqlite3_table_column_metadata() routine so that it gives the correct answer for the "rowid" column in a WITHOUT ROWID table. Enhance it so that it can be used to check for the existence of a table by setting the column name parameter to NULL. The routine is now included in the build by default, even without the SQLITE_ENABLE_COLUMN_METADATA compile-time option. FossilOrigin-Name: cf9be419a16156a9814e1378bb49b780de977343 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/main.c | 16 +++++++++------- src/sqlite.h.in | 33 ++++++++++++++++++++------------- src/test1.c | 4 ++-- test/colmeta.test | 35 ++++++++++++++++++++++++++++------- 6 files changed, 70 insertions(+), 40 deletions(-) diff --git a/manifest b/manifest index 0baa94d673..e4a81bbd8d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sextra\stests\sto\se_walckpt.test. -D 2014-12-09T20:13:40.856 +C Fix\sthe\ssqlite3_table_column_metadata()\sroutine\sso\sthat\sit\sgives\sthe\scorrect\nanswer\sfor\sthe\s"rowid"\scolumn\sin\sa\sWITHOUT\sROWID\stable.\s\sEnhance\sit\sso\sthat\nit\scan\sbe\sused\sto\scheck\sfor\sthe\sexistence\sof\sa\stable\sby\ssetting\sthe\scolumn\nname\sparameter\sto\sNULL.\s\sThe\sroutine\sis\snow\sincluded\sin\sthe\sbuild\sby\ndefault,\seven\swithout\sthe\sSQLITE_ENABLE_COLUMN_METADATA\scompile-time\soption. +D 2014-12-09T22:24:42.981 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -195,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 -F src/main.c ad4c0ed3b4731274aabb91b9158405a48dfaabad +F src/main.c 4bfb07de96118350a63103380819ff8cbbefc5cd F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -230,7 +230,7 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75 F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf -F src/sqlite.h.in a68ac3ba964e17c446457944b41ad50313a11b21 +F src/sqlite.h.in cc237b8aa62348685b36d06f1b6beb10dfea39ae F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f @@ -238,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 f60b9e973cf813fdabb2b67ccbb4a08e9f1d81be +F src/test1.c 7e806af12d7915445e46407d32b275d8ca9db4e7 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -404,7 +404,7 @@ F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868 F test/collate8.test df26649cfcbddf109c04122b340301616d3a88f6 F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 -F test/colmeta.test 63f92e28d87de59430b1a1a9bb43ad7f8d19335e +F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1 F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b F test/conflict.test 841bcf7cabbfca39c577eb8411ea8601843b46a8 F test/conflict2.test 0d3af4fb534fa1bd020c79960bb56e4d52655f09 @@ -1226,7 +1226,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 1ba8911c18f2fe34c20dc42f25a8f3c1c798fa7a -R 3c53b0c88f36488767cc876fe1e6e0b0 -U dan -Z bbcee16517facfe70298aa47dfb20c31 +P 84f9581019961efa31297f8be48427b17bcca857 +R 0b640911f896cbfee28a6d7f7893118c +U drh +Z 0a34c44c2738c668de181b5c6607c9d7 diff --git a/manifest.uuid b/manifest.uuid index 587f7e93dc..fbd6f6fb7b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -84f9581019961efa31297f8be48427b17bcca857 \ No newline at end of file +cf9be419a16156a9814e1378bb49b780de977343 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 6d10c15389..0727c0d75a 100644 --- a/src/main.c +++ b/src/main.c @@ -3188,11 +3188,8 @@ int sqlite3_table_column_metadata( } /* Find the column for which info is requested */ - if( sqlite3IsRowid(zColumnName) ){ - iCol = pTab->iPKey; - if( iCol>=0 ){ - pCol = &pTab->aCol[iCol]; - } + if( zColumnName==0 ){ + /* Query for existance of table only */ }else{ for(iCol=0; iColnCol; iCol++){ pCol = &pTab->aCol[iCol]; @@ -3201,8 +3198,13 @@ int sqlite3_table_column_metadata( } } if( iCol==pTab->nCol ){ - pTab = 0; - goto error_out; + if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ + iCol = pTab->iPKey; + pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; + }else{ + pTab = 0; + goto error_out; + } } } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 66a917e0cd..b3ff061151 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5152,9 +5152,17 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* ** CAPI3REF: Extract Metadata About A Column Of A Table ** -** ^This routine returns metadata about a specific column of a specific -** database table accessible using the [database connection] handle -** passed as the first function argument. +** ^The sqlite3_table_column_metadata(X,D,T,C,....) routine returns +** information about column C of table T in database D +** on [database connection] X. ^The sqlite3_table_column_metadata() +** interface returns SQLITE_OK and fills in the non-NULL pointers in +** the final five arguments with appropriate vaules if the specified +** column exists. ^The sqlite3_table_column_metadata() interface returns +** SQLITE_ERROR and if the specified column does not exist. +** If the column-name parameter to sqlite3_table_column_metadata() is a +** NULL pointer, then the routine simply checks for the existance of the +** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it +** does not. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^The second parameter is either the name of the database @@ -5164,8 +5172,7 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** resolve unqualified table references. ** ** ^The third and fourth parameters to this function are the table and column -** name of the desired column, respectively. Neither of these parameters -** may be NULL. +** name of the desired column, respectively. ** ** ^Metadata is returned by writing to the memory locations passed as the 5th ** and subsequent parameters to this function. ^Any of these arguments may be @@ -5184,16 +5191,17 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** )^ ** ** ^The memory pointed to by the character pointers returned for the -** declaration type and collation sequence is valid only until the next +** declaration type and collation sequence is valid until the next ** call to any SQLite API function. ** ** ^If the specified table is actually a view, an [error code] is returned. ** -** ^If the specified column is "rowid", "oid" or "_rowid_" and an +** ^If the specified column is "rowid", "oid" or "_rowid_" and the table +** is not a [WITHOUT ROWID] table and an ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output ** parameters are set for the explicitly declared column. ^(If there is no -** explicitly declared [INTEGER PRIMARY KEY] column, then the output -** parameters are set as follows: +** [INTEGER PRIMARY KEY] column, then the outputs +** for the [rowid] are set as follows: ** **
 **     data type: "INTEGER"
@@ -5203,10 +5211,9 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
 **     auto increment: 0
 ** 
)^ ** -** ^(This function may load one or more schemas from database files. If an -** error occurs during this process, or if the requested table or column -** cannot be found, an [error code] is returned and an error message left -** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^ +** ^This function causes all database schemas to be read from disk and +** parsed, if that has not already been done, and returns an error if +** any errors are encountered while loading the schema. */ int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ diff --git a/src/test1.c b/src/test1.c index 009b88a543..851249461c 100644 --- a/src/test1.c +++ b/src/test1.c @@ -1588,14 +1588,14 @@ static int test_table_column_metadata( int primarykey; int autoincrement; - if( objc!=5 ){ + if( objc!=5 && objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB dbname tblname colname"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zDb = Tcl_GetString(objv[2]); zTbl = Tcl_GetString(objv[3]); - zCol = Tcl_GetString(objv[4]); + zCol = objc==5 ? Tcl_GetString(objv[4]) : 0; if( strlen(zDb)==0 ) zDb = 0; diff --git a/test/colmeta.test b/test/colmeta.test index ec5891f058..21b0e0f38a 100644 --- a/test/colmeta.test +++ b/test/colmeta.test @@ -23,6 +23,8 @@ do_test colmeta-0 { CREATE TABLE abc(a, b, c); CREATE TABLE abc2(a PRIMARY KEY COLLATE NOCASE, b VARCHAR(32), c); CREATE TABLE abc3(a NOT NULL, b INTEGER PRIMARY KEY, c); + CREATE TABLE abc5(w,x,y,z,PRIMARY KEY(x,z)) WITHOUT ROWID; + CREATE TABLE abc6(rowid TEXT COLLATE rtrim, oid REAL, _rowid_ BLOB); } ifcapable autoinc { execsql { @@ -52,19 +54,27 @@ set tests { 13 {main abc rowid} {0 {INTEGER BINARY 0 1 0}} 14 {main abc3 rowid} {0 {INTEGER BINARY 0 1 0}} 16 {main abc d} {1 {no such table column: abc.d}} + 20 {main abc5 w} {0 {{} BINARY 0 0 0}} + 21 {main abc5 x} {0 {{} BINARY 1 1 0}} + 22 {main abc5 y} {0 {{} BINARY 0 0 0}} + 23 {main abc5 z} {0 {{} BINARY 1 1 0}} + 24 {main abc5 rowid} {1 {no such table column: abc5.rowid}} + 30 {main abc6 rowid} {0 {TEXT rtrim 0 0 0}} + 31 {main abc6 oid} {0 {REAL BINARY 0 0 0}} + 32 {main abc6 _rowid_} {0 {BLOB BINARY 0 0 0}} } -ifcapable view { +ifcapable autoinc { set tests [concat $tests { - 8 {{} abc4 b} {0 {INTEGER BINARY 0 1 1}} - 15 {main abc4 rowid} {0 {INTEGER BINARY 0 1 1}} + 100 {{} abc4 b} {0 {INTEGER BINARY 0 1 1}} + 101 {main abc4 rowid} {0 {INTEGER BINARY 0 1 1}} }] } ifcapable view { set tests [concat $tests { - 9 {{} v1 a} {1 {no such table column: v1.a}} - 10 {main v1 b} {1 {no such table column: v1.b}} - 11 {main v1 badname} {1 {no such table column: v1.badname}} - 12 {main v1 rowid} {1 {no such table column: v1.rowid}} + 200 {{} v1 a} {1 {no such table column: v1.a}} + 201 {main v1 b} {1 {no such table column: v1.b}} + 202 {main v1 badname} {1 {no such table column: v1.badname}} + 203 {main v1 rowid} {1 {no such table column: v1.rowid}} }] } @@ -86,4 +96,15 @@ foreach {tn params results} $tests { } $results } +# Calling sqlite3_table_column_metadata with a NULL column name merely +# checks for the existance of the table. +# +do_test colmeta-300 { + catch {sqlite3_table_column_metadata $::DB main xyzzy} res +} {1} +do_test colmeta-301 { + catch {sqlite3_table_column_metadata $::DB main abc} res +} {0} + + finish_test From 6f7febffa29cad09d5f9f49450e009cf5f9040f7 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 10 Dec 2014 04:58:43 +0000 Subject: [PATCH 06/22] Fix typos in the documentation for sqlite3_table_column_metadata(). No changes to code. FossilOrigin-Name: 3528f8dd39acace8eeb7337994c8617313f4b04b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index e4a81bbd8d..07a4a6fd33 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\ssqlite3_table_column_metadata()\sroutine\sso\sthat\sit\sgives\sthe\scorrect\nanswer\sfor\sthe\s"rowid"\scolumn\sin\sa\sWITHOUT\sROWID\stable.\s\sEnhance\sit\sso\sthat\nit\scan\sbe\sused\sto\scheck\sfor\sthe\sexistence\sof\sa\stable\sby\ssetting\sthe\scolumn\nname\sparameter\sto\sNULL.\s\sThe\sroutine\sis\snow\sincluded\sin\sthe\sbuild\sby\ndefault,\seven\swithout\sthe\sSQLITE_ENABLE_COLUMN_METADATA\scompile-time\soption. -D 2014-12-09T22:24:42.981 +C Fix\stypos\sin\sthe\sdocumentation\sfor\ssqlite3_table_column_metadata().\nNo\schanges\sto\scode. +D 2014-12-10T04:58:43.490 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,7 +230,7 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75 F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf -F src/sqlite.h.in cc237b8aa62348685b36d06f1b6beb10dfea39ae +F src/sqlite.h.in 6c1ca2ee6949a2232029ecd5391dcf3468bf4114 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f @@ -1226,7 +1226,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 84f9581019961efa31297f8be48427b17bcca857 -R 0b640911f896cbfee28a6d7f7893118c +P cf9be419a16156a9814e1378bb49b780de977343 +R 080e42720ecc05dbe5a6fab44e9bfd04 U drh -Z 0a34c44c2738c668de181b5c6607c9d7 +Z 55e0d7a4f974fc615b3f61db59cc799b diff --git a/manifest.uuid b/manifest.uuid index fbd6f6fb7b..9199a8d464 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf9be419a16156a9814e1378bb49b780de977343 \ No newline at end of file +3528f8dd39acace8eeb7337994c8617313f4b04b \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index b3ff061151..dd07976a1d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5152,22 +5152,22 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* ** CAPI3REF: Extract Metadata About A Column Of A Table ** -** ^The sqlite3_table_column_metadata(X,D,T,C,....) routine returns +** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns ** information about column C of table T in database D -** on [database connection] X. ^The sqlite3_table_column_metadata() +** on [database connection] X.)^ ^The sqlite3_table_column_metadata() ** interface returns SQLITE_OK and fills in the non-NULL pointers in -** the final five arguments with appropriate vaules if the specified +** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. -** If the column-name parameter to sqlite3_table_column_metadata() is a -** NULL pointer, then the routine simply checks for the existance of the +** ^If the column-name parameter to sqlite3_table_column_metadata() is a +** NULL pointer, then this routine simply checks for the existance of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it ** does not. ** ** ^The column is identified by the second, third and fourth parameters to -** this function. ^The second parameter is either the name of the database +** this function. ^(The second parameter is either the name of the database ** (i.e. "main", "temp", or an attached database) containing the specified -** table or NULL. ^If it is NULL, then all attached databases are searched +** table or NULL.)^ ^If it is NULL, then all attached databases are searched ** for the table using the same algorithm used by the database engine to ** resolve unqualified table references. ** From 684ec98fe3f0a11aa825a8747a6724225ee30a24 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Wed, 10 Dec 2014 17:34:48 +0000 Subject: [PATCH 07/22] Revise mutex handling by the sqlite3_win32_reset_heap() function. FossilOrigin-Name: eacb3b7baa910e84f984b8e45695a2a2f5a4c861 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_win.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 07a4a6fd33..18deb8120f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypos\sin\sthe\sdocumentation\sfor\ssqlite3_table_column_metadata().\nNo\schanges\sto\scode. -D 2014-12-10T04:58:43.490 +C Revise\smutex\shandling\sby\sthe\ssqlite3_win32_reset_heap()\sfunction. +D 2014-12-10T17:34:48.091 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -214,7 +214,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 a9e500dd963fb1f67d7860e58b5772abe6123862 +F src/os_win.c ecb04a0dad2fa6fa659931a9d8f0f3aca33f908a F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 F src/pager.c 7a5c5bc0e29b9b16834f5558a9d5d22bbae59a08 F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b @@ -1226,7 +1226,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 cf9be419a16156a9814e1378bb49b780de977343 -R 080e42720ecc05dbe5a6fab44e9bfd04 -U drh -Z 55e0d7a4f974fc615b3f61db59cc799b +P 3528f8dd39acace8eeb7337994c8617313f4b04b +R fe43d40d066c10ff075f9f4225f2f387 +U mistachkin +Z cb29644ec15937d54f010f859dadafbb diff --git a/manifest.uuid b/manifest.uuid index 9199a8d464..47c85f8870 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3528f8dd39acace8eeb7337994c8617313f4b04b \ No newline at end of file +eacb3b7baa910e84f984b8e45695a2a2f5a4c861 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index 2a7681c73f..80ce97a6cd 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1203,8 +1203,8 @@ int sqlite3_win32_reset_heap(){ int rc; MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ - MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) - MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) + MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); ) + MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); ) sqlite3_mutex_enter(pMaster); sqlite3_mutex_enter(pMem); winMemAssertMagic(); From 6e45e0c8d7cb8cc14ea80896cad8b269bc990c95 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 10 Dec 2014 20:29:49 +0000 Subject: [PATCH 08/22] Add new test file e_walhook.test. FossilOrigin-Name: 2eb6d3e4fbe388ef28e4b7b846e9e8a4361517a4 --- manifest | 17 ++-- manifest.uuid | 2 +- src/sqlite.h.in | 8 +- src/tclsqlite.c | 1 + test/e_walhook.test | 199 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+), 14 deletions(-) create mode 100644 test/e_walhook.test diff --git a/manifest b/manifest index 18deb8120f..f7c2015248 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Revise\smutex\shandling\sby\sthe\ssqlite3_win32_reset_heap()\sfunction. -D 2014-12-10T17:34:48.091 +C Add\snew\stest\sfile\se_walhook.test. +D 2014-12-10T20:29:49.614 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,14 +230,14 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75 F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf -F src/sqlite.h.in 6c1ca2ee6949a2232029ecd5391dcf3468bf4114 +F src/sqlite.h.in 2e699aabd1df6042aff4265cd93bdc8812629f11 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc -F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228 +F src/tclsqlite.c c6a21c64da1490e14d53cdc2062d1e2e57942622 F src/test1.c 7e806af12d7915445e46407d32b275d8ca9db4e7 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c @@ -479,6 +479,7 @@ F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a F test/e_walckpt.test 3116a98fa0dd9b2c9e493de7c59730adfe436746 +F test/e_walhook.test 9a859599e9a0f354ffcc7c716f7ec699e41f617c F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 @@ -1226,7 +1227,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 3528f8dd39acace8eeb7337994c8617313f4b04b -R fe43d40d066c10ff075f9f4225f2f387 -U mistachkin -Z cb29644ec15937d54f010f859dadafbb +P eacb3b7baa910e84f984b8e45695a2a2f5a4c861 +R de56ad0a085434d1b275f3b398c245cd +U dan +Z 076528022e1550b90a78f1e189e33666 diff --git a/manifest.uuid b/manifest.uuid index 47c85f8870..989cb2cfa4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eacb3b7baa910e84f984b8e45695a2a2f5a4c861 \ No newline at end of file +2eb6d3e4fbe388ef28e4b7b846e9e8a4361517a4 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index dd07976a1d..a4ca793969 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7180,12 +7180,10 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...); ** CAPI3REF: Write-Ahead Log Commit Hook ** ** ^The [sqlite3_wal_hook()] function is used to register a callback that -** will be invoked each time a database connection commits data to a -** [write-ahead log] (i.e. whenever a transaction is committed in -** [journal_mode | journal_mode=WAL mode]). +** is invoked each time data is committed to a database in wal mode. ** -** ^The callback is invoked by SQLite after the commit has taken place and -** the associated write-lock on the database released, so the implementation +** ^(The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released)^, so the implementation ** may read, write or [checkpoint] the database as required. ** ** ^The first parameter passed to the callback function when it is invoked diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 4fb78a5d12..32de527301 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -635,6 +635,7 @@ static int DbWalHandler( Tcl_Interp *interp = pDb->interp; assert(pDb->pWalHook); + assert( db==pDb->db ); p = Tcl_DuplicateObj(pDb->pWalHook); Tcl_IncrRefCount(p); Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); diff --git a/test/e_walhook.test b/test/e_walhook.test new file mode 100644 index 0000000000..e12d3b57e9 --- /dev/null +++ b/test/e_walhook.test @@ -0,0 +1,199 @@ +# 2014 December 04 +# +# 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 +source $testdir/wal_common.tcl +set testprefix e_walhook + + +# EVIDENCE-OF: R-00752-43975 The sqlite3_wal_hook() function is used to +# register a callback that is invoked each time data is committed to a +# database in wal mode. +# +# 1.1: shows that the wal-hook is not invoked in rollback mode. +# 1.2: but is invoked in wal mode. +# +set ::wal_hook_count 0 +proc my_wal_hook {args} { + incr ::wal_hook_count + return 0 +} + +do_test 1.1.1 { + db wal_hook my_wal_hook + execsql { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + } + set ::wal_hook_count +} 0 +do_test 1.1.2 { + execsql { PRAGMA journal_mode = wal } + set ::wal_hook_count +} 0 + +do_test 1.3 { + execsql { INSERT INTO t1 VALUES(2) } + set wal_hook_count +} 1 + +do_test 1.4 { + execsql { + BEGIN; + INSERT INTO t1 VALUES(3); + INSERT INTO t1 VALUES(4); + COMMIT; + } + set wal_hook_count +} 2 + +# EVIDENCE-OF: R-65366-15139 The callback is invoked by SQLite after the +# commit has taken place and the associated write-lock on the database +# released +# +set ::read_ok 0 +proc my_wal_hook {args} { + sqlite3 db2 test.db + if {[db2 eval { SELECT * FROM t1 }] == "1 2 3 4 5"} { + set ::read_ok 1 + } + db2 close +} +do_test 2.1 { + execsql { INSERT INTO t1 VALUES(5) } + set ::read_ok +} 1 + +# EVIDENCE-OF: R-44294-52863 The third parameter is the name of the +# database that was written to - either "main" or the name of an +# ATTACH-ed database. +# +# EVIDENCE-OF: R-18913-19355 The fourth parameter is the number of pages +# currently in the write-ahead log file, including those that were just +# committed. +# +set ::wal_hook_args [list] +proc my_wal_hook {dbname nEntry} { + set ::wal_hook_args [list $dbname $nEntry] +} +forcedelete test.db2 +do_test 3.0 { + execsql { + ATTACH 'test.db2' AS aux; + CREATE TABLE aux.t2(x); + PRAGMA aux.journal_mode = wal; + } +} {wal} + +# Database "aux" +do_test 3.1.1 { + set wal_hook_args [list] + execsql { INSERT INTO t2 VALUES('a') } +} {} +do_test 3.1.2 { + set wal_hook_args +} [list aux [wal_frame_count test.db2-wal 1024]] + +# Database "main" +do_test 3.2.1 { + set wal_hook_args [list] + execsql { INSERT INTO t1 VALUES(6) } +} {} +do_test 3.1.2 { + set wal_hook_args +} [list main [wal_frame_count test.db-wal 1024]] + +# EVIDENCE-OF: R-14034-00929 If an error code is returned, that error +# will propagate back up through the SQLite code base to cause the +# statement that provoked the callback to report an error, though the +# commit will have still occurred. +# +proc my_wal_hook {args} { return 1 ;# SQLITE_ERROR } +do_catchsql_test 4.1 { + INSERT INTO t1 VALUES(7) +} {1 {SQL logic error or missing database}} + +proc my_wal_hook {args} { return 5 ;# SQLITE_BUSY } +do_catchsql_test 4.2 { + INSERT INTO t1 VALUES(8) +} {1 {database is locked}} + +proc my_wal_hook {args} { return 14 ;# SQLITE_CANTOPEN } +do_catchsql_test 4.3 { + INSERT INTO t1 VALUES(9) +} {1 {unable to open database file}} + +do_execsql_test 4.4 { + SELECT * FROM t1 +} {1 2 3 4 5 6 7 8 9} + +# EVIDENCE-OF: R-10466-53920 Calling sqlite3_wal_hook() replaces any +# previously registered write-ahead log callback. +set ::old_wal_hook 0 +proc my_old_wal_hook {args} { + incr ::old_wal_hook + return 0 +} +db wal_hook my_old_wal_hook +do_test 5.1 { + execsql { INSERT INTO t1 VALUES(10) } + set ::old_wal_hook +} {1} + +# Replace old_wal_hook. Observe that it is not invoked after it has +# been replaced. +proc my_new_wal_hook {args} { return 0 } +db wal_hook my_new_wal_hook +do_test 5.2 { + execsql { INSERT INTO t1 VALUES(11) } + set ::old_wal_hook +} {1} + + + +# EVIDENCE-OF: R-42842-27162 Note that the sqlite3_wal_autocheckpoint() +# interface and the wal_autocheckpoint pragma both invoke +# sqlite3_wal_hook() and will those overwrite any prior +# sqlite3_wal_hook() settings. +# +set ::old_wal_hook 0 +proc my_old_wal_hook {args} { incr ::old_wal_hook ; return 0 } +do_test 6.1.1 { + execsql { INSERT INTO t1 VALUES(12) } + set ::old_wal_hook +} {1} +do_test 6.1.2 { + execsql { PRAGA wal_autocheckpoint = 1000 } + execsql { INSERT INTO t1 VALUES(12) } + set ::old_wal_hook +} {1} + +# EVIDENCE-OF: R-52629-38967 The first parameter passed to the callback +# function when it is invoked is a copy of the third parameter passed to +# sqlite3_wal_hook() when registering the callback. +# +# This is tricky to test using the tcl interface. However, the +# mechanism used to invoke the tcl script registered as a wal-hook +# depends on the context pointer being correctly passed through. And +# since multiple different wal-hook scripts have been successfully +# invoked by this test script, consider this tested. +# +# EVIDENCE-OF: R-23378-42536 The second is a copy of the database +# handle. +# +# There is an assert() in the C wal-hook used by tclsqlite.c to +# prove this. And that hook has been invoked multiple times when +# running this script. So consider this requirement tested as well. +# + +finish_test From 1f03b86523a0560f92eb3d8b2950a6a81ddc95c5 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 10 Dec 2014 20:57:20 +0000 Subject: [PATCH 09/22] Fix a typo causing a test error in e_walhook.test. FossilOrigin-Name: d9f916ba09f1a61684b4d59548ab6cf71cdb6a37 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/e_walhook.test | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index f7c2015248..528f1250c5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\stest\sfile\se_walhook.test. -D 2014-12-10T20:29:49.614 +C Fix\sa\stypo\scausing\sa\stest\serror\sin\se_walhook.test. +D 2014-12-10T20:57:20.700 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -479,7 +479,7 @@ F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a F test/e_walckpt.test 3116a98fa0dd9b2c9e493de7c59730adfe436746 -F test/e_walhook.test 9a859599e9a0f354ffcc7c716f7ec699e41f617c +F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40 @@ -1227,7 +1227,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 eacb3b7baa910e84f984b8e45695a2a2f5a4c861 -R de56ad0a085434d1b275f3b398c245cd +P 2eb6d3e4fbe388ef28e4b7b846e9e8a4361517a4 +R 6969ca3627ab2efde502167b1f0ba7a8 U dan -Z 076528022e1550b90a78f1e189e33666 +Z dbe3e99b743e5bbd88e69201e8af7d3a diff --git a/manifest.uuid b/manifest.uuid index 989cb2cfa4..b790577929 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2eb6d3e4fbe388ef28e4b7b846e9e8a4361517a4 \ No newline at end of file +d9f916ba09f1a61684b4d59548ab6cf71cdb6a37 \ No newline at end of file diff --git a/test/e_walhook.test b/test/e_walhook.test index e12d3b57e9..c8c8819493 100644 --- a/test/e_walhook.test +++ b/test/e_walhook.test @@ -168,12 +168,13 @@ do_test 5.2 { # set ::old_wal_hook 0 proc my_old_wal_hook {args} { incr ::old_wal_hook ; return 0 } +db wal_hook my_old_wal_hook do_test 6.1.1 { execsql { INSERT INTO t1 VALUES(12) } set ::old_wal_hook } {1} do_test 6.1.2 { - execsql { PRAGA wal_autocheckpoint = 1000 } + execsql { PRAGMA wal_autocheckpoint = 1000 } execsql { INSERT INTO t1 VALUES(12) } set ::old_wal_hook } {1} From 0a3520c0f4fa504e92646cf3c182ad2a9e98d0f6 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Dec 2014 15:27:04 +0000 Subject: [PATCH 10/22] Fix a typo in the documentation for sqlite3_threadsafe(). FossilOrigin-Name: 258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 528f1250c5..17ec6c7d04 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\scausing\sa\stest\serror\sin\se_walhook.test. -D 2014-12-10T20:57:20.700 +C Fix\sa\stypo\sin\sthe\sdocumentation\sfor\ssqlite3_threadsafe(). +D 2014-12-11T15:27:04.851 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -230,7 +230,7 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75 F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf -F src/sqlite.h.in 2e699aabd1df6042aff4265cd93bdc8812629f11 +F src/sqlite.h.in 116dc731361549ee3fc79dcebace11b57d24dcfd F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f @@ -1227,7 +1227,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 2eb6d3e4fbe388ef28e4b7b846e9e8a4361517a4 -R 6969ca3627ab2efde502167b1f0ba7a8 -U dan -Z dbe3e99b743e5bbd88e69201e8af7d3a +P d9f916ba09f1a61684b4d59548ab6cf71cdb6a37 +R be485ee74d8699a155e9699a0ceccb5f +U drh +Z 8b7cdafef867d0fe5e1164d6f32f45ce diff --git a/manifest.uuid b/manifest.uuid index b790577929..de0c011b0b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d9f916ba09f1a61684b4d59548ab6cf71cdb6a37 \ No newline at end of file +258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index a4ca793969..701e6de2e3 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -196,7 +196,7 @@ const char *sqlite3_compileoption_get(int N); ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but ** can be fully or partially disabled using a call to [sqlite3_config()] ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], -** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the +** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the ** sqlite3_threadsafe() function shows only the compile-time setting of ** thread safety, not any run-time changes to that setting made by ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() From 857536623a7cf447c028ca1d9fd251fdbcf9ea0b Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 11 Dec 2014 16:38:18 +0000 Subject: [PATCH 11/22] Fix a race condition to do with very large index keys in shared-cache mode. FossilOrigin-Name: fc157dd7f18c94b7ae5f155e1b4a5d7714b7da8c --- manifest | 21 ++++----- manifest.uuid | 2 +- src/btree.c | 8 ++-- src/vdbeapi.c | 1 - test/threadtest3.c | 2 + test/tt3_index.c | 2 +- test/tt3_lookaside1.c | 99 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 test/tt3_lookaside1.c diff --git a/manifest b/manifest index 17ec6c7d04..69fe030103 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sthe\sdocumentation\sfor\ssqlite3_threadsafe(). -D 2014-12-11T15:27:04.851 +C Fix\sa\srace\scondition\sto\sdo\swith\svery\slarge\sindex\skeys\sin\sshared-cache\smode. +D 2014-12-11T16:38:18.086 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 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 ea6692ce58bfba55b12c75d2947fec0906d1ef7a +F src/btree.c ab4b60fcf9920d862ff4d96efb1d605e4e7701a0 F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 @@ -294,7 +294,7 @@ F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c F src/vdbe.c 1a9e671c9cfc259e4d2affc71f7df4a4c00a842c F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 -F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 +F src/vdbeapi.c f8dd2d33a30938188fc292d524e88a91f2e65887 F src/vdbeaux.c 6f7f39c3fcf0f5923758df8561bb5d843908a553 F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f @@ -912,7 +912,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 -F test/threadtest3.c fca8d360b470405ae3ed431b5cb4cdf031f85a74 +F test/threadtest3.c 2b6e07e915c383c250a5b531cf6ef163a3047d7e F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 @@ -1076,7 +1076,8 @@ F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52 F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af -F test/tt3_index.c 2e7f3151a0ae522f031e8e2761ca2bda63f4d221 +F test/tt3_index.c 14f4b0cc3f4c05353e25778cf531c9d6e3b0d27f +F test/tt3_lookaside1.c 0b5b79ba37f21a1eb849cd4a54eed367f4d4aaaf F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a @@ -1227,7 +1228,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 d9f916ba09f1a61684b4d59548ab6cf71cdb6a37 -R be485ee74d8699a155e9699a0ceccb5f -U drh -Z 8b7cdafef867d0fe5e1164d6f32f45ce +P 258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 +R 016d1b9c16d412ff926cdf599ae97f64 +U dan +Z 8da7cca75b292da60a4687ff246cc6b3 diff --git a/manifest.uuid b/manifest.uuid index de0c011b0b..0de4da3602 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 \ No newline at end of file +fc157dd7f18c94b7ae5f155e1b4a5d7714b7da8c \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 4283d00fd3..a73c831219 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3913,7 +3913,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ releasePage(pCur->apPage[i]); } unlockBtreeIfUnused(pBt); - sqlite3DbFree(pBtree->db, pCur->aOverflow); + sqlite3_free(pCur->aOverflow); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } @@ -4208,6 +4208,7 @@ static int accessPayload( offset -= pCur->info.nLocal; } + if( rc==SQLITE_OK && amt>0 ){ const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ Pgno nextPage; @@ -4225,8 +4226,8 @@ static int accessPayload( if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; if( nOvfl>pCur->nOvflAlloc ){ - Pgno *aNew = (Pgno*)sqlite3DbRealloc( - pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno) + Pgno *aNew = (Pgno*)sqlite3Realloc( + pCur->aOverflow, nOvfl*2*sizeof(Pgno) ); if( aNew==0 ){ rc = SQLITE_NOMEM; @@ -4273,6 +4274,7 @@ static int accessPayload( */ assert( eOp!=2 ); assert( pCur->curFlags & BTCF_ValidOvfl ); + assert( pCur->pBtree->db==pBt->db ); if( pCur->aOverflow[iIdx+1] ){ nextPage = pCur->aOverflow[iIdx+1]; }else{ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 5744c28632..c611688193 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -580,7 +580,6 @@ int sqlite3_step(sqlite3_stmt *pStmt){ ** sqlite3_errmsg() and sqlite3_errcode(). */ const char *zErr = (const char *)sqlite3_value_text(db->pErr); - assert( zErr!=0 || db->mallocFailed ); sqlite3DbFree(db, v->zErrMsg); if( !db->mallocFailed ){ v->zErrMsg = sqlite3DbStrDup(db, zErr); diff --git a/test/threadtest3.c b/test/threadtest3.c index 084ca022a9..afa4197ee2 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -1398,6 +1398,7 @@ static void dynamic_triggers(int nMs){ #include "tt3_checkpoint.c" #include "tt3_index.c" +#include "tt3_lookaside1.c" int main(int argc, char **argv){ struct ThreadTest { @@ -1419,6 +1420,7 @@ int main(int argc, char **argv){ { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 }, { create_drop_index_1, "create_drop_index_1", 10000 }, + { lookaside1, "lookaside1", 10000 }, }; int i; diff --git a/test/tt3_index.c b/test/tt3_index.c index b79768c6c7..4bad64aabc 100644 --- a/test/tt3_index.c +++ b/test/tt3_index.c @@ -67,8 +67,8 @@ static void create_drop_index_1(int nMs){ launch_thread(&err, &threads, create_drop_index_thread, 0); launch_thread(&err, &threads, create_drop_index_thread, 0); launch_thread(&err, &threads, create_drop_index_thread, 0); - sqlite3_enable_shared_cache(0); join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); print_and_free_err(&err); } diff --git a/test/tt3_lookaside1.c b/test/tt3_lookaside1.c new file mode 100644 index 0000000000..486de808cd --- /dev/null +++ b/test/tt3_lookaside1.c @@ -0,0 +1,99 @@ +/* +** 2014 December 9 +** +** 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. +** +************************************************************************* +** +** lookaside1 +*/ + +/* +** The test in this file attempts to expose a specific race condition +** that is suspected to exist at time of writing. +*/ + +static char *lookaside1_thread_reader(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + opendb(&err, &db, "test.db", 0); + + while( !timetostop(&err) ){ + sqlite3_stmt *pStmt = 0; + int rc; + + sqlite3_prepare_v2(db.db, "SELECT 1 FROM t1", -1, &pStmt, 0); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + execsql(&err, &db, "SELECT length(x||y||z) FROM t2"); + } + rc = sqlite3_finalize(pStmt); + if( err.rc==SQLITE_OK && rc!=SQLITE_OK ){ + sqlite_error(&err, &db, "finalize"); + } + } + + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +static char *lookaside1_thread_writer(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + opendb(&err, &db, "test.db", 0); + + do{ + sql_script(&err, &db, + "BEGIN;" + "UPDATE t3 SET i=i+1 WHERE x=1;" + "ROLLBACK;" + ); + }while( !timetostop(&err) ); + + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + + +static void lookaside1(int nMs){ + Error err = {0}; + Sqlite db = {0}; + Threadset threads = {0}; + + opendb(&err, &db, "test.db", 1); + sql_script(&err, &db, + "CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;" + "WITH data(x,y) AS (" + " SELECT 1, quote(randomblob(750)) UNION ALL " + " SELECT x*2, y||y FROM data WHERE x<5) " + "INSERT INTO t1 SELECT y FROM data;" + + "CREATE TABLE t3(x PRIMARY KEY,i) WITHOUT ROWID;" + "INSERT INTO t3 VALUES(1, 1);" + + "CREATE TABLE t2(x,y,z);" + "INSERT INTO t2 VALUES(randomblob(50), randomblob(50), randomblob(50));" + ); + closedb(&err, &db); + + setstoptime(&err, nMs); + + sqlite3_enable_shared_cache(1); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_reader, 0); + launch_thread(&err, &threads, lookaside1_thread_writer, 0); + join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); + print_and_free_err(&err); +} From 1e57430e6326c0cb3b07de81fcae2baf4f5c0d15 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Dec 2014 19:29:42 +0000 Subject: [PATCH 12/22] Add the threadtest4.c test program. Not yet working. FossilOrigin-Name: ec3a74469ca2f0f3fb7d82a05fdac7500354e78f --- manifest | 14 +- manifest.uuid | 2 +- test/threadtest4.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 445 insertions(+), 6 deletions(-) create mode 100644 test/threadtest4.c diff --git a/manifest b/manifest index 17ec6c7d04..a949b5b360 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sthe\sdocumentation\sfor\ssqlite3_threadsafe(). -D 2014-12-11T15:27:04.851 +C Add\sthe\sthreadtest4.c\stest\sprogram.\s\sNot\syet\sworking. +D 2014-12-11T19:29:42.156 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -913,6 +913,7 @@ F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c fca8d360b470405ae3ed431b5cb4cdf031f85a74 +F test/threadtest4.c e2bcee459bbd27fa2d55751e9900a4a5a4675cd5 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 @@ -1227,7 +1228,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 d9f916ba09f1a61684b4d59548ab6cf71cdb6a37 -R be485ee74d8699a155e9699a0ceccb5f +P 258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 +R 4bb41891ae2017245bf160d9a28a8371 +T *branch * threadtest4 +T *sym-threadtest4 * +T -sym-trunk * U drh -Z 8b7cdafef867d0fe5e1164d6f32f45ce +Z 474616aece6be366bfcf36cb343f9bea diff --git a/manifest.uuid b/manifest.uuid index de0c011b0b..ea9eb0df3e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 \ No newline at end of file +ec3a74469ca2f0f3fb7d82a05fdac7500354e78f \ No newline at end of file diff --git a/test/threadtest4.c b/test/threadtest4.c new file mode 100644 index 0000000000..e4cd644a4f --- /dev/null +++ b/test/threadtest4.c @@ -0,0 +1,435 @@ +/* +** 2014-12-11 +** +** 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 a simple standalone program used to stress the +** SQLite library when accessing the same set of databases simultaneously +** from multiple threads in shared-cache mode. +** +** This test program runs on unix-like systems only. It uses pthreads. +** To compile: +** +** gcc -o tt4 -I. threadtest4.c sqlite3.c -ldl -lpthread +** +** To run: +** +** ./tt4 10 +** +** The argument is the number of threads. +*/ +#include "sqlite3.h" +#include +#include +#include +#include +#include +#include +#include + +/* +** An instance of the following structure is passed into each worker +** thread. +*/ +typedef struct WorkerInfo WorkerInfo; +struct WorkerInfo { + int tid; /* Thread ID */ + unsigned wkrFlags; /* Flags */ + sqlite3 *mainDb; /* Database connection of the main thread */ + sqlite3 *db; /* Database connection of this thread */ + int nErr; /* Number of errors seen by this thread */ + int nTest; /* Number of tests run by this thread */ + char *zMsg; /* Message returned by this thread */ + pthread_t id; /* Thread id */ + pthread_mutex_t *pWrMutex; /* Hold this mutex while writing */ +}; + +/* +** Allowed values for WorkerInfo.wkrFlags +*/ +#define TT4_SERIALIZED 0x0000001 /* The --serialized option is used */ +#define TT4_WAL 0x0000002 /* WAL mode in use */ +#define TT4_TRACE 0x0000004 /* Trace activity */ + + +/* +** Report an OOM error and die if the argument is NULL +*/ +static void check_oom(void *x){ + if( x==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } +} + +/* +** Allocate memory. If the allocation fails, print an error message and +** kill the process. +*/ +static void *safe_malloc(int sz){ + void *x = sqlite3_malloc(sz>0?sz:1); + check_oom(x); + return x; +} + +/* +** Print a trace message for a worker +*/ +static void worker_trace(WorkerInfo *p, const char *zFormat, ...){ + va_list ap; + char *zMsg; + if( (p->wkrFlags & TT4_TRACE)==0 ) return; + va_start(ap, zFormat); + zMsg = sqlite3_vmprintf(zFormat, ap); + check_oom(zMsg); + va_end(ap); + fprintf(stderr, "TRACE(%02d): %s\n", p->tid, zMsg); + sqlite3_free(zMsg); +} + +/* +** Prepare a single SQL query +*/ +static sqlite3_stmt *prep_sql(sqlite3 *db, const char *zFormat, ...){ + va_list ap; + char *zSql; + int rc; + sqlite3_stmt *pStmt = 0; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + check_oom(zSql); + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "SQL error (%d,%d): %s\nWhile preparing: [%s]\n", + rc, sqlite3_extended_errcode(db), sqlite3_errmsg(db), zSql); + exit(1); + } + sqlite3_free(zSql); + return pStmt; +} + +/* +** Run a SQL statements. Panic if unable. +*/ +static void run_sql(WorkerInfo *p, const char *zFormat, ...){ + va_list ap; + char *zSql; + int rc; + sqlite3_stmt *pStmt = 0; + int nRetry = 0; + + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + check_oom(zSql); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "SQL error (%d,%d): %s\nWhile preparing: [%s]\n", + rc, sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zSql); + exit(1); + } + worker_trace(p, "running [%s]", zSql); + while( (rc = sqlite3_step(pStmt))!=SQLITE_DONE ){ + if( (rc&0xff)==SQLITE_BUSY || (rc&0xff)==SQLITE_LOCKED ){ + sqlite3_reset(pStmt); + nRetry++; + if( nRetry<10 ){ + worker_trace(p, "retry %d for [%s]", nRetry, zSql); + sched_yield(); + continue; + }else{ + fprintf(stderr, "Deadlock in thread %d while running [%s]\n", + p->tid, zSql); + exit(1); + } + } + if( rc!=SQLITE_ROW ){ + fprintf(stderr, "SQL error (%d,%d): %s\nWhile running [%s]\n", + rc, sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zSql); + exit(1); + } + } + sqlite3_free(zSql); + sqlite3_finalize(pStmt); +} + + +/* +** Open the database connection for WorkerInfo. The order in which +** the files are opened is a function of the tid value. +*/ +static void worker_open_connection(WorkerInfo *p, int iCnt){ + char *zFile; + int x; + int rc; + static const unsigned char aOrder[6][3] = { + { 1, 2, 3}, + { 1, 3, 2}, + { 2, 1, 3}, + { 2, 3, 1}, + { 3, 1, 2}, + { 3, 2, 1} + }; + x = (p->tid + iCnt) % 6; + zFile = sqlite3_mprintf("tt4-test%d.db", aOrder[x][0]); + check_oom(zFile); + worker_trace(p, "open %s", zFile); + rc = sqlite3_open_v2(zFile, &p->db, + SQLITE_OPEN_READWRITE|SQLITE_OPEN_SHAREDCACHE, 0); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "sqlite_open_v2(%s) failed on thread %d\n", + zFile, p->tid); + exit(1); + } + sqlite3_free(zFile); + run_sql(p, "PRAGMA read_uncommitted=ON;"); + sqlite3_busy_timeout(p->db, 10000); + run_sql(p, "PRAGMA synchronous=OFF;"); + run_sql(p, "ATTACH 'tt4-test%d.db' AS aux1", aOrder[x][1]); + run_sql(p, "ATTACH 'tt4-test%d.db' AS aux2", aOrder[x][2]); +} + +/* +** Close the worker database connection +*/ +static void worker_close_connection(WorkerInfo *p){ + if( p->db ){ + worker_trace(p, "close"); + sqlite3_close(p->db); + p->db = 0; + } +} + +/* +** Delete all content in the three databases associated with a +** single thread. Make this happen all in a single transaction if +** inTrans is true, or separately for each database if inTrans is +** false. +*/ +static void worker_delete_all_content(WorkerInfo *p, int inTrans){ + if( inTrans ){ + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "BEGIN"); + run_sql(p, "DELETE FROM t1 WHERE tid=%d", p->tid); + run_sql(p, "DELETE FROM t2 WHERE tid=%d", p->tid); + run_sql(p, "DELETE FROM t3 WHERE tid=%d", p->tid); + run_sql(p, "COMMIT"); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + }else{ + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "DELETE FROM t1 WHERE tid=%d", p->tid); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "DELETE FROM t2 WHERE tid=%d", p->tid); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "DELETE FROM t3 WHERE tid=%d", p->tid); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; + } +} + +/* +** Create rows mn through mx in table iTab for the given worker +*/ +static void worker_add_content(WorkerInfo *p, int mn, int mx, int iTab){ + char *zTabDef; + switch( iTab ){ + case 1: zTabDef = "t1(tid,sp,a,b,c)"; break; + case 2: zTabDef = "t2(tid,sp,d,e,f)"; break; + case 3: zTabDef = "t3(tid,sp,x,y,z)"; break; + } + pthread_mutex_lock(p->pWrMutex); + run_sql(p, + "WITH RECURSIVE\n" + " c(i) AS (VALUES(%d) UNION ALL SELECT i+1 FROM c WHERE i<%d)\n" + "INSERT INTO %s SELECT %d, zeroblob(3000), i, printf('%%d',i), i FROM c;", + mn, mx, zTabDef, p->tid + ); + pthread_mutex_unlock(p->pWrMutex); + p->nTest++; +} + +/* +** Set an error message on a worker +*/ +static void worker_error(WorkerInfo *p, const char *zFormat, ...){ + va_list ap; + p->nErr++; + sqlite3_free(p->zMsg); + va_start(ap, zFormat); + p->zMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** Each thread runs the following function. +*/ +static void *worker_thread(void *pArg){ + WorkerInfo *p = (WorkerInfo*)pArg; + int iOuter; + int i; + int rc; + sqlite3_stmt *pStmt; + + printf("worker %d startup\n", p->tid); fflush(stdout); + for(iOuter=1; iOuter<=4; iOuter++){ + worker_open_connection(p, iOuter); + for(i=0; i<4; i++){ + worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter)%3 + 1); + worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+1)%3 + 1); + worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+2)%3 + 1); + } + + pStmt = prep_sql(p->db, "SELECT count(a) FROM t1 WHERE tid=%d", p->tid); + worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW ){ + worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); + }else if( sqlite3_column_int(pStmt, 0)!=400 ){ + worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0)); + } + if( p->nErr ) break; + + worker_delete_all_content(p, (p->tid+iOuter)%2); + worker_close_connection(p); + p->db = 0; + } + worker_close_connection(p); + printf("worker %d finished\n", p->tid); fflush(stdout); + return 0; +} + +int main(int argc, char **argv){ + int nWorker = 0; /* Number of worker threads */ + int i; /* Loop counter */ + WorkerInfo *aInfo; /* Information for each worker */ + unsigned wkrFlags = 0; /* Default worker flags */ + int nErr = 0; /* Number of errors */ + int nTest = 0; /* Number of tests */ + int rc; /* Return code */ + sqlite3 *db = 0; /* Main database connection */ + pthread_mutex_t wrMutex; /* The write serialization mutex */ + WorkerInfo infoTop; /* WorkerInfo for the main thread */ + WorkerInfo *p; /* Pointer to infoTop */ + + sqlite3_config(SQLITE_CONFIG_MULTITHREAD); + for(i=1; i='1' && z[0]<='9' && nWorker==0 ){ + nWorker = atoi(z); + if( nWorker<2 ){ + fprintf(stderr, "minimum of 2 threads\n"); + exit(1); + } + }else{ + fprintf(stderr, "extra command-line argument: \"%s\"\n", argv[i]); + exit(1); + } + } + if( nWorker==0 ){ + fprintf(stderr, + "usage: %s ?OPTIONS? N\n" + "N is the number of threads and must be at least 2.\n" + "Options:\n" + " --serialized\n" + " --multithread\n" + ,argv[0] + ); + exit(1); + } + if( !sqlite3_threadsafe() ){ + fprintf(stderr, "requires a threadsafe build of SQLite\n"); + exit(1); + } + sqlite3_initialize(); + sqlite3_enable_shared_cache(1); + pthread_mutex_init(&wrMutex, 0); + + /* Initialize the test database files */ + (void)unlink("tt4-test1.db"); + (void)unlink("tt4-test2.db"); + (void)unlink("tt4-test3.db"); + rc = sqlite3_open("tt4-test1.db", &db); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "Unable to open test database: tt4-test2.db\n"); + exit(1); + } + memset(&infoTop, 0, sizeof(infoTop)); + infoTop.db = db; + infoTop.wkrFlags = wkrFlags; + p = &infoTop; + if( wkrFlags & TT4_WAL ){ + run_sql(p, "PRAGMA journal_mode=WAL"); + } + run_sql(p, "PRAGMA synchronous=OFF"); + run_sql(p, "CREATE TABLE IF NOT EXISTS t1(tid INTEGER, sp, a, b, c)"); + run_sql(p, "CREATE INDEX t1tid ON t1(tid)"); + run_sql(p, "CREATE INDEX t1ab ON t1(a,b)"); + run_sql(p, "ATTACH 'tt4-test2.db' AS 'test2'"); + run_sql(p, "CREATE TABLE IF NOT EXISTS test2.t2(tid INTEGER, sp, d, e, f)"); + run_sql(p, "CREATE INDEX test2.t2tid ON t2(tid)"); + run_sql(p, "CREATE INDEX test2.t2de ON t2(d,e)"); + run_sql(p, "ATTACH 'tt4-test3.db' AS 'test3'"); + run_sql(p, "CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)"); + run_sql(p, "CREATE INDEX test3.t3tid ON t3(tid)"); + run_sql(p, "CREATE INDEX test3.t3xy ON t3(x,y)"); + aInfo = safe_malloc( sizeof(*aInfo)*nWorker ); + memset(aInfo, 0, sizeof(*aInfo)*nWorker); + for(i=0; i Date: Fri, 12 Dec 2014 00:20:37 +0000 Subject: [PATCH 13/22] Fix a bug in the threadtest4.c program. Remove the keyinfo cache as it provides minimal performance improvements, and then only at SQL preparation time, not at runtime, and it has problems with data races in shared-cache mode. We might later add the keyinfo cache back but only enable it when shared-cache mode is off. FossilOrigin-Name: b7489f9451628c68f1dfc1d457fc161a0921c631 --- manifest | 23 ++++++++++----------- manifest.uuid | 2 +- src/build.c | 50 +++++++++++++++++++--------------------------- src/main.c | 37 ---------------------------------- src/sqliteInt.h | 1 - src/where.c | 1 - test/threadtest4.c | 1 + 7 files changed, 32 insertions(+), 83 deletions(-) diff --git a/manifest b/manifest index a949b5b360..9e5cb882e3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sthreadtest4.c\stest\sprogram.\s\sNot\syet\sworking. -D 2014-12-11T19:29:42.156 +C Fix\sa\sbug\sin\sthe\sthreadtest4.c\sprogram.\s\sRemove\sthe\skeyinfo\scache\sas\sit\sprovides\nminimal\sperformance\simprovements,\sand\sthen\sonly\sat\sSQL\spreparation\stime,\snot\nat\sruntime,\sand\sit\shas\sproblems\swith\sdata\sraces\sin\sshared-cache\smode.\s\sWe\smight\nlater\sadd\sthe\skeyinfo\scache\sback\sbut\sonly\senable\sit\swhen\sshared-cache\smode\nis\soff. +D 2014-12-12T00:20:37.023 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 F src/btree.c ea6692ce58bfba55b12c75d2947fec0906d1ef7a F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 -F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 +F src/build.c 162d84e4833b03f9d07192ef06057b0226f6e543 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c c4ba6e0626bb94bc77a0861735f3382fcf7cc818 F src/ctime.c df19848891c8a553c80e6f5a035e768280952d1a @@ -195,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 -F src/main.c 4bfb07de96118350a63103380819ff8cbbefc5cd +F src/main.c 1f40f66165a6609203a5ff7ecb0292b90b302130 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -233,7 +233,7 @@ F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf F src/sqlite.h.in 116dc731361549ee3fc79dcebace11b57d24dcfd F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f +F src/sqliteInt.h 073d54f7a631b978b66d50d255c84549fb9e5429 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc @@ -304,7 +304,7 @@ F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9 F src/wal.c 847692349eb6e1fb8543dbc97e69ddbfa4cc7ea7 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c e914fdb9159bb36af4a673193bbda08aaf9e5a73 +F src/where.c d46de821bc604a4fd36fa3928c086950e91aafb1 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -913,7 +913,7 @@ F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c fca8d360b470405ae3ed431b5cb4cdf031f85a74 -F test/threadtest4.c e2bcee459bbd27fa2d55751e9900a4a5a4675cd5 +F test/threadtest4.c 38cb574939d5e0c8bd3baa5eb45def2ac6da4db4 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 @@ -1228,10 +1228,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 258e747bb7e3a2bc46f932cc2b06c2689d43aeb0 -R 4bb41891ae2017245bf160d9a28a8371 -T *branch * threadtest4 -T *sym-threadtest4 * -T -sym-trunk * +P ec3a74469ca2f0f3fb7d82a05fdac7500354e78f +R e481d4adf19d880dc699635431f7c379 U drh -Z 474616aece6be366bfcf36cb343f9bea +Z 4073b2f4a4cd5608e79ca3cad9ca9b28 diff --git a/manifest.uuid b/manifest.uuid index ea9eb0df3e..7461209f05 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ec3a74469ca2f0f3fb7d82a05fdac7500354e78f \ No newline at end of file +b7489f9451628c68f1dfc1d457fc161a0921c631 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 0b4affc664..db954647cc 100644 --- a/src/build.c +++ b/src/build.c @@ -435,7 +435,6 @@ static void freeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif - if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo); sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); @@ -4190,40 +4189,31 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ ** when it has finished using it. */ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ + int i; + int nCol = pIdx->nColumn; + int nKey = pIdx->nKeyCol; + KeyInfo *pKey; if( pParse->nErr ) return 0; -#ifndef SQLITE_OMIT_SHARED_CACHE - if( pIdx->pKeyInfo && pIdx->pKeyInfo->db!=pParse->db ){ - sqlite3KeyInfoUnref(pIdx->pKeyInfo); - pIdx->pKeyInfo = 0; + if( pIdx->uniqNotNull ){ + pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); + }else{ + pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); } -#endif - if( pIdx->pKeyInfo==0 ){ - int i; - int nCol = pIdx->nColumn; - int nKey = pIdx->nKeyCol; - KeyInfo *pKey; - if( pIdx->uniqNotNull ){ - pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); - }else{ - pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); + if( pKey ){ + assert( sqlite3KeyInfoIsWriteable(pKey) ); + for(i=0; iazColl[i]; + assert( zColl!=0 ); + pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 : + sqlite3LocateCollSeq(pParse, zColl); + pKey->aSortOrder[i] = pIdx->aSortOrder[i]; } - if( pKey ){ - assert( sqlite3KeyInfoIsWriteable(pKey) ); - for(i=0; iazColl[i]; - assert( zColl!=0 ); - pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 : - sqlite3LocateCollSeq(pParse, zColl); - pKey->aSortOrder[i] = pIdx->aSortOrder[i]; - } - if( pParse->nErr ){ - sqlite3KeyInfoUnref(pKey); - }else{ - pIdx->pKeyInfo = pKey; - } + if( pParse->nErr ){ + sqlite3KeyInfoUnref(pKey); + pKey = 0; } } - return sqlite3KeyInfoRef(pIdx->pKeyInfo); + return pKey; } #ifndef SQLITE_OMIT_CTE diff --git a/src/main.c b/src/main.c index 0727c0d75a..5dfa29279f 100644 --- a/src/main.c +++ b/src/main.c @@ -1032,16 +1032,6 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ for(j=0; jnDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ - if( pDb->pSchema ){ - /* Must clear the KeyInfo cache. See ticket [e4a18565a36884b00edf] */ - sqlite3BtreeEnter(pDb->pBt); - for(i=sqliteHashFirst(&pDb->pSchema->idxHash); i; i=sqliteHashNext(i)){ - Index *pIdx = sqliteHashData(i); - sqlite3KeyInfoUnref(pIdx->pKeyInfo); - pIdx->pKeyInfo = 0; - } - sqlite3BtreeLeave(pDb->pBt); - } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; if( j!=1 ){ @@ -2169,32 +2159,6 @@ const char *sqlite3_errstr(int rc){ return sqlite3ErrStr(rc); } -/* -** Invalidate all cached KeyInfo objects for database connection "db" -*/ -static void invalidateCachedKeyInfo(sqlite3 *db){ - Db *pDb; /* A single database */ - int iDb; /* The database index number */ - HashElem *k; /* For looping over tables in pDb */ - Table *pTab; /* A table in the database */ - Index *pIdx; /* Each index */ - - for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ - if( pDb->pBt==0 ) continue; - sqlite3BtreeEnter(pDb->pBt); - for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ - pTab = (Table*)sqliteHashData(k); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->pKeyInfo && pIdx->pKeyInfo->db==db ){ - sqlite3KeyInfoUnref(pIdx->pKeyInfo); - pIdx->pKeyInfo = 0; - } - } - } - sqlite3BtreeLeave(pDb->pBt); - } -} - /* ** Create a new collating function for database "db". The name is zName ** and the encoding is enc. @@ -2238,7 +2202,6 @@ static int createCollation( return SQLITE_BUSY; } sqlite3ExpirePreparedStatements(db); - invalidateCachedKeyInfo(db); /* If collation sequence pColl was created directly by a call to ** sqlite3_create_collation, and not generated by synthCollSeq(), diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3498517f25..80f9597557 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1784,7 +1784,6 @@ struct Index { u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ - KeyInfo *pKeyInfo; /* A KeyInfo object suitable for this index */ int tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ diff --git a/src/where.c b/src/where.c index ee42534f34..183a8cb667 100644 --- a/src/where.c +++ b/src/where.c @@ -3941,7 +3941,6 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); - sqlite3KeyInfoUnref(p->u.btree.pIndex->pKeyInfo); sqlite3DbFree(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } diff --git a/test/threadtest4.c b/test/threadtest4.c index e4cd644a4f..79ba094b1a 100644 --- a/test/threadtest4.c +++ b/test/threadtest4.c @@ -301,6 +301,7 @@ static void *worker_thread(void *pArg){ worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0)); } if( p->nErr ) break; + sqlite3_finalize(pStmt); worker_delete_all_content(p, (p->tid+iOuter)%2); worker_close_connection(p); From 5942b01611b9d44d7c64898b24a414d1dfbe5821 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 12 Dec 2014 00:40:58 +0000 Subject: [PATCH 14/22] Make sure the Btree mutex is held when setting the locking mode and the secure delete flag when attaching a shared-cache database. FossilOrigin-Name: 6bef7ede2bbf0a51729e1943b0b0c895cb57c718 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/attach.c | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 3dc59d55a4..022b15647e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\scell\soverflow\spage\snumber\scache\sthread\srace\sfix\sfrom\strunk. -D 2014-12-12T00:26:59.974 +C Make\ssure\sthe\sBtree\smutex\sis\sheld\swhen\ssetting\sthe\slocking\smode\sand\sthe\nsecure\sdelete\sflag\swhen\sattaching\sa\sshared-cache\sdatabase. +D 2014-12-12T00:40:58.882 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -168,7 +168,7 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb F src/analyze.c 7a2986e6ea8247e5f21aca3d0b584598f58d84fe -F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9 +F src/attach.c 7f6b3fafa2290b407e4a94dcf1afda7ec0fe394b F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb @@ -1229,7 +1229,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 b7489f9451628c68f1dfc1d457fc161a0921c631 fc157dd7f18c94b7ae5f155e1b4a5d7714b7da8c -R e0ac31855803c332d28311de41dcc42f +P cefad47ec2ad58d7ecd58bab9a261e4d5816cd69 +R 43ea10bc03cfab6b8cae2a465b94aee2 U drh -Z 01b0e5c37f35211bc16bf2591a3974d7 +Z 01d198dabe70d93c23f2c971bf866fd9 diff --git a/manifest.uuid b/manifest.uuid index b6c1d34b27..2d4407626b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cefad47ec2ad58d7ecd58bab9a261e4d5816cd69 \ No newline at end of file +6bef7ede2bbf0a51729e1943b0b0c895cb57c718 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index cf52bb24b1..de8742938b 100644 --- a/src/attach.c +++ b/src/attach.c @@ -150,6 +150,7 @@ static void attachFunc( "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } + sqlite3BtreeEnter(aNew->pBt); pPager = sqlite3BtreePager(aNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3BtreeSecureDelete(aNew->pBt, @@ -157,6 +158,7 @@ static void attachFunc( #ifndef SQLITE_OMIT_PAGER_PRAGMAS sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK)); #endif + sqlite3BtreeLeave(aNew->pBt); } aNew->safety_level = 3; aNew->zName = sqlite3DbStrDup(db, zName); From ef15c6e9e65cec6f9a847b8780265ca6d4124286 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 12 Dec 2014 01:27:17 +0000 Subject: [PATCH 15/22] Add new tests to the threadtest4.c program. Fix a long-standing data race in WAL mode for shared-cache. FossilOrigin-Name: d8d3e6d04cbb9e3033ad8613e3dbd4ad0b01765a --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/vdbeapi.c | 5 ++++- test/threadtest4.c | 27 +++++++++++++++++++++++---- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 446beca49b..fb9bed5983 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sKeyInfo\scache\s(for\snow\s-\sperhaps\swe\swill\sadd\sit\sback\sin\slater\s-\sor\nmaybe\snot\ssince\sit\sprovides\snegligible\sbenefit\sbut\sadds\sa\slot\sof\scomplexity\nand\sthread-safety\srisk).\s\sAdd\sa\smutex\sto\sATTACH\sto\sdeal\swith\sa\sdata\srace. -D 2014-12-12T00:52:10.892 +C Add\snew\stests\sto\sthe\sthreadtest4.c\sprogram.\s\sFix\sa\slong-standing\sdata\srace\nin\sWAL\smode\sfor\sshared-cache. +D 2014-12-12T01:27:17.213 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -294,7 +294,7 @@ F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c F src/vdbe.c 1a9e671c9cfc259e4d2affc71f7df4a4c00a842c F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 -F src/vdbeapi.c f8dd2d33a30938188fc292d524e88a91f2e65887 +F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71 F src/vdbeaux.c 6f7f39c3fcf0f5923758df8561bb5d843908a553 F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f @@ -913,7 +913,7 @@ F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 2b6e07e915c383c250a5b531cf6ef163a3047d7e -F test/threadtest4.c 38cb574939d5e0c8bd3baa5eb45def2ac6da4db4 +F test/threadtest4.c 1678c340387c19ae28b18e4d8f71d4a989297e46 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 @@ -1229,8 +1229,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 fc157dd7f18c94b7ae5f155e1b4a5d7714b7da8c 6bef7ede2bbf0a51729e1943b0b0c895cb57c718 -R 43ea10bc03cfab6b8cae2a465b94aee2 -T +closed 6bef7ede2bbf0a51729e1943b0b0c895cb57c718 +P 03c443eaf24413d6faaa91a33575d9dfd3528b5c +R 7d057661252570fbf3877a000bcb607e U drh -Z 6886c071ca5a249d6b983c22ce222f5d +Z 24d2ddd2be9b77d0c401fa6e4cbdad23 diff --git a/manifest.uuid b/manifest.uuid index e881507359..82e8f8a854 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -03c443eaf24413d6faaa91a33575d9dfd3528b5c \ No newline at end of file +d8d3e6d04cbb9e3033ad8613e3dbd4ad0b01765a \ No newline at end of file diff --git a/src/vdbeapi.c b/src/vdbeapi.c index c611688193..21c537d776 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -400,7 +400,10 @@ static int doWalCallbacks(sqlite3 *db){ for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ - int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); + int nEntry; + sqlite3BtreeEnter(pBt); + nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); + sqlite3BtreeLeave(pBt); if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry); } diff --git a/test/threadtest4.c b/test/threadtest4.c index 79ba094b1a..859841c738 100644 --- a/test/threadtest4.c +++ b/test/threadtest4.c @@ -16,13 +16,17 @@ ** This test program runs on unix-like systems only. It uses pthreads. ** To compile: ** -** gcc -o tt4 -I. threadtest4.c sqlite3.c -ldl -lpthread +** gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread ** ** To run: ** -** ./tt4 10 +** ./a.out 10 ** -** The argument is the number of threads. +** The argument is the number of threads. There are also options, such +** as -wal and -multithread and -serialized. +** +** Consider also compiling with clang instead of gcc and adding the +** -fsanitize=thread option. */ #include "sqlite3.h" #include @@ -40,6 +44,7 @@ typedef struct WorkerInfo WorkerInfo; struct WorkerInfo { int tid; /* Thread ID */ + int nWorker; /* Total number of workers */ unsigned wkrFlags; /* Flags */ sqlite3 *mainDb; /* Database connection of the main thread */ sqlite3 *db; /* Database connection of this thread */ @@ -284,7 +289,7 @@ static void *worker_thread(void *pArg){ sqlite3_stmt *pStmt; printf("worker %d startup\n", p->tid); fflush(stdout); - for(iOuter=1; iOuter<=4; iOuter++){ + for(iOuter=1; iOuter<=p->nWorker; iOuter++){ worker_open_connection(p, iOuter); for(i=0; i<4; i++){ worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter)%3 + 1); @@ -303,6 +308,17 @@ static void *worker_thread(void *pArg){ if( p->nErr ) break; sqlite3_finalize(pStmt); + if( ((iOuter+p->tid)%3)==0 ){ + sqlite3_db_release_memory(p->db); + p->nTest++; + } + + if( iOuter==p->tid ){ + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "VACUUM"); + pthread_mutex_unlock(p->pWrMutex); + } + worker_delete_all_content(p, (p->tid+iOuter)%2); worker_close_connection(p); p->db = 0; @@ -362,6 +378,8 @@ int main(int argc, char **argv){ "Options:\n" " --serialized\n" " --multithread\n" + " --wal\n" + " --trace\n" ,argv[0] ); exit(1); @@ -406,6 +424,7 @@ int main(int argc, char **argv){ memset(aInfo, 0, sizeof(*aInfo)*nWorker); for(i=0; i Date: Fri, 12 Dec 2014 16:39:38 +0000 Subject: [PATCH 16/22] Add extra tests to threadtest3. FossilOrigin-Name: f6bf86f907cbff31bed3cbfc922c10c973575498 --- main.mk | 12 +++- manifest | 20 +++--- manifest.uuid | 2 +- test/threadtest3.c | 6 +- test/tt3_index.c | 22 +++---- test/tt3_stress.c | 161 +++++++++++++++++++++++++++++++++++++++++++++ test/tt3_vacuum.c | 90 +++++++++++++++++++++++++ 7 files changed, 288 insertions(+), 25 deletions(-) create mode 100644 test/tt3_stress.c create mode 100644 test/tt3_vacuum.c diff --git a/main.mk b/main.mk index cac996864d..e2213bc62c 100644 --- a/main.mk +++ b/main.mk @@ -625,9 +625,15 @@ test: testfixture$(EXE) sqlite3$(EXE) # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. # -threadtest3$(EXE): sqlite3.o $(TOP)/test/threadtest3.c $(TOP)/test/tt3_checkpoint.c - $(TCCX) -O2 sqlite3.o $(TOP)/test/threadtest3.c \ - -o threadtest3$(EXE) $(THREADLIB) +THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ + $(TOP)/test/tt3_checkpoint.c \ + $(TOP)/test/tt3_index.c \ + $(TOP)/test/tt3_vacuum.c \ + $(TOP)/test/tt3_stress.c \ + $(TOP)/test/tt3_lookaside1.c + +threadtest3$(EXE): sqlite3.o $(THREADTEST3_SRC) + $(TCCX) $(TOP)/test/threadtest3.c sqlite3.o -o $@ $(THREADLIB) threadtest: threadtest3$(EXE) ./threadtest3$(EXE) diff --git a/manifest b/manifest index fb9bed5983..599bf4fb39 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\stests\sto\sthe\sthreadtest4.c\sprogram.\s\sFix\sa\slong-standing\sdata\srace\nin\sWAL\smode\sfor\sshared-cache. -D 2014-12-12T01:27:17.213 +C Add\sextra\stests\sto\sthreadtest3. +D 2014-12-12T16:39:38.824 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -152,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 084976077a4aa3bd985154b5423e7aed88e4a2e9 +F main.mk 9f8c54fe62b60e0a24a2e65cfc8d2add063dda07 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -912,7 +912,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 -F test/threadtest3.c 2b6e07e915c383c250a5b531cf6ef163a3047d7e +F test/threadtest3.c bef2bde18b4e638b6cf4b119aa2076123ffdc425 F test/threadtest4.c 1678c340387c19ae28b18e4d8f71d4a989297e46 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 @@ -1077,8 +1077,10 @@ F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52 F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af -F test/tt3_index.c 14f4b0cc3f4c05353e25778cf531c9d6e3b0d27f +F test/tt3_index.c 652630e6b6fc7a48adf2ead60de1ef48e1a34569 F test/tt3_lookaside1.c 0b5b79ba37f21a1eb849cd4a54eed367f4d4aaaf +F test/tt3_stress.c e003a8486ba990c43dc9b8298f4b266cd10eb1c1 +F test/tt3_vacuum.c 6a66e52e2b39fc0cccb71db5a302411f34d09736 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a @@ -1229,7 +1231,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 03c443eaf24413d6faaa91a33575d9dfd3528b5c -R 7d057661252570fbf3877a000bcb607e -U drh -Z 24d2ddd2be9b77d0c401fa6e4cbdad23 +P d8d3e6d04cbb9e3033ad8613e3dbd4ad0b01765a +R 2ae2d517339c22d48400a669b2098fec +U dan +Z 951a78f63dc9b91d226749536e3eb614 diff --git a/manifest.uuid b/manifest.uuid index 82e8f8a854..816a546aae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d8d3e6d04cbb9e3033ad8613e3dbd4ad0b01765a \ No newline at end of file +f6bf86f907cbff31bed3cbfc922c10c973575498 \ No newline at end of file diff --git a/test/threadtest3.c b/test/threadtest3.c index afa4197ee2..9b12616e3a 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -1399,6 +1399,8 @@ static void dynamic_triggers(int nMs){ #include "tt3_checkpoint.c" #include "tt3_index.c" #include "tt3_lookaside1.c" +#include "tt3_vacuum.c" +#include "tt3_stress.c" int main(int argc, char **argv){ struct ThreadTest { @@ -1420,7 +1422,9 @@ int main(int argc, char **argv){ { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 }, { create_drop_index_1, "create_drop_index_1", 10000 }, - { lookaside1, "lookaside1", 10000 }, + { lookaside1, "lookaside1", 10000 }, + { vacuum1, "vacuum1", 10000 }, + { stress1, "stress1", 10000 }, }; int i; diff --git a/test/tt3_index.c b/test/tt3_index.c index 4bad64aabc..2445f398cd 100644 --- a/test/tt3_index.c +++ b/test/tt3_index.c @@ -22,22 +22,22 @@ static char *create_drop_index_thread(int iTid, int iArg){ opendb(&err, &db, "test.db", 0); sql_script(&err, &db, - "DROP INDEX IF EXISTS i1;" "DROP INDEX IF EXISTS i2;" "DROP INDEX IF EXISTS i3;" "DROP INDEX IF EXISTS i4;" - "CREATE INDEX IF NOT EXISTS i1 ON t1(a);" - "CREATE INDEX IF NOT EXISTS i2 ON t1(b);" - "CREATE INDEX IF NOT EXISTS i3 ON t1(c);" - "CREATE INDEX IF NOT EXISTS i4 ON t1(d);" + "CREATE INDEX IF NOT EXISTS i1 ON t11(a);" + "CREATE INDEX IF NOT EXISTS i2 ON t11(b);" + "CREATE INDEX IF NOT EXISTS i3 ON t11(c);" + "CREATE INDEX IF NOT EXISTS i4 ON t11(d);" - "SELECT * FROM t1 ORDER BY a;" - "SELECT * FROM t1 ORDER BY b;" - "SELECT * FROM t1 ORDER BY c;" - "SELECT * FROM t1 ORDER BY d;" + "SELECT * FROM t11 ORDER BY a;" + "SELECT * FROM t11 ORDER BY b;" + "SELECT * FROM t11 ORDER BY c;" + "SELECT * FROM t11 ORDER BY d;" ); + clear_error(&err, SQLITE_LOCKED); closedb(&err, &db); } @@ -53,9 +53,9 @@ static void create_drop_index_1(int nMs){ opendb(&err, &db, "test.db", 1); sql_script(&err, &db, - "CREATE TABLE t1(a, b, c, d);" + "CREATE TABLE t11(a, b, c, d);" "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) " - "INSERT INTO t1 SELECT x,x,x,x FROM data;" + "INSERT INTO t11 SELECT x,x,x,x FROM data;" ); closedb(&err, &db); diff --git a/test/tt3_stress.c b/test/tt3_stress.c new file mode 100644 index 0000000000..93a0d0aa1c --- /dev/null +++ b/test/tt3_stress.c @@ -0,0 +1,161 @@ +/* +** 2014 December 9 +** +** 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. +** +************************************************************************* +** +** +*/ + + +/* +** Thread 1. CREATE and DROP a table. +*/ +static char *stress_thread_1(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b)"); + clear_error(&err, SQLITE_LOCKED); + sql_script(&err, &db, "DROP TABLE IF EXISTS t1"); + clear_error(&err, SQLITE_LOCKED); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +/* +** Thread 2. Open and close database connections. +*/ +static char *stress_thread_2(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + while( !timetostop(&err) ){ + opendb(&err, &db, "test.db", 0); + sql_script(&err, &db, "SELECT * FROM sqlite_master;"); + clear_error(&err, SQLITE_LOCKED); + closedb(&err, &db); + } + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +/* +** Thread 3. Attempt many small SELECT statements. +*/ +static char *stress_thread_3(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + int i1 = 0; + int i2 = 0; + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;"); + i1++; + if( err.rc ) i2++; + clear_error(&err, SQLITE_LOCKED); + clear_error(&err, SQLITE_ERROR); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("read t1 %d/%d attempts", i2, i1); +} + +/* +** Thread 5. Attempt INSERT statements. +*/ +static char *stress_thread_4(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + int i1 = 0; + int i2 = 0; + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + if( iArg ){ + closedb(&err, &db); + opendb(&err, &db, "test.db", 0); + } + sql_script(&err, &db, + "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop LIMIT 200) " + "INSERT INTO t1 VALUES(randomblob(60), randomblob(60));" + ); + i1++; + if( err.rc ) i2++; + clear_error(&err, SQLITE_LOCKED); + clear_error(&err, SQLITE_ERROR); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("wrote t1 %d/%d attempts", i2, i1); +} + +/* +** Thread 6. Attempt DELETE operations. +*/ +static char *stress_thread_5(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + + int i1 = 0; + int i2 = 0; + + opendb(&err, &db, "test.db", 0); + while( !timetostop(&err) ){ + i64 i = (i1 % 4); + if( iArg ){ + closedb(&err, &db); + opendb(&err, &db, "test.db", 0); + } + execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i); + i1++; + if( err.rc ) i2++; + clear_error(&err, SQLITE_LOCKED); + clear_error(&err, SQLITE_ERROR); + } + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("deleted from t1 %d/%d attempts", i2, i1); +} + + +static void stress1(int nMs){ + Error err = {0}; + Sqlite db = {0}; + Threadset threads = {0}; + + + setstoptime(&err, nMs); + + sqlite3_enable_shared_cache(1); + + launch_thread(&err, &threads, stress_thread_1, 0); + launch_thread(&err, &threads, stress_thread_1, 0); + + launch_thread(&err, &threads, stress_thread_2, 0); + launch_thread(&err, &threads, stress_thread_2, 0); + + launch_thread(&err, &threads, stress_thread_3, 0); + launch_thread(&err, &threads, stress_thread_3, 0); + + launch_thread(&err, &threads, stress_thread_4, 0); + launch_thread(&err, &threads, stress_thread_4, 0); + + launch_thread(&err, &threads, stress_thread_5, 0); + launch_thread(&err, &threads, stress_thread_5, 1); + + join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); + + print_and_free_err(&err); +} diff --git a/test/tt3_vacuum.c b/test/tt3_vacuum.c new file mode 100644 index 0000000000..126bbfc26e --- /dev/null +++ b/test/tt3_vacuum.c @@ -0,0 +1,90 @@ +/* +** 2014 December 9 +** +** 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 contains multi-threaded tests that use shared-cache and +** the VACUUM command. +** +** Tests: +** +** vacuum1 +** +*/ + + +static char *vacuum1_thread_writer(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + opendb(&err, &db, "test.db", 0); + i64 i = 0; + + while( !timetostop(&err) ){ + i++; + + /* Insert lots of rows. Then delete some. */ + execsql(&err, &db, + "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop WHERE i<100) " + "INSERT INTO t1 SELECT randomblob(50), randomblob(2500) FROM loop" + ); + + /* Delete lots of rows */ + execsql(&err, &db, "DELETE FROM t1 WHERE rowid = :i", &i); + clear_error(&err, SQLITE_LOCKED); + + /* Select the rows */ + execsql(&err, &db, "SELECT * FROM t1 ORDER BY x"); + clear_error(&err, SQLITE_LOCKED); + } + + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +static char *vacuum1_thread_vacuumer(int iTid, int iArg){ + Error err = {0}; /* Error code and message */ + Sqlite db = {0}; /* SQLite database connection */ + opendb(&err, &db, "test.db", 0); + + do{ + sql_script(&err, &db, "VACUUM"); + clear_error(&err, SQLITE_LOCKED); + }while( !timetostop(&err) ); + + closedb(&err, &db); + print_and_free_err(&err); + return sqlite3_mprintf("ok"); +} + +static void vacuum1(int nMs){ + Error err = {0}; + Sqlite db = {0}; + Threadset threads = {0}; + + opendb(&err, &db, "test.db", 1); + sql_script(&err, &db, + "CREATE TABLE t1(x PRIMARY KEY, y BLOB);" + "CREATE INDEX i1 ON t1(y);" + ); + closedb(&err, &db); + + setstoptime(&err, nMs); + + sqlite3_enable_shared_cache(1); + launch_thread(&err, &threads, vacuum1_thread_writer, 0); + launch_thread(&err, &threads, vacuum1_thread_writer, 0); + launch_thread(&err, &threads, vacuum1_thread_writer, 0); + launch_thread(&err, &threads, vacuum1_thread_vacuumer, 0); + join_all_threads(&err, &threads); + sqlite3_enable_shared_cache(0); + + print_and_free_err(&err); +} From 9bd3cc46814595f1107d95f372ce912e947e5bf5 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 12 Dec 2014 23:17:54 +0000 Subject: [PATCH 17/22] Add extra tests to threadtest4.c. Fix a benign data race accessing the text encoding using ENC(db). FossilOrigin-Name: d7bb7ea4ab97ad26f4c84c9b8dc2827010093803 --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/main.c | 3 ++- src/pragma.c | 3 ++- src/prepare.c | 2 ++ src/sqliteInt.h | 4 +++- test/threadtest4.c | 31 ++++++++++++++++++++++++++++++- 7 files changed, 51 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 599bf4fb39..ff005f7ef4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sextra\stests\sto\sthreadtest3. -D 2014-12-12T16:39:38.824 +C Add\sextra\stests\sto\sthreadtest4.c.\s\sFix\sa\sbenign\sdata\srace\saccessing\sthe\ntext\sencoding\susing\sENC(db). +D 2014-12-12T23:17:54.003 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -195,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660 -F src/main.c 1f40f66165a6609203a5ff7ecb0292b90b302130 +F src/main.c 48e0410a661c629471ca9061d4153245cc9f853b F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -222,8 +222,8 @@ F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98 -F src/pragma.c d54cdd40b63d608f2d95b7482c710690e3593a73 -F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7 +F src/pragma.c c93be505649183b2d80082c2eef1a56879dabfe6 +F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada @@ -233,7 +233,7 @@ F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf F src/sqlite.h.in 116dc731361549ee3fc79dcebace11b57d24dcfd F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h 073d54f7a631b978b66d50d255c84549fb9e5429 +F src/sqliteInt.h d36da9a07130cae13cbfee0986bf20028cb01465 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc @@ -913,7 +913,7 @@ F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c bef2bde18b4e638b6cf4b119aa2076123ffdc425 -F test/threadtest4.c 1678c340387c19ae28b18e4d8f71d4a989297e46 +F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 @@ -1231,7 +1231,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 d8d3e6d04cbb9e3033ad8613e3dbd4ad0b01765a -R 2ae2d517339c22d48400a669b2098fec -U dan -Z 951a78f63dc9b91d226749536e3eb614 +P f6bf86f907cbff31bed3cbfc922c10c973575498 +R 97f096b77c750d9e694c3063635e4c8a +U drh +Z 4a2c4212438d559f2811b75a6a368836 diff --git a/manifest.uuid b/manifest.uuid index 816a546aae..2694c2c363 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f6bf86f907cbff31bed3cbfc922c10c973575498 \ No newline at end of file +d7bb7ea4ab97ad26f4c84c9b8dc2827010093803 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 5dfa29279f..c89ccbd55d 100644 --- a/src/main.c +++ b/src/main.c @@ -2758,6 +2758,7 @@ static int openDatabase( } sqlite3BtreeEnter(db->aDb[0].pBt); db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); + if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db); sqlite3BtreeLeave(db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); @@ -2916,7 +2917,7 @@ int sqlite3_open16( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); assert( *ppDb || rc==SQLITE_NOMEM ); if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){ - ENC(*ppDb) = SQLITE_UTF16NATIVE; + SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE; } }else{ rc = SQLITE_NOMEM; diff --git a/src/pragma.c b/src/pragma.c index ab9a283629..837a15102d 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -2080,7 +2080,8 @@ void sqlite3Pragma( ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ - ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; + SCHEMA_ENC(db) = ENC(db) = + pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; break; } } diff --git a/src/prepare.c b/src/prepare.c index ca9c64b441..97be900d68 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -394,9 +394,11 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int commit_internal = !(db->flags&SQLITE_InternChanges); assert( sqlite3_mutex_held(db->mutex) ); + assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); rc = SQLITE_OK; db->init.busy = 1; + ENC(db) = SCHEMA_ENC(db); for(i=0; rc==SQLITE_OK && inDb; i++){ if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; rc = sqlite3InitOne(db, i, pzErrMsg); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 80f9597557..d90089ba0e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1059,6 +1059,7 @@ struct sqlite3 { int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u16 dbOptFlags; /* Flags to enable/disable optimizations */ + u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ @@ -1160,7 +1161,8 @@ struct sqlite3 { /* ** A macro to discover the encoding of a database. */ -#define ENC(db) ((db)->aDb[0].pSchema->enc) +#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) +#define ENC(db) ((db)->enc) /* ** Possible values for the sqlite3.flags. diff --git a/test/threadtest4.c b/test/threadtest4.c index 859841c738..da5ce75f05 100644 --- a/test/threadtest4.c +++ b/test/threadtest4.c @@ -305,20 +305,49 @@ static void *worker_thread(void *pArg){ }else if( sqlite3_column_int(pStmt, 0)!=400 ){ worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0)); } - if( p->nErr ) break; sqlite3_finalize(pStmt); + if( p->nErr ) break; if( ((iOuter+p->tid)%3)==0 ){ sqlite3_db_release_memory(p->db); p->nTest++; } + pthread_mutex_lock(p->pWrMutex); + run_sql(p, "BEGIN;"); + run_sql(p, "UPDATE t1 SET c=NULL WHERE a=55"); + run_sql(p, "UPDATE t2 SET f=NULL WHERE d=42"); + run_sql(p, "UPDATE t3 SET z=NULL WHERE x=31"); + run_sql(p, "ROLLBACK;"); + p->nTest++; + pthread_mutex_unlock(p->pWrMutex); + + if( iOuter==p->tid ){ pthread_mutex_lock(p->pWrMutex); run_sql(p, "VACUUM"); pthread_mutex_unlock(p->pWrMutex); } + pStmt = prep_sql(p->db, + "SELECT t1.rowid, t2.rowid, t3.rowid" + " FROM t1, t2, t3" + " WHERE t1.tid=%d AND t2.tid=%d AND t3.tid=%d" + " AND t1.a<>t2.d AND t2.d<>t3.x" + " ORDER BY 1, 2, 3" + ,p->tid, p->tid, p->tid); + worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); + for(i=0; inWorker; i++){ + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW ){ + worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); + break; + } + sched_yield(); + } + sqlite3_finalize(pStmt); + if( p->nErr ) break; + worker_delete_all_content(p, (p->tid+iOuter)%2); worker_close_connection(p); p->db = 0; From 053542d72a174f16644bba4d580d41da75f038f7 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 13 Dec 2014 17:41:48 +0000 Subject: [PATCH 18/22] Further enhancements to threadtest3 stress tests. FossilOrigin-Name: ba772cff602ca7c3c0c91451e701f52a872e7a14 --- manifest | 24 ++--- manifest.uuid | 2 +- test/threadtest3.c | 83 +++++++++------ test/tt3_checkpoint.c | 2 +- test/tt3_index.c | 2 +- test/tt3_lookaside1.c | 4 +- test/tt3_stress.c | 238 ++++++++++++++++++++++++++++++++++++++++-- test/tt3_vacuum.c | 4 +- 8 files changed, 299 insertions(+), 60 deletions(-) diff --git a/manifest b/manifest index ff005f7ef4..d0026036ad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sextra\stests\sto\sthreadtest4.c.\s\sFix\sa\sbenign\sdata\srace\saccessing\sthe\ntext\sencoding\susing\sENC(db). -D 2014-12-12T23:17:54.003 +C Further\senhancements\sto\sthreadtest3\sstress\stests. +D 2014-12-13T17:41:48.275 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -912,7 +912,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 -F test/threadtest3.c bef2bde18b4e638b6cf4b119aa2076123ffdc425 +F test/threadtest3.c 05d67ab8fd4ad82978a96200701a22af35faa097 F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 @@ -1076,11 +1076,11 @@ F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52 -F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af -F test/tt3_index.c 652630e6b6fc7a48adf2ead60de1ef48e1a34569 -F test/tt3_lookaside1.c 0b5b79ba37f21a1eb849cd4a54eed367f4d4aaaf -F test/tt3_stress.c e003a8486ba990c43dc9b8298f4b266cd10eb1c1 -F test/tt3_vacuum.c 6a66e52e2b39fc0cccb71db5a302411f34d09736 +F test/tt3_checkpoint.c 5e63ee65ed5f87176e25a996480cb02c6caec8b4 +F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a +F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9 +F test/tt3_stress.c edbb00ed1516535691040315e97cf32c62df22d0 +F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a @@ -1231,7 +1231,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 f6bf86f907cbff31bed3cbfc922c10c973575498 -R 97f096b77c750d9e694c3063635e4c8a -U drh -Z 4a2c4212438d559f2811b75a6a368836 +P d7bb7ea4ab97ad26f4c84c9b8dc2827010093803 +R 5d62798e848b5017221fa2f718c6fa3d +U dan +Z 748bf95122bf9ac21f60dff7348c8009 diff --git a/manifest.uuid b/manifest.uuid index 2694c2c363..4d5b9316c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d7bb7ea4ab97ad26f4c84c9b8dc2827010093803 \ No newline at end of file +ba772cff602ca7c3c0c91451e701f52a872e7a14 \ No newline at end of file diff --git a/test/threadtest3.c b/test/threadtest3.c index 9b12616e3a..4cdb0f8e9b 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -47,10 +47,13 @@ #define execsql_i64(x,y,...) (SEL(x), execsql_i64_x(x,y,__VA_ARGS__)) #define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__)) #define execsql(x,y,...) (SEL(x), (void)execsql_i64_x(x,y,__VA_ARGS__)) +#define sql_script_printf(x,y,z,...) ( \ + SEL(x), sql_script_printf_x(x,y,z,__VA_ARGS__) \ +) /* Thread functions */ -#define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z)) -#define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z)) +#define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z)) +#define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z)) /* Timer functions */ #define setstoptime(y,z) (SEL(y), setstoptime_x(y,z)) @@ -64,6 +67,9 @@ #define filesize(y,z) (SEL(y), filesize_x(y,z)) #define filecopy(x,y,z) (SEL(x), filecopy_x(x,y,z)) +#define PTR2INT(x) ((int)((intptr_t)x)) +#define INT2PTR(x) ((void*)((intptr_t)x)) + /* ** End of test code/infrastructure interface macros. *************************************************************************/ @@ -334,7 +340,7 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ MD5Transform(ctx->buf, (uint32 *)ctx->in); byteReverse((unsigned char *)ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */ + memset(ctx, 0, sizeof(*ctx)); /* In case it is sensitive */ } /* @@ -398,9 +404,6 @@ typedef struct Thread Thread; /* Total number of errors in this process so far. */ static int nGlobalErr = 0; -/* Set to true to run in "process" instead of "thread" mode. */ -static int bProcessMode = 0; - struct Error { int rc; int iLine; @@ -421,10 +424,10 @@ struct Statement { struct Thread { int iTid; /* Thread number within test */ - int iArg; /* Integer argument passed by caller */ + void* pArg; /* Pointer argument passed by caller */ pthread_t tid; /* Thread id */ - char *(*xProc)(int, int); /* Thread main proc */ + char *(*xProc)(int, void*); /* Thread main proc */ Thread *pNext; /* Next in this list of threads */ }; @@ -506,8 +509,9 @@ static void opendb_x( ){ if( pErr->rc==SQLITE_OK ){ int rc; + int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI; if( bDelete ) unlink(zFile); - rc = sqlite3_open(zFile, &pDb->db); + rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0); if( rc ){ sqlite_error(pErr, pDb, "open"); sqlite3_close(pDb->db); @@ -556,6 +560,22 @@ static void sql_script_x( } } +static void sql_script_printf_x( + Error *pErr, /* IN/OUT: Error code */ + Sqlite *pDb, /* Database handle */ + const char *zFormat, /* SQL printf format string */ + ... /* Printf args */ +){ + va_list ap; /* ... printf arguments */ + va_start(ap, zFormat); + if( pErr->rc==SQLITE_OK ){ + char *zSql = sqlite3_vmprintf(zFormat, ap); + pErr->rc = sqlite3_exec(pDb->db, zSql, 0, 0, &pErr->zErr); + sqlite3_free(zSql); + } + va_end(ap); +} + static Statement *getSqlStatement( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ @@ -624,11 +644,9 @@ static i64 execsql_i64_x( if( pErr->rc==SQLITE_OK ){ sqlite3_stmt *pStmt; /* SQL statement to execute */ va_list ap; /* ... arguments */ - int i; /* Used to iterate through parameters */ va_start(ap, pDb); pStmt = getAndBindSqlStatement(pErr, pDb, ap); if( pStmt ){ - int rc; int first = 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( first && sqlite3_column_count(pStmt)>0 ){ @@ -663,11 +681,9 @@ static char * execsql_text_x( if( pErr->rc==SQLITE_OK ){ sqlite3_stmt *pStmt; /* SQL statement to execute */ va_list ap; /* ... arguments */ - int i; /* Used to iterate through parameters */ va_start(ap, iSlot); pStmt = getAndBindSqlStatement(pErr, pDb, ap); if( pStmt ){ - int rc; int first = 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( first && sqlite3_column_count(pStmt)>0 ){ @@ -693,14 +709,13 @@ static void integrity_check_x( ){ if( pErr->rc==SQLITE_OK ){ Statement *pStatement; /* Statement to execute */ - int rc; /* Return code */ char *zErr = 0; /* Integrity check error */ pStatement = getSqlStatement(pErr, pDb, "PRAGMA integrity_check"); if( pStatement ){ sqlite3_stmt *pStmt = pStatement->pStmt; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *z = sqlite3_column_text(pStmt, 0); + const char *z = (const char*)sqlite3_column_text(pStmt, 0); if( strcmp(z, "ok") ){ if( zErr==0 ){ zErr = sqlite3_mprintf("%s", z); @@ -721,14 +736,14 @@ static void integrity_check_x( static void *launch_thread_main(void *pArg){ Thread *p = (Thread *)pArg; - return (void *)p->xProc(p->iTid, p->iArg); + return (void *)p->xProc(p->iTid, p->pArg); } static void launch_thread_x( Error *pErr, /* IN/OUT: Error code */ Threadset *pThreads, /* Thread set */ - char *(*xProc)(int, int), /* Proc to run */ - int iArg /* Argument passed to thread proc */ + char *(*xProc)(int, void*), /* Proc to run */ + void *pArg /* Argument passed to thread proc */ ){ if( pErr->rc==SQLITE_OK ){ int iTid = ++pThreads->iMaxTid; @@ -738,7 +753,7 @@ static void launch_thread_x( p = (Thread *)sqlite3_malloc(sizeof(Thread)); memset(p, 0, sizeof(Thread)); p->iTid = iTid; - p->iArg = iArg; + p->pArg = pArg; p->xProc = xProc; rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p); @@ -895,7 +910,7 @@ static int timetostop_x( #define WALTHREAD1_NTHREAD 10 #define WALTHREAD3_NTHREAD 6 -static char *walthread1_thread(int iTid, int iArg){ +static char *walthread1_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nIter = 0; /* Iterations so far */ @@ -934,7 +949,7 @@ static char *walthread1_thread(int iTid, int iArg){ return sqlite3_mprintf("%d iterations", nIter); } -static char *walthread1_ckpt_thread(int iTid, int iArg){ +static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ @@ -977,10 +992,11 @@ static void walthread1(int nMs){ print_and_free_err(&err); } -static char *walthread2_thread(int iTid, int iArg){ +static char *walthread2_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int anTrans[2] = {0, 0}; /* Number of WAL and Rollback transactions */ + int iArg = PTR2INT(pArg); const char *zJournal = "PRAGMA journal_mode = WAL"; if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; } @@ -1026,17 +1042,18 @@ static void walthread2(int nMs){ setstoptime(&err, nMs); launch_thread(&err, &threads, walthread2_thread, 0); launch_thread(&err, &threads, walthread2_thread, 0); - launch_thread(&err, &threads, walthread2_thread, 1); - launch_thread(&err, &threads, walthread2_thread, 1); + launch_thread(&err, &threads, walthread2_thread, (void*)1); + launch_thread(&err, &threads, walthread2_thread, (void*)1); join_all_threads(&err, &threads); print_and_free_err(&err); } -static char *walthread3_thread(int iTid, int iArg){ +static char *walthread3_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 iNextWrite; /* Next value this thread will write */ + int iArg = PTR2INT(pArg); opendb(&err, &db, "test.db", 0); sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10"); @@ -1087,14 +1104,14 @@ static void walthread3(int nMs){ setstoptime(&err, nMs); for(i=0; izDb, 0); + while( !timetostop(&err) ){ + pCtx->xProc(&err, &db, i1); + i2 += (err.rc==SQLITE_OK); + clear_error(&err, SQLITE_LOCKED); + clear_error(&err, SQLITE_ERROR); + i1++; + } + + print_and_free_err(&err); + return sqlite3_mprintf("ok %d/%d", i2, i1); +} + +static void stress2_launch_thread_loop( + Error *pErr, /* IN/OUT: Error code */ + Threadset *pThreads, /* Thread set */ + const char *zDb, /* Database name */ + void (*x)(Error*,Sqlite*,int) /* Run this until error or timeout */ +){ + Stress2Ctx *pCtx = sqlite3_malloc(sizeof(Stress2Ctx)); + pCtx->zDb = zDb; + pCtx->xProc = x; + launch_thread(pErr, pThreads, stress2_thread_wrapper, (void*)pCtx); +} + +static void stress2(int nMs){ + struct Stress2Task { + void (*x)(Error*,Sqlite*,int); + } aTask[] = { + { stress2_workload1 }, + { stress2_workload2 }, + { stress2_workload3 }, + { stress2_workload4 }, + { stress2_workload5 }, + { stress2_workload6 }, + { stress2_workload7 }, + { stress2_workload8 }, + { stress2_workload9 }, + { stress2_workload10 }, + { stress2_workload11 }, + { stress2_workload14 }, + { stress2_workload17 }, + }; + const char *azDb[] = { + "test.db", + "file::memory:?cache=shared" + }; + int j; + + for(j=0; j Date: Mon, 15 Dec 2014 08:46:17 +0000 Subject: [PATCH 19/22] Fix errors in threadtest3 tests caused by earlier tests neglecting to close database handles. FossilOrigin-Name: 1d44f1b1a9fefeb2449892775c59765c46784eb1 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/threadtest3.c | 33 ++++++++++++++------------------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index d0026036ad..56aa9e8cb0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\senhancements\sto\sthreadtest3\sstress\stests. -D 2014-12-13T17:41:48.275 +C Fix\serrors\sin\sthreadtest3\stests\scaused\sby\searlier\stests\sneglecting\sto\sclose\sdatabase\shandles. +D 2014-12-15T08:46:17.172 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -912,7 +912,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 -F test/threadtest3.c 05d67ab8fd4ad82978a96200701a22af35faa097 +F test/threadtest3.c c8629f836331dd4e5d6ef514b6696605cb593135 F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 @@ -1231,7 +1231,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 d7bb7ea4ab97ad26f4c84c9b8dc2827010093803 -R 5d62798e848b5017221fa2f718c6fa3d +P ba772cff602ca7c3c0c91451e701f52a872e7a14 +R ed0c57369d0ec456d80773711d0601f8 U dan -Z 748bf95122bf9ac21f60dff7348c8009 +Z bfcc45ad20cf310717047c8b8c88d22b diff --git a/manifest.uuid b/manifest.uuid index 4d5b9316c6..53e85dbd36 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba772cff602ca7c3c0c91451e701f52a872e7a14 \ No newline at end of file +1d44f1b1a9fefeb2449892775c59765c46784eb1 \ No newline at end of file diff --git a/test/threadtest3.c b/test/threadtest3.c index 4cdb0f8e9b..c8830bb55e 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -1343,6 +1343,7 @@ static char *dynamic_triggers_1(int iTid, void *pArg){ nDrop++; } } + closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("%d created, %d dropped", nCreate, nDrop); @@ -1369,6 +1370,7 @@ static char *dynamic_triggers_2(int iTid, void *pArg){ nDelete++; } while( iVal ); } + closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("%d inserts, %d deletes", nInsert, nDelete); @@ -1393,6 +1395,7 @@ static void dynamic_triggers(int nMs){ "CREATE TABLE t8(x, y);" "CREATE TABLE t9(x, y);" ); + closedb(&err, &db); setstoptime(&err, nMs); @@ -1446,32 +1449,24 @@ int main(int argc, char **argv){ }; int i; - char *zTest = 0; - int nTest = 0; int bTestfound = 0; - int bPrefix = 0; - - if( argc>2 ) goto usage; - if( argc==2 ){ - zTest = argv[1]; - nTest = strlen(zTest); - if( zTest[nTest-1]=='*' ){ - nTest--; - bPrefix = 1; - } - } sqlite3_config(SQLITE_CONFIG_MULTITHREAD); sqlite3_config(SQLITE_CONFIG_MULTITHREAD); for(i=0; i1 ){ + int iArg; + for(iArg=1; iArg0 ? 255 : 0); usage: - printf("Usage: %s [testname|testprefix*]\n", argv[0]); + printf("Usage: %s [testname|testprefix*]...\n", argv[0]); printf("Available tests are:\n"); for(i=0; i Date: Mon, 15 Dec 2014 16:27:12 +0000 Subject: [PATCH 20/22] Add new test file e_walauto.test. FossilOrigin-Name: 62ef45140cdbff5eeb8bef506db8b78ced3ace94 --- manifest | 13 +-- manifest.uuid | 2 +- src/test1.c | 38 +++++++++ test/e_walauto.test | 201 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 7 deletions(-) create mode 100644 test/e_walauto.test diff --git a/manifest b/manifest index 56aa9e8cb0..eeea121a6a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\serrors\sin\sthreadtest3\stests\scaused\sby\searlier\stests\sneglecting\sto\sclose\sdatabase\shandles. -D 2014-12-15T08:46:17.172 +C Add\snew\stest\sfile\se_walauto.test. +D 2014-12-15T16:27:12.622 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -238,7 +238,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc F src/tclsqlite.c c6a21c64da1490e14d53cdc2062d1e2e57942622 -F src/test1.c 7e806af12d7915445e46407d32b275d8ca9db4e7 +F src/test1.c 56e33bf6b1827c6ca7520c189131ddd778fb2267 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -478,6 +478,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52 F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a +F test/e_walauto.test a1fa9d36c160cc4001a934d1e009aae597b440b7 F test/e_walckpt.test 3116a98fa0dd9b2c9e493de7c59730adfe436746 F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea @@ -1231,7 +1232,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 ba772cff602ca7c3c0c91451e701f52a872e7a14 -R ed0c57369d0ec456d80773711d0601f8 +P 1d44f1b1a9fefeb2449892775c59765c46784eb1 +R 10b3e0524cfe98a487f450c2b23f40b1 U dan -Z bfcc45ad20cf310717047c8b8c88d22b +Z 762d85cad7a4c7a6623b46eb7c11e324 diff --git a/manifest.uuid b/manifest.uuid index 53e85dbd36..2d88a004d6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1d44f1b1a9fefeb2449892775c59765c46784eb1 \ No newline at end of file +62ef45140cdbff5eeb8bef506db8b78ced3ace94 \ No newline at end of file diff --git a/src/test1.c b/src/test1.c index 851249461c..40acac8360 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5726,6 +5726,43 @@ static int test_wal_checkpoint_v2( return TCL_OK; } +/* +** tclcmd: sqlite3_wal_autocheckpoint db VALUE +*/ +static int test_wal_autocheckpoint( + ClientData clientData, /* Unused */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + int rc; + int iVal; + + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB VALUE"); + return TCL_ERROR; + } + + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) + || Tcl_GetIntFromObj(0, objv[2], &iVal) + ){ + return TCL_ERROR; + } + + rc = sqlite3_wal_autocheckpoint(db, iVal); + Tcl_ResetResult(interp); + if( rc!=SQLITE_OK ){ + const char *zErrCode = sqlite3ErrName(rc); + Tcl_SetObjResult(interp, Tcl_NewStringObj(zErrCode, -1)); + return TCL_ERROR; + } + + return TCL_OK; +} + + /* ** tclcmd: test_sqlite3_log ?SCRIPT? */ @@ -6787,6 +6824,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ #endif { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, + { "sqlite3_wal_autocheckpoint",test_wal_autocheckpoint, 0 }, { "test_sqlite3_log", test_sqlite3_log, 0 }, #ifndef SQLITE_OMIT_EXPLAIN { "print_explain_query_plan", test_print_eqp, 0 }, diff --git a/test/e_walauto.test b/test/e_walauto.test new file mode 100644 index 0000000000..fc394e9053 --- /dev/null +++ b/test/e_walauto.test @@ -0,0 +1,201 @@ +# 2014 December 04 +# +# 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 +source $testdir/wal_common.tcl +set testprefix e_walauto + + +proc read_nbackfill {} { + seek $::shmfd 96 + binary scan [read $::shmfd 4] i nBackfill + set nBackfill +} +proc read_mxframe {} { + seek $::shmfd 16 + binary scan [read $::shmfd 4] i mxFrame + set mxFrame +} + +# Assuming that the main db for database handle +# +proc do_autocommit_threshold_test {tn value} { + + set nBackfillSaved [read_nbackfill] + while {1} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + if {[read_mxframe] >= $value} break + } + + set nBackfillNew [read_nbackfill] + uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1] +} + +# EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used +# to invoke this interface from SQL. +# +# All tests in this file are run twice - once using the +# sqlite3_wal_autocheckpoint() API, and once using "PRAGMA +# wal_autocheckpoint". +# +foreach {tn code} { + 1 { + proc autocheckpoint {db value} { + uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"] + } + } + + 2 { + proc autocheckpoint {db value} { + uplevel [list sqlite3_wal_autocheckpoint $db $value] + return $value + } + } +} { + + eval $code + + reset_db + do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal} + do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) } + set shmfd [open "test.db-shm"] + + # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to + # having the auto-checkpoint enabled with a threshold of 1000 or + # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages. + # + do_autocommit_threshold_test 1.$tn.2 1000 + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + do_autocommit_threshold_test 1.$tn.3 1000 + + # EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a + # wrapper around sqlite3_wal_hook() that causes any database on database + # connection D to automatically checkpoint after committing a + # transaction if there are N or more frames in the write-ahead log file. + # + do_test 1.$tn.4 { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + autocheckpoint db 100 + } {100} + do_autocommit_threshold_test 1.$tn.5 100 + + do_test 1.$tn.6 { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + autocheckpoint db 500 + } {500} + do_autocommit_threshold_test 1.$tn.7 500 + + # EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the + # nFrame parameter disables automatic checkpoints entirely. + # + do_test 1.$tn.7 { + autocheckpoint db 0 ;# Set to zero + for {set i 0} {$i < 10000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] > (5 * 1024 * 1024)} + } 1 + do_test 1.$tn.8 { + sqlite3_wal_checkpoint_v2 db truncate + file size test.db-wal + } 0 + do_test 1.$tn.9 { + autocheckpoint db -4 ;# Set to a negative value + for {set i 0} {$i < 10000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] > (5 * 1024 * 1024)} + } 1 + + # EVIDENCE-OF: R-10203-42688 The callback registered by this function + # replaces any existing callback registered using sqlite3_wal_hook(). + # + set ::wal_hook_callback 0 + proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 } + do_test 1.$tn.10.1 { + db wal_hook wal_hook_callback + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + set ::wal_hook_callback + } 2 + do_test 1.$tn.10.2 { + autocheckpoint db 100 + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + set ::wal_hook_callback + } 2 + + # EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using + # sqlite3_wal_hook() disables the automatic checkpoint mechanism + # configured by this function. + do_test 1.$tn.11.1 { + sqlite3_wal_checkpoint_v2 db truncate + file size test.db-wal + } 0 + do_test 1.$tn.11.2 { + autocheckpoint db 100 + for {set i 0} {$i < 1000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] < (1 * 1024 * 1024)} + } 1 + do_test 1.$tn.11.3 { + db wal_hook wal_hook_callback + for {set i 0} {$i < 1000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + expr {[file size test.db-wal] < (1 * 1024 * 1024)} + } 0 + + # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism + # are PASSIVE. + # + set ::busy_callback_count 0 + proc busy_callback {args} { + puts Hello + incr ::busy_callback_count + return 0 + } + do_test 1.$tn.12.1 { + sqlite3_wal_checkpoint_v2 db truncate + autocheckpoint db 100 + db busy busy_callback + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } {} + do_test 1.$tn.12.2 { + sqlite3 db2 test.db + db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; } + read_nbackfill + } {0} + do_test 1.$tn.12.3 { + for {set i 0} {$i < 1000} {incr i} { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + } + read_nbackfill + } {2} + do_test 1.$tn.12.4 { + set ::busy_callback_count + } {0} + db2 close + + do_test 1.$tn.12.5 { + db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } + read_nbackfill + } {1559} + + db close + close $shmfd +} + +finish_test From 1ee46c01b4822c73169bc093ab51ec79f668daf5 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 15 Dec 2014 20:49:26 +0000 Subject: [PATCH 21/22] Changes to threadtest3 so that "stress2" is more similar to the SDS stress test. FossilOrigin-Name: 5648af96d8e2521c5b0cca19f1358374d032394d --- manifest | 17 ++++--- manifest.uuid | 2 +- test/threadtest3.c | 37 ++++++++------- test/tt3_stress.c | 115 ++++++++++++++++++++------------------------- 4 files changed, 82 insertions(+), 89 deletions(-) diff --git a/manifest b/manifest index eeea121a6a..96dffc16a7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\stest\sfile\se_walauto.test. -D 2014-12-15T16:27:12.622 +C Changes\sto\sthreadtest3\sso\sthat\s"stress2"\sis\smore\ssimilar\sto\sthe\sSDS\sstress\stest. +D 2014-12-15T20:49:26.942 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -913,7 +913,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 -F test/threadtest3.c c8629f836331dd4e5d6ef514b6696605cb593135 +F test/threadtest3.c f8c6595664a4c5ef5f28d97a612386fe14dd1940 F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 @@ -1080,7 +1080,7 @@ F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52 F test/tt3_checkpoint.c 5e63ee65ed5f87176e25a996480cb02c6caec8b4 F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9 -F test/tt3_stress.c edbb00ed1516535691040315e97cf32c62df22d0 +F test/tt3_stress.c c57d804716165811d979d4a719e05baccd79277f F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 @@ -1232,7 +1232,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 1d44f1b1a9fefeb2449892775c59765c46784eb1 -R 10b3e0524cfe98a487f450c2b23f40b1 +P 62ef45140cdbff5eeb8bef506db8b78ced3ace94 +R 9a6502f6d41e6a843f5a509613ed553f +T *branch * threadtest3 +T *sym-threadtest3 * +T -sym-trunk * U dan -Z 762d85cad7a4c7a6623b46eb7c11e324 +Z 02118ab9cf865ac1e1c9e40290c79fe8 diff --git a/manifest.uuid b/manifest.uuid index 2d88a004d6..038c947b8e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62ef45140cdbff5eeb8bef506db8b78ced3ace94 \ No newline at end of file +5648af96d8e2521c5b0cca19f1358374d032394d \ No newline at end of file diff --git a/test/threadtest3.c b/test/threadtest3.c index c8830bb55e..ff8add5bf6 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -121,7 +121,10 @@ struct MD5Context { int isInit; uint32 buf[4]; uint32 bits[2]; - unsigned char in[64]; + union { + unsigned char in[64]; + uint32 in32[16]; + } u; }; typedef struct MD5Context MD5Context; @@ -270,7 +273,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ /* Handle any leading odd-sized chunks */ if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; + unsigned char *p = (unsigned char *)ctx->u.in + t; t = 64-t; if (len < t) { @@ -278,8 +281,8 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ return; } memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse(ctx->u.in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); buf += t; len -= t; } @@ -287,16 +290,16 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ /* Process data in 64-byte chunks */ while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); + memcpy(ctx->u.in, buf, 64); + byteReverse(ctx->u.in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); + memcpy(ctx->u.in, buf, len); } /* @@ -312,7 +315,7 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ - p = ctx->in + count; + p = ctx->u.in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ @@ -322,22 +325,22 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse(ctx->u.in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); + memset(ctx->u.in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count-8); } - byteReverse(ctx->in, 14); + byteReverse(ctx->u.in, 14); /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; + ctx->u.in32[14] = ctx->bits[0]; + ctx->u.in32[15] = ctx->bits[1]; - MD5Transform(ctx->buf, (uint32 *)ctx->in); + MD5Transform(ctx->buf, (uint32 *)ctx->u.in); byteReverse((unsigned char *)ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it is sensitive */ @@ -1445,7 +1448,7 @@ int main(int argc, char **argv){ { lookaside1, "lookaside1", 10000 }, { vacuum1, "vacuum1", 10000 }, { stress1, "stress1", 10000 }, - { stress2, "stress2", 10000 }, + { stress2, "stress2", 60000 }, }; int i; diff --git a/test/tt3_stress.c b/test/tt3_stress.c index a1151dd79c..cdfab9c09c 100644 --- a/test/tt3_stress.c +++ b/test/tt3_stress.c @@ -124,7 +124,6 @@ static char *stress_thread_5(int iTid, void *pArg){ i1++; if( err.rc ) i2++; clear_error(&err, SQLITE_LOCKED); - clear_error(&err, SQLITE_ERROR); } closedb(&err, &db); print_and_free_err(&err); @@ -184,73 +183,66 @@ static void stress1(int nMs){ ** 19. Open and close database connections rapidly. */ -#define STRESS2_TABCNT 5 +#define STRESS2_TABCNT 5 /* count1 in SDS test */ + +#define STRESS2_COUNT2 200 /* count2 in SDS test */ +#define STRESS2_COUNT3 57 /* count2 in SDS test */ static void stress2_workload1(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); + int iTab = (i % (STRESS2_TABCNT-1)) + 1; sql_script_printf(pErr, pDb, "CREATE TABLE IF NOT EXISTS t%d(x PRIMARY KEY, y, z);", iTab ); } static void stress2_workload2(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); + int iTab = (i % (STRESS2_TABCNT-1)) + 1; sql_script_printf(pErr, pDb, "DROP TABLE IF EXISTS t%d;", iTab); } static void stress2_workload3(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); - sql_script_printf(pErr, pDb, "SELECT * FROM t%d WHERE z = 'small'", iTab); + sql_script(pErr, pDb, "SELECT * FROM t0 WHERE z = 'small'"); } static void stress2_workload4(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); - sql_script_printf(pErr, pDb, "SELECT * FROM t%d WHERE z = 'big'", iTab); + sql_script(pErr, pDb, "SELECT * FROM t0 WHERE z = 'big'"); } static void stress2_workload5(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); - sql_script_printf(pErr, pDb, - "INSERT INTO t%d VALUES(random(), hex(randomblob(57)), 'small');", iTab + sql_script(pErr, pDb, + "INSERT INTO t0 VALUES(hex(random()), hex(randomblob(200)), 'small');" ); } static void stress2_workload6(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); - sql_script_printf(pErr, pDb, - "INSERT INTO t%d VALUES(random(), hex(randomblob(2000)), 'big');", iTab + sql_script(pErr, pDb, + "INSERT INTO t0 VALUES(hex(random()), hex(randomblob(57)), 'big');" ); } static void stress2_workload7(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); sql_script_printf(pErr, pDb, - "UPDATE t%d SET y = hex(randomblob(57)) " - "WHERE (x %% 5)==(%d %% 5) AND z='small';" - ,iTab, i + "UPDATE t0 SET y = hex(randomblob(200)) " + "WHERE x LIKE hex((%d %% 5)) AND z='small';" + ,i ); } static void stress2_workload8(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); sql_script_printf(pErr, pDb, - "UPDATE t%d SET y = hex(randomblob(2000)) " - "WHERE (x %% 5)==(%d %% 5) AND z='big';" - ,iTab, i + "UPDATE t0 SET y = hex(randomblob(57)) " + "WHERE x LIKE hex(%d %% 5) AND z='big';" + ,i ); } static void stress2_workload9(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); sql_script_printf(pErr, pDb, - "DELETE FROM t%d WHERE (x %% 5)==(%d %% 5) AND z='small';" - ,iTab, i + "DELETE FROM t0 WHERE x LIKE hex(%d %% 5) AND z='small';", i ); } static void stress2_workload10(Error *pErr, Sqlite *pDb, int i){ - int iTab = (i % STRESS2_TABCNT); sql_script_printf(pErr, pDb, - "DELETE FROM t%d WHERE (x %% 5)==(%d %% 5) AND z='big';" - ,iTab, i + "DELETE FROM t0 WHERE x LIKE hex(%d %% 5) AND z='big';", i ); } @@ -296,13 +288,16 @@ static char *stress2_thread_wrapper(int iTid, void *pArg){ int i1 = 0; int i2 = 0; - opendb(&err, &db, pCtx->zDb, 0); while( !timetostop(&err) ){ - pCtx->xProc(&err, &db, i1); - i2 += (err.rc==SQLITE_OK); - clear_error(&err, SQLITE_LOCKED); - clear_error(&err, SQLITE_ERROR); - i1++; + int cnt; + opendb(&err, &db, pCtx->zDb, 0); + for(cnt=0; err.rc==SQLITE_OK && cntxProc(&err, &db, i1); + i2 += (err.rc==SQLITE_OK); + clear_error(&err, SQLITE_LOCKED); + i1++; + } + closedb(&err, &db); } print_and_free_err(&err); @@ -339,41 +334,33 @@ static void stress2(int nMs){ { stress2_workload14 }, { stress2_workload17 }, }; - const char *azDb[] = { - "test.db", - "file::memory:?cache=shared" - }; - int j; + const char *zDb = "test.db"; - for(j=0; j Date: Tue, 16 Dec 2014 00:08:31 +0000 Subject: [PATCH 22/22] Make sure the sqlite3BtreeCount() routine does not leave index cursors in an inconsistent state, as doing so might result in an assertion fault inside of sqlite3BtreeKey() called from saveAllCursors() if content is deleted out from under the statement that issued the sqlite3BtreeCount() call. FossilOrigin-Name: 5b1b697040116048e464b3ebab8395fe088e389a --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/btree.c | 2 +- test/pragma.test | 26 +++++++++++++++++++++++++- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index eeea121a6a..8542d0d893 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\snew\stest\sfile\se_walauto.test. -D 2014-12-15T16:27:12.622 +C Make\ssure\sthe\ssqlite3BtreeCount()\sroutine\sdoes\snot\sleave\sindex\scursors\sin\san\ninconsistent\sstate,\sas\sdoing\sso\smight\sresult\sin\san\sassertion\sfault\sinside\nof\ssqlite3BtreeKey()\scalled\sfrom\ssaveAllCursors()\sif\scontent\sis\sdeleted\sout\nfrom\sunder\sthe\sstatement\sthat\sissued\sthe\ssqlite3BtreeCount()\scall. +D 2014-12-16T00:08:31.918 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 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 ab4b60fcf9920d862ff4d96efb1d605e4e7701a0 +F src/btree.c 92f745ccd18099973beb28e25fce80148545429e F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 F src/build.c 162d84e4833b03f9d07192ef06057b0226f6e543 @@ -782,7 +782,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test 4e12d43f4639ea8a0e366d9c64e0009afe2eb544 -F test/pragma.test 49ac8a73c0daa574824538fed28727d1259fe735 +F test/pragma.test aa16dedfe01c02c8895169012f7dfde9c163f0d5 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a @@ -1232,7 +1232,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 1d44f1b1a9fefeb2449892775c59765c46784eb1 -R 10b3e0524cfe98a487f450c2b23f40b1 -U dan -Z 762d85cad7a4c7a6623b46eb7c11e324 +P 62ef45140cdbff5eeb8bef506db8b78ced3ace94 +R f292d3e817736f788b9a711a02a9af3e +U drh +Z 46e826bbedddd4a807c643712561f79a diff --git a/manifest.uuid b/manifest.uuid index 2d88a004d6..af4336842d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62ef45140cdbff5eeb8bef506db8b78ced3ace94 \ No newline at end of file +5b1b697040116048e464b3ebab8395fe088e389a \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index a73c831219..d24f6a876a 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8278,7 +8278,7 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ if( pCur->iPage==0 ){ /* All pages of the b-tree have been visited. Return successfully. */ *pnEntry = nEntry; - return SQLITE_OK; + return moveToRoot(pCur); } moveToParent(pCur); }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); diff --git a/test/pragma.test b/test/pragma.test index e660ab0fe7..09b9b6c14f 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -454,10 +454,34 @@ do_execsql_test pragma-3.21 { do_execsql_test pragma-3.22 { PRAGMA integrity_check(2); } {{non-unique entry in index t1a} {NULL value in t1x.a}} -do_execsql_test pragma-3.21 { +do_execsql_test pragma-3.23 { PRAGMA integrity_check(1); } {{non-unique entry in index t1a}} +# PRAGMA integrity check (or more specifically the sqlite3BtreeCount() +# interface) used to leave index cursors in an inconsistent state +# which could result in an assertion fault in sqlite3BtreeKey() +# called from saveCursorPosition() if content is removed from the +# index while the integrity_check is still running. This test verifies +# that problem has been fixed. +# +do_test pragma-3.30 { + db close + delete_file test.db + sqlite3 db test.db + db eval { + CREATE TABLE t1(a,b,c); + WITH RECURSIVE + c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<100) + INSERT INTO t1(a,b,c) SELECT i, printf('xyz%08x',i), 2000-i FROM c; + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1bc ON t1(b,c); + } + db eval {PRAGMA integrity_check} { + db eval {DELETE FROM t1} + } +} {} + # Test modifying the cache_size of an attached database. ifcapable pager_pragmas&&attach { do_test pragma-4.1 {