- C Merge\sall\sthe\slatest\senhancements\sand\sfixes\sfrom\strunk.
- D 2015-11-20T13:49:01.510
- F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1
-C Remove\sunreachable\sbranches\sfrom\sthe\sdecltype\scomputation\slogic\sin\sthe\squery\nplanner.
-D 2015-12-02T19:46:12.775
++C Merge\srecent\senhancements\sfrom\strunk.
++D 2015-12-02T20:53:14.202
+ F Makefile.in 23d9a63484a383fc64951b25ef44067930f98dc6
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
- F Makefile.msc e928e68168df69b353300ac87c10105206653a03
+ F Makefile.msc e8fdca1cb89a1b58b5f4d3a130ea9a3d28cb314d
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
F VERSION 8b9d3ac6f1962f94e06ba05462422a544f9c4e36
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c 2869a76c03eb393ee795416e2387005553df72bc
- F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d
+ F src/bitvec.c 1a78d450a17c5016710eec900bedfc5729bf9bdf
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
-F src/btree.c d3bdd8462a86492e2ebc9aca4a0168429017de25
-F src/btree.h 2d76dee44704c47eed323356a758662724b674a0
-F src/btreeInt.h 3ab435ed27adea54d040584b0bcc488ee7db1e38
-F src/build.c e83da4d004a4e050c01acbb821ff7a7b1019c29b
+F src/btree.c ab52539c0c321de2bf4bb1238cff11eaad55c0bb
+F src/btree.h beef31274289a103fa811a7d7adc2dcedbcf2077
+F src/btreeInt.h 99ebf5c9716a8dd1ea6c0583b624e8e0de148d61
- F src/build.c a59767596bf5dfa2c9cceb756bff50a17741c2d2
++F src/build.c a3fa162b06a16e10136e1693b0eae9998a82b324
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
- F src/ctime.c 509ef9c64d1321f42448f111da86400b1799218a
+ F src/ctime.c 58eda76364fb6f374e044aa4493219b13abf9400
F src/date.c fb1c99172017dcc8e237339132c91a21a0788584
F src/dbstat.c ffd63fc8ba7541476ced189b95e95d7f2bc63f78
F src/delete.c 00af9f08a15ddc5cba5962d3d3e5bf2d67b2e7da
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
F src/os_common.h abdb9a191a367793268fe553d25bab894e986a0e
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
- F src/os_unix.c eb24e0340fbe3cfd0eabfb15a71476953e54fa73
- F src/os_win.c 2d77dab5c555a18c0aff379c6a692fc3499044d9
+ F src/os_unix.c 60997373a8d90bd17e1c0e49d11ef361b713439b
+ F src/os_win.c 386fba30419e8458b13209781c2af5590eab2811
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
- F src/pager.c 44cc9e8e5df703e52b8e305ff9af2fddf6c62d0f
- F src/pager.h f392409a9c64a700c4756b6111b8e73a78d07cf3
-F src/pager.c f92aacd5216d8815136c9e0190041783c602641a
-F src/pager.h 9153c71a89dc82a5a77e485f3929792116c70aae
-F src/parse.y 23737e649c26ce327603799e57f5c2ff50e5e6ba
++F src/pager.c d4c71e12bf9ac51ee38043aa718eace0b52c7e98
++F src/pager.h c6b437a6543c7c57d7f85ceb474e176f1e62163e
+F src/parse.y b0ad024157be717d43f9e1eb4f377873574153a3
F src/pcache.c 73895411fa6b7bd6f0091212feabbe833b358d23
F src/pcache.h 1ff11adce609ba7de139b6abfabaf9a2bac947b5
- F src/pcache1.c 902e1bc7bdaa81b40f8543407c5e2ac8ef4dc035
+ F src/pcache1.c 46a110be31a8d9f9b41431733836822ca0dd27ab
F src/pragma.c f3e7147299ca05ef4304a36f1fd6e002729c72c6
F src/pragma.h 3d94aebbebd2089899fecc01909bf2608b39507d
F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
- F src/printf.c f8fc8f04e75b1e983ef2793c27ec7a43b287e94a
+ F src/printf.c ca05561795ad6c2fa47acdd007702586282f7feb
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
- F src/resolve.c 1954a0f01bf65d78d7d559aea3d5c67f33376d91
+ F src/resolve.c f4c897ca76ca6d5e0b3f0499c627392ffe657c8e
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
- F src/select.c 2376d320907a5c28c55290f18fd94aa3400bf97c
- F src/shell.c f0f59ea60ad297f671b7ae0fb957a736ad17c92c
- F src/sqlite.h.in fa62718f73553f06b2f2e362fd09ccb4e1cbb626
+ F src/select.c 1611828a7116e5f6cc1e69cd07d59b0d2c662ea9
+ F src/shell.c 2796237990d42e6a5a7beafee65ef70cc8767d21
+ F src/sqlite.h.in 5bd83191711d3dc85030326daa9e8e5226a495e7
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
- F src/sqlite3ext.h 4b66e3e3435da4b4c8c83696d0349f0c503b3924
+ F src/sqlite3ext.h 41ef50b0418a7c5ad1337bb80db5a7928dee764f
-F src/sqliteInt.h 64256d193a16a147d9f6317cc4e095fdd3e0a2e9
+F src/sqliteInt.h f298ca1b9fc4826becdec3918f10d216a23ac4d1
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
F src/test_blob.c e5a7a81d61a780da79101aeb1e60d300af169e07
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
- F src/test_config.c a482301b987f859098d5985cc19c239d8cd6e340
-F src/test_config.c 48850687dd5abc8260e23835632511054ccae172
++F src/test_config.c 311a6bdbd6865d534e7c3cf853bb7dd865d63674
F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
- F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
+ F src/test_fs.c aab47ac456316502faa265daadf9ac832fea12b9
F src/test_func.c 0d9c25956152adefee8881c6fadc8354793764d0
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
F src/tokenize.c 5606871a377f390af7040ec3c12e0d183512d785
F src/treeview.c 78842e90c1f71269e7a73a1d4221b6fe360bab66
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
- F src/update.c 40e51cd0883cb5bfd6abb7d8a7cd8aa47fab2945
+ F src/update.c 17332f9fe818cbc0444c36a811800af8498af4c3
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
- F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
+ F src/util.c e802e8e311a0d6c48cd1b3e89db164f6f0248d70
-F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
-F src/vdbe.c 4d75375fa8bf911aa76ab8383d6f7eea0dec0fda
+F src/vacuum.c 983cc3754718ef169a6ea9aef86798bd28106f21
- F src/vdbe.c 6b125884a09e7fc33b062baa0b44f38fe6f40af8
++F src/vdbe.c ff46035880b746d7e2b126670078dae012b59c49
F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637
- F src/vdbeInt.h 33403622c6a8feaaac5f0f3f17f5d1bf6df42286
+ F src/vdbeInt.h 75c2e82ee3357e9210c06474f8d9bdf12c81105d
F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca
- F src/vdbeaux.c 0a6263b83b63843360b676542d5eb5e2846c178f
- F src/vdbeblob.c 565fabd302f5fca3bdf3d56cac330483616a39b6
-F src/vdbeaux.c 9a234c9aaab4ad725daf94667cfed441a437c52d
++F src/vdbeaux.c 1236e154f9e1ad37d3d5640f57f147002f3ec00e
+ F src/vdbeblob.c fdc4a81605ae7a35ae94a55bd768b66d6be16f15
F src/vdbemem.c fdd1578e47bea61390d472de53c565781d81e045
- F src/vdbesort.c 8b23930a1289526f6d2a3a9f2e965bcc963e4a68
+ F src/vdbesort.c a7ec02da4494c59dfd071126dd3726be5a11459d
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
F src/vtab.c 2a8b44aa372c33f6154208e7a7f6c44254549806
F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
- F src/wal.c fd2351d771df2e147b0d6a952314078fa20af171
-F src/wal.c 1569802364cd192bbd5c4a8ea3fd6de593edecbd
-F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
++F src/wal.c bacf8a69cfed6581600002519e4cd30c2220326e
+F src/wal.h 361b16891d2772294b138054c84f5a3bad6e9d05
F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba
- F src/where.c 6aceb72cc58dc06922a9e1604d559c8ca4c3e728
- F src/whereInt.h 7892bb54cf9ca0ae5c7e6094491b94c9286dc647
- F src/wherecode.c 4c96182e7b25e4be54008dee2da5b9c2f8480b9b
- F src/whereexpr.c e63244ca06c503e5f3c5b7f3c9aea0db826089ed
+ F src/where.c b18edbb9e5afabb77f4f27550c471c5c824e0fe7
+ F src/whereInt.h e20801d89e34de1912bb6a3babb30c390da27add
+ F src/wherecode.c dfbfe198e418b01f208b489e088edd230c91a4e7
+ F src/whereexpr.c eebba8340c90de73b3d3bbe8c43b84559b8e6e2c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
- F test/concurrent2.test f20913d376d993a85f28ef3323f09d4cba37206a
+F test/concfault.test 500f17c3fcfe7705114422bcc6ddd3c740001a43
+F test/concurrent.test 634b6a88f1942f5d68cc89d4d5efa2b11ba7913c
++F test/concurrent2.test 77d655c6af93e77803b5c926555a838bb21f922f
+F test/concurrent3.test 0a5f7e3036d1eccf0782d7153ac21f5f222e9468
F test/conflict.test 841bcf7cabbfca39c577eb8411ea8601843b46a8
F test/conflict2.test 0d3af4fb534fa1bd020c79960bb56e4d52655f09
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
- P f2cde4cfc58cc372f59ae274bf0c2f7cf6e7ddf9 35c7f6cba6febf2480de01fca9d61b8065bf1c12
- R c1404ace283281f01646ea3d425143a2
-P 3e1d71fcaf57c0223ab9a7366c8607f8f66bb21c
-R 0397cf9717330ffe9055735c8207c81a
++P 41c8b8e39bc0483cfbc0b4bfcc8ef8b2737a70a9 4f2bcff94c672312805be1400050a7026f93a9d7
++R 1055895e20d2661fa554c8715dd55dea
U drh
- Z 1cdd9c780b66b45977a11df8c67e2bf8
-Z 6381d064415ccbeec9de47fb6017aaa8
++Z 24ef1b5b92d0b1a13c94dec0494ce832
--- /dev/null
- } {wal 33}
+# 2015 July 26
+#
+# 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.
+#
+#***********************************************************************
+#
+# Miscellaneous tests for transactions started with BEGIN CONCURRENT.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/wal_common.tcl
+set ::testprefix concurrent2
+
+ifcapable !concurrent {
+ finish_test
+ return
+}
+
+do_multiclient_test tn {
+
+ do_test 1.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(x);
+ CREATE TABLE t2(y);
+ }
+ } {wal}
+ do_test 1.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+
+ # Test that an CONCURRENT transaction that allocates/frees no pages does
+ # not conflict with a transaction that does allocate pages.
+ do_test 1.$tn.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(4);
+ }
+ sql2 {
+ INSERT INTO t2 VALUES(randomblob(1500));
+ }
+ sql1 {
+ COMMIT;
+ }
+ } {}
+ do_test 1.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+
+ # But that an CONCURRENT transaction does conflict with a transaction
+ # that modifies the db schema.
+ do_test 1.$tn.3 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(5);
+ }
+ sql2 {
+ CREATE TABLE t3(z);
+ }
+ list [catch { sql1 COMMIT } msg] $msg
+ } {1 {database is locked}}
+ do_test 1.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+
+ # Test that an CONCURRENT transaction that allocates at least one page
+ # does not conflict with a transaction that allocates no pages.
+ do_test 1.$tn.4 {
+ sql1 {
+ ROLLBACK;
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(randomblob(1500));
+ }
+ sql2 {
+ INSERT INTO t2 VALUES(8);
+ }
+ sql1 {
+ COMMIT;
+ }
+ } {}
+
+ do_test 1.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+}
+
+do_multiclient_test tn {
+ do_test 2.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(x UNIQUE);
+ CREATE TABLE t2(y UNIQUE);
+ }
+ } {wal}
+
+ do_test 2.$tn.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(randomblob(1500));
+ }
+ sql2 {
+ INSERT INTO t2 VALUES(randomblob(1500));
+ }
+ sql1 COMMIT
+ } {}
+
+ do_test 2.$tn.3 { sql3 { PRAGMA integrity_check } } {ok}
+
+ do_test 2.$tn.4 {
+ sql1 {
+ BEGIN CONCURRENT;
+ DELETE FROM t1;
+ }
+ sql2 {
+ DELETE FROM t2;
+ }
+ sql1 COMMIT
+ } {}
+
+ do_test 2.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+
+ do_test 2.$tn.6 {
+ sql1 {
+ INSERT INTO t1 VALUES(randomblob(1500));
+ INSERT INTO t1 VALUES(randomblob(1500));
+ INSERT INTO t2 VALUES(randomblob(1500));
+ DELETE FROM t1 WHERE rowid=1;
+ }
+
+ sql1 {
+ BEGIN CONCURRENT;
+ DELETE FROM t1 WHERE rowid=2;
+ }
+
+ sql2 {
+ DELETE FROM t2;
+ }
+
+ sql1 COMMIT
+ } {}
+
+ do_test 2.$tn.7 { sql3 { PRAGMA integrity_check } } {ok}
+}
+
+#-------------------------------------------------------------------------
+# When an CONCURRENT transaction is opened on a database, the nFree and
+# iTrunk header fields of the cached version of page 1 are both set
+# to 0. This allows an CONCURRENT transaction to use its own private
+# free-page-list, which is merged with the main database free-list when
+# the transaction is committed.
+#
+# The following tests check that nFree/iTrunk are correctly restored if
+# an CONCURRENT transaction is rolled back, and that savepoint rollbacks
+# that occur within CONCURRENT transactions do not incorrectly restore
+# these fields to their on-disk values.
+#
+reset_db
+do_execsql_test 3.0 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(x, y);
+ INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
+ DELETE FROM t1;
+} {wal}
+
+do_execsql_test 3.1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(1, 2);
+ ROLLBACK;
+}
+
+do_execsql_test 3.2 { PRAGMA integrity_check } {ok}
+do_execsql_test 3.3 { PRAGMA freelist_count } {2}
+
+do_execsql_test 3.4.1 {
+ BEGIN CONCURRENT;
+ PRAGMA freelist_count;
+} {2}
+do_execsql_test 3.4.2 {
+ SAVEPOINT xyz;
+ INSERT INTO t1 VALUES(randomblob(1500), NULL);
+ PRAGMA freelist_count;
+} {0}
+do_execsql_test 3.4.3 {
+ ROLLBACK TO xyz;
+} {}
+do_execsql_test 3.4.4 { PRAGMA freelist_count } {0}
+do_execsql_test 3.4.5 { COMMIT; PRAGMA freelist_count } {2}
+do_execsql_test 3.4.6 { PRAGMA integrity_check } {ok}
+
+do_execsql_test 3.5.1 {
+ BEGIN CONCURRENT;
+ UPDATE t1 SET x=randomblob(10) WHERE y=555;
+ PRAGMA freelist_count;
+} {0}
+do_execsql_test 3.5.2 {
+ ROLLBACK;
+ PRAGMA freelist_count;
+} {2}
+do_execsql_test 3.5.3 { PRAGMA integrity_check } {ok}
+
+#-------------------------------------------------------------------------
+# Test that nothing goes wrong if an CONCURRENT transaction allocates a
+# page at the end of the file, frees it within the same transaction, and
+# then has to move the same page to avoid a conflict on COMMIT.
+#
+do_multiclient_test tn {
+ do_test 4.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(x);
+ CREATE TABLE t2(x);
+ }
+ } {wal}
+
+ do_test 4.$tn.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(randomblob(1500));
+ INSERT INTO t1 VALUES(randomblob(1500));
+ DELETE FROM t1 WHERE rowid = 1;
+ }
+
+ sql2 {
+ INSERT INTO t2 VALUES(randomblob(1500));
+ INSERT INTO t2 VALUES(randomblob(1500));
+ INSERT INTO t2 VALUES(randomblob(1500));
+ INSERT INTO t2 VALUES(randomblob(1500));
+ DELETE FROM t2 WHERE rowid IN (1, 2);
+ }
+
+ sql1 COMMIT
+ } {}
+}
+
+#-------------------------------------------------------------------------
+#
+do_multiclient_test tn {
+ do_test 5.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(x);
+ CREATE TABLE t2(x);
+ INSERT INTO t1 VALUES(randomblob(1500));
+ PRAGMA page_count;
+ }
+ } {wal 4}
+
+ do_test 5.$tn.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t2 VALUES(randomblob(1500));
+ PRAGMA page_count;
+ }
+ } {5}
+
+ do_test 5.$tn.3 {
+ sql2 {
+ DELETE FROM t1;
+ PRAGMA freelist_count;
+ PRAGMA page_count;
+ }
+ } {1 4}
+
+ do_test 5.$tn.4 { sql1 COMMIT } {}
+ do_test 5.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+}
+
+#-------------------------------------------------------------------------
+#
+do_multiclient_test tn {
+ do_test 6.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES(randomblob(1500));
+ PRAGMA wal_checkpoint;
+ }
+ } {wal 0 5 5}
+
+ do_test 6.$tn.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(randomblob(1500));
+ INSERT INTO t1 VALUES(randomblob(1500));
+ }
+ } {}
+
+ do_test 6.$tn.3 {
+ sql2 {
+ BEGIN;
+ INSERT INTO t1 VALUES(randomblob(1500));
+ INSERT INTO t1 VALUES(randomblob(1500));
+ COMMIT;
+ }
+ } {}
+
+ do_test 6.$tn.4 {
+ list [catch { sql1 COMMIT } msg] $msg
+ } {1 {database is locked}}
+ do_test 6.$tn.5 { sql3 { PRAGMA integrity_check } } {ok}
+ do_test 6.$tn.5 { sql3 { SELECT count(*) from t1 } } {3}
+}
+
+#-------------------------------------------------------------------------
+# Test that if a corrupt wal-index-header is encountered when attempting
+# to commit a CONCURRENT transaction, the transaction is not committed
+# (or rolled back) and that SQLITE_BUSY_SNAPSHOT is returned to the user.
+#
+catch { db close }
+forcedelete test.db
+testvfs tvfs
+sqlite3 db test.db -vfs tvfs
+do_execsql_test 7.1 {
+ PRAGMA journal_mode = wal;
+ BEGIN;
+ CREATE TABLE t1(a, b, PRIMARY KEY(a));
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(3, 4);
+ COMMIT;
+ BEGIN CONCURRENT;
+ INSERT INTO t1 VALUES(5, 6);
+ INSERT INTO t1 VALUES(7, 8);
+ SELECT * FROM t1;
+} {wal 1 2 3 4 5 6 7 8}
+
+# Corrupt the wal-index header
+incr_tvfs_hdr test.db 11 1
+
+do_catchsql_test 7.2.1 { COMMIT } {1 {database is locked}}
+do_test 7.2.2 { sqlite3_extended_errcode db } SQLITE_BUSY_SNAPSHOT
+
+do_execsql_test 7.3.1 {
+ SELECT * FROM t1;
+ ROLLBACK;
+} {1 2 3 4 5 6 7 8}
+do_execsql_test 7.3.2 {
+ SELECT * FROM t1;
+} {1 2 3 4}
+
+#-------------------------------------------------------------------------
+# Test that "PRAGMA integrity_check" works within a concurrent
+# transaction. Within a concurrent transaction, "PRAGMA integrity_check"
+# is unable to detect unused database pages, but can detect other types
+# of corruption.
+#
+reset_db
+do_execsql_test 8.1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE kv(k INTEGER PRIMARY KEY, v UNIQUE);
+ INSERT INTO kv VALUES(NULL, randomblob(750));
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ INSERT INTO kv SELECT NULL, randomblob(750) FROM kv;
+ DELETE FROM kv WHERE rowid%2;
+ PRAGMA freelist_count;
-
++} {wal 34}
+do_execsql_test 8.2 { PRAGMA integrity_check } ok
+do_execsql_test 8.3 {
+ BEGIN CONCURRENT;
+ PRAGMA integrity_check;
+} {ok}
+do_execsql_test 8.4 {
+ INSERT INTO kv VALUES(1100, 1100);
+ PRAGMA integrity_check;
+} {ok}
+do_execsql_test 8.5 {
+ COMMIT;
+ PRAGMA integrity_check;
+} {ok}
+
+#-------------------------------------------------------------------------
+# Test that concurrent transactions do not allow foreign-key constraints
+# to be bypassed.
+#
+do_multiclient_test tn {
+ do_test 9.$tn.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE pp(i INTEGER PRIMARY KEY, j);
+ CREATE TABLE cc(a, b REFERENCES pp);
+
+ WITH seq(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM seq WHERE i<100)
+ INSERT INTO pp SELECT i, randomblob(1000) FROM seq;
+
+ PRAGMA foreign_keys = 1;
+ }
+ } {wal}
+
+
+ do_test 9.$tn.2.1 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO cc VALUES(42, 42);
+ }
+ } {}
+ do_test 9.$tn.2.2 {
+ sql2 { DELETE FROM pp WHERE i=42 }
+ list [catch { sql1 COMMIT } msg] $msg
+ } {1 {database is locked}}
+ do_test 9.$tn.2.3 {
+ sql1 ROLLBACK
+ } {}
+
+ do_test 9.$tn.3.1 {
+ sql1 {
+ PRAGMA foreign_keys = 0;
+ BEGIN CONCURRENT;
+ INSERT INTO cc VALUES(43, 43);
+ }
+ } {}
+ do_test 9.$tn.3.2 {
+ sql2 { DELETE FROM pp WHERE i=43 }
+ list [catch { sql1 COMMIT } msg] $msg
+ } {0 {}}
+
+ do_test 9.$tn.4.1 {
+ sql1 {
+ PRAGMA foreign_keys = on;
+ BEGIN CONCURRENT;
+ INSERT INTO cc VALUES(44, 44);
+ }
+ } {}
+ do_test 9.$tn.4.2 {
+ sql2 { DELETE FROM pp WHERE i=1 }
+ list [catch { sql1 COMMIT } msg] $msg
+ } {0 {}}
+}
+
+#-------------------------------------------------------------------------
+# Test that even if a SELECT statement appears before all writes within
+# a CONCURRENT transaction, the pages it reads are still considered when
+# considering whether or not the transaction may be committed.
+#
+do_multiclient_test tn {
+ do_test 10.$tn.1.1 {
+ sql1 {
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(a);
+ CREATE TABLE t2(b);
+ CREATE TABLE t3(c);
+ INSERT INTO t1 VALUES(1), (2), (3);
+ INSERT INTO t2 VALUES(1), (2), (3);
+ INSERT INTO t3 VALUES(1), (2), (3);
+ }
+ } {wal}
+
+ do_test 10.$tn.1.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ SELECT * FROM t1;
+ INSERT INTO t2 VALUES(4);
+ }
+ } {1 2 3}
+
+ do_test 10.$tn.1.3 {
+ sql2 { INSERT INTO t1 VALUES(4) }
+ list [catch {sql1 COMMIT} msg] $msg
+ } {1 {database is locked}}
+ sql1 ROLLBACK
+
+ # In this case, because the "SELECT * FROM t1" is first stepped before
+ # the "BEGIN CONCURRENT", the pages it reads are not recorded by the
+ # pager object. And so the transaction can be committed. Technically
+ # this behaviour (the effect of an ongoing SELECT on a BEGIN CONCURRENT
+ # transacation) is undefined.
+ #
+ do_test 10.$tn.2.1 {
+ code1 {
+ set ::stmt [sqlite3_prepare db "SELECT * FROM t1" -1 dummy]
+ sqlite3_step $::stmt
+ }
+ } {SQLITE_ROW}
+ do_test 10.$tn.2.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t2 VALUES(4);
+ }
+ code1 {
+ set res [list]
+ lappend res [sqlite3_column_int $::stmt 0]
+ while {[sqlite3_step $::stmt]=="SQLITE_ROW"} {
+ lappend res [sqlite3_column_int $::stmt 0]
+ }
+ sqlite3_finalize $::stmt
+ set res
+ }
+ } {1 2 3 4}
+ do_test 10.$tn.2.3 {
+ sql2 { INSERT INTO t1 VALUES(5) }
+ sql1 COMMIT
+ } {}
+
+ # More tests surrounding long-lived prepared statements and concurrent
+ # transactions.
+ do_test 10.$tn.3.1 {
+ sql1 {
+ BEGIN CONCURRENT;
+ SELECT * FROM t1;
+ COMMIT;
+ }
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t2 VALUES(5);
+ }
+ sql2 {
+ INSERT INTO t1 VALUES(5);
+ }
+ sql1 COMMIT
+ sql3 {
+ SELECT * FROM t2;
+ }
+ } {1 2 3 4 5}
+ do_test 10.$tn.3.2 {
+ sql1 {
+ BEGIN CONCURRENT;
+ SELECT * FROM t1;
+ ROLLBACK;
+ }
+ sql1 {
+ BEGIN CONCURRENT;
+ INSERT INTO t2 VALUES(6);
+ }
+ sql2 {
+ INSERT INTO t1 VALUES(6);
+ }
+ sql1 COMMIT
+ sql3 { SELECT * FROM t2 }
+ } {1 2 3 4 5 6}
+ do_test 10.$tn.3.3 {
+ sql1 { BEGIN CONCURRENT }
+ code1 {
+ set ::stmt [sqlite3_prepare db "SELECT * FROM t1" -1 dummy]
+ sqlite3_step $::stmt
+ }
+ sql1 {
+ INSERT INTO t2 VALUES(7);
+ SELECT * FROM t3;
+ ROLLBACK;
+ BEGIN CONCURRENT;
+ }
+ sql2 { INSERT INTO t3 VALUES(5) }
+ code1 { sqlite3_finalize $::stmt }
+ sql1 {
+ INSERT INTO t2 VALUES(8);
+ COMMIT;
+ }
+ } {}
+}
+
+
+finish_test