blob: 7b79d0e232f9c5aa4eeba0ef862dd7320171d188 [file] [log] [blame]
dand3f8f942010-04-13 11:35:01 +00001# 2010 April 13
2#
3# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
5#
6# May you do good and not evil.
7# May you find forgiveness for yourself and forgive others.
8# May you share freely, never taking more than you give.
9#
10#***********************************************************************
11# This file implements regression tests for SQLite library. The
12# focus of this file is testing the operation of the library in
13# "PRAGMA journal_mode=WAL" mode.
14#
dan7c246102010-04-12 19:00:29 +000015
16set testdir [file dirname $argv0]
17source $testdir/tester.tcl
dane264d982010-04-14 18:06:50 +000018source $testdir/lock_common.tcl
dan7c246102010-04-12 19:00:29 +000019
20proc reopen_db {} {
danb9bf16b2010-04-14 11:23:30 +000021 catch { db close }
dan31f98fc2010-04-27 05:42:32 +000022 file delete -force test.db test.db-wal test.db-wal-summary
dan7c246102010-04-12 19:00:29 +000023 sqlite3_wal db test.db
dan7c246102010-04-12 19:00:29 +000024}
25
dan67032392010-04-17 15:42:43 +000026set ::blobcnt 0
27proc blob {nByte} {
28 incr ::blobcnt
29 return [string range [string repeat "${::blobcnt}x" $nByte] 1 $nByte]
30}
31
dan7c246102010-04-12 19:00:29 +000032proc sqlite3_wal {args} {
33 eval sqlite3 $args
dane04dc882010-04-20 18:53:15 +000034 [lindex $args 0] eval { PRAGMA page_size = 1024 }
dan7c246102010-04-12 19:00:29 +000035 [lindex $args 0] eval { PRAGMA journal_mode = wal }
dan67032392010-04-17 15:42:43 +000036 [lindex $args 0] eval { PRAGMA synchronous = normal }
37 [lindex $args 0] function blob blob
dan7c246102010-04-12 19:00:29 +000038}
39
dan97a31352010-04-16 13:59:31 +000040proc log_file_size {nFrame pgsz} {
41 expr {12 + ($pgsz+16)*$nFrame}
42}
43
dan3de777f2010-04-17 12:31:37 +000044proc log_deleted {logfile} {
45 return [expr [file exists $logfile]==0]
46}
47
dan7c246102010-04-12 19:00:29 +000048#
49# These are 'warm-body' tests used while developing the WAL code. They
50# serve to prove that a few really simple cases work:
51#
52# wal-1.*: Read and write the database.
53# wal-2.*: Test MVCC with one reader, one writer.
54# wal-3.*: Test transaction rollback.
55# wal-4.*: Test savepoint/statement rollback.
56# wal-5.*: Test the temp database.
57# wal-6.*: Test creating databases with different page sizes.
58#
59
60do_test wal-0.1 {
dan67032392010-04-17 15:42:43 +000061 execsql { PRAGMA synchronous = normal }
dan7c246102010-04-12 19:00:29 +000062 execsql { PRAGMA journal_mode = wal }
63} {wal}
dane04dc882010-04-20 18:53:15 +000064do_test wal-0.2 {
65 file size test.db
66} {1024}
dan7c246102010-04-12 19:00:29 +000067
68do_test wal-1.0 {
69 execsql {
70 BEGIN;
71 CREATE TABLE t1(a, b);
72 }
dane04dc882010-04-20 18:53:15 +000073 list [file exists test.db-journal] \
74 [file exists test.db-wal] \
75 [file size test.db]
76} {0 1 1024}
dan7c246102010-04-12 19:00:29 +000077do_test wal-1.1 {
78 execsql COMMIT
79 list [file exists test.db-journal] [file exists test.db-wal]
80} {0 1}
81do_test wal-1.2 {
82 # There are now two pages in the log.
83 file size test.db-wal
dan97a31352010-04-16 13:59:31 +000084} [log_file_size 2 1024]
dan7c246102010-04-12 19:00:29 +000085
86do_test wal-1.3 {
87 execsql { SELECT * FROM sqlite_master }
88} {table t1 t1 2 {CREATE TABLE t1(a, b)}}
89
90do_test wal-1.4 {
91 execsql { INSERT INTO t1 VALUES(1, 2) }
92 execsql { INSERT INTO t1 VALUES(3, 4) }
93 execsql { INSERT INTO t1 VALUES(5, 6) }
94 execsql { INSERT INTO t1 VALUES(7, 8) }
95 execsql { INSERT INTO t1 VALUES(9, 10) }
96} {}
97
98do_test wal-1.5 {
99 execsql { SELECT * FROM t1 }
100} {1 2 3 4 5 6 7 8 9 10}
101
102do_test wal-2.1 {
103 sqlite3_wal db2 ./test.db
104 execsql { BEGIN; SELECT * FROM t1 } db2
105} {1 2 3 4 5 6 7 8 9 10}
106
107do_test wal-2.2 {
108 execsql { INSERT INTO t1 VALUES(11, 12) }
109 execsql { SELECT * FROM t1 }
110} {1 2 3 4 5 6 7 8 9 10 11 12}
111
112do_test wal-2.3 {
113 execsql { SELECT * FROM t1 } db2
114} {1 2 3 4 5 6 7 8 9 10}
115
116do_test wal-2.4 {
117 execsql { INSERT INTO t1 VALUES(13, 14) }
118 execsql { SELECT * FROM t1 }
119} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
120
121do_test wal-2.5 {
122 execsql { SELECT * FROM t1 } db2
123} {1 2 3 4 5 6 7 8 9 10}
124
125do_test wal-2.6 {
126 execsql { COMMIT; SELECT * FROM t1 } db2
127} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
128
129do_test wal-3.1 {
130 execsql { BEGIN; DELETE FROM t1 }
131 execsql { SELECT * FROM t1 }
132} {}
133do_test wal-3.2 {
134 execsql { SELECT * FROM t1 } db2
135} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
136do_test wal-3.3 {
137 execsql { ROLLBACK }
138 execsql { SELECT * FROM t1 }
139} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
140db2 close
141
dan74d6cd82010-04-24 18:44:05 +0000142#-------------------------------------------------------------------------
143# The following tests, wal-4.*, test that savepoints work with WAL
144# databases.
145#
dan7c246102010-04-12 19:00:29 +0000146do_test wal-4.1 {
147 execsql {
148 DELETE FROM t1;
149 BEGIN;
150 INSERT INTO t1 VALUES('a', 'b');
151 SAVEPOINT sp;
152 INSERT INTO t1 VALUES('c', 'd');
153 SELECT * FROM t1;
154 }
155} {a b c d}
156do_test wal-4.2 {
157 execsql {
158 ROLLBACK TO sp;
159 SELECT * FROM t1;
160 }
161} {a b}
162do_test wal-4.3 {
163 execsql {
164 COMMIT;
165 SELECT * FROM t1;
166 }
167} {a b}
168
dan4cd78b42010-04-26 16:57:10 +0000169do_test wal-4.4.1 {
dan74d6cd82010-04-24 18:44:05 +0000170 db close
171 sqlite3 db test.db
172 db func blob blob
173 list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
174} {{a b} 0}
dan4cd78b42010-04-26 16:57:10 +0000175do_test wal-4.4.2 {
dan74d6cd82010-04-24 18:44:05 +0000176 execsql { PRAGMA cache_size = 10 }
177 execsql {
178 CREATE TABLE t2(a, b);
179 INSERT INTO t2 VALUES(blob(400), blob(400));
180 SAVEPOINT tr;
181 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 2 */
182 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 4 */
183 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 8 */
184 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 16 */
185 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 32 */
186 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 2 */
187 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 4 */
188 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 8 */
189 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 16 */
190 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 32 */
191 SELECT count(*) FROM t2;
192 }
193} {32}
dan4cd78b42010-04-26 16:57:10 +0000194do_test wal-4.4.3 {
dan74d6cd82010-04-24 18:44:05 +0000195 execsql { ROLLBACK TO tr }
196} {}
dan4cd78b42010-04-26 16:57:10 +0000197do_test wal-4.4.4 {
dan74d6cd82010-04-24 18:44:05 +0000198 set logsize [file size test.db-wal]
199 execsql {
200 INSERT INTO t1 VALUES('x', 'y');
201 RELEASE tr;
202 }
203 expr { $logsize == [file size test.db-wal] }
204} {1}
dan4cd78b42010-04-26 16:57:10 +0000205do_test wal-4.4.5 {
dan74d6cd82010-04-24 18:44:05 +0000206 execsql { SELECT count(*) FROM t2 }
207} {1}
dan4cd78b42010-04-26 16:57:10 +0000208do_test wal-4.4.6 {
dan74d6cd82010-04-24 18:44:05 +0000209 file copy -force test.db test2.db
210 file copy -force test.db-wal test2.db-wal
211 sqlite3 db2 test2.db
212 execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2
213} {1 2}
dan4cd78b42010-04-26 16:57:10 +0000214do_test wal-4.4.7 {
dan74d6cd82010-04-24 18:44:05 +0000215 execsql { PRAGMA integrity_check } db2
216} {ok}
217db2 close
218
dan4cd78b42010-04-26 16:57:10 +0000219do_test wal-4.5.1 {
220 reopen_db
221 db func blob blob
222 execsql {
223 PRAGMA journal_mode = WAL;
224 CREATE TABLE t1(a, b);
225 INSERT INTO t1 VALUES('a', 'b');
226 }
227 sqlite3 db test.db
228 db func blob blob
229 list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
230} {{a b} 0}
231do_test wal-4.5.2 {
232 execsql { PRAGMA cache_size = 10 }
233 execsql {
234 CREATE TABLE t2(a, b);
235 BEGIN;
236 INSERT INTO t2 VALUES(blob(400), blob(400));
237 SAVEPOINT tr;
238 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 2 */
239 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 4 */
240 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 8 */
241 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 16 */
242 INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 32 */
243 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 2 */
244 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 4 */
245 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 8 */
246 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 16 */
247 INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 32 */
248 SELECT count(*) FROM t2;
249 }
250} {32}
251do_test wal-4.5.3 {
dan4cd78b42010-04-26 16:57:10 +0000252 execsql { ROLLBACK TO tr }
253} {}
254do_test wal-4.5.4 {
255 set logsize [file size test.db-wal]
dan4cd78b42010-04-26 16:57:10 +0000256 execsql {
257 INSERT INTO t1 VALUES('x', 'y');
258 RELEASE tr;
259 COMMIT;
260 }
261 expr { $logsize == [file size test.db-wal] }
262} {1}
263do_test wal-4.5.5 {
264 execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 }
265} {1 2}
266do_test wal-4.5.6 {
267 file copy -force test.db test2.db
268 file copy -force test.db-wal test2.db-wal
269 sqlite3 db2 test2.db
dan4cd78b42010-04-26 16:57:10 +0000270 execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2
271} {1 2}
272do_test wal-4.5.7 {
273 execsql { PRAGMA integrity_check } db2
274} {ok}
275db2 close
276
277
dan74d6cd82010-04-24 18:44:05 +0000278reopen_db
dan7c246102010-04-12 19:00:29 +0000279do_test wal-5.1 {
280 execsql {
281 CREATE TEMP TABLE t2(a, b);
282 INSERT INTO t2 VALUES(1, 2);
283 }
284} {}
285do_test wal-5.2 {
286 execsql {
287 BEGIN;
288 INSERT INTO t2 VALUES(3, 4);
289 SELECT * FROM t2;
290 }
291} {1 2 3 4}
292do_test wal-5.3 {
293 execsql {
294 ROLLBACK;
295 SELECT * FROM t2;
296 }
297} {1 2}
298do_test wal-5.4 {
299 execsql {
300 CREATE TEMP TABLE t3(x UNIQUE);
301 BEGIN;
302 INSERT INTO t2 VALUES(3, 4);
303 INSERT INTO t3 VALUES('abc');
304 }
305 catchsql { INSERT INTO t3 VALUES('abc') }
306} {1 {column x is not unique}}
307do_test wal-5.5 {
308 execsql {
309 COMMIT;
310 SELECT * FROM t2;
311 }
312} {1 2 3 4}
313db close
314
dan7c246102010-04-12 19:00:29 +0000315foreach sector {512 4096} {
316 sqlite3_simulate_device -sectorsize $sector
317 foreach pgsz {512 1024 2048 4096} {
318 file delete -force test.db test.db-wal
319 do_test wal-6.$sector.$pgsz.1 {
dane04dc882010-04-20 18:53:15 +0000320 sqlite3 db test.db -vfs devsym
dan7c246102010-04-12 19:00:29 +0000321 execsql "
dane04dc882010-04-20 18:53:15 +0000322 PRAGMA page_size = $pgsz;
323 PRAGMA journal_mode = wal;
dan7c246102010-04-12 19:00:29 +0000324 "
325 execsql "
326 CREATE TABLE t1(a, b);
327 INSERT INTO t1 VALUES(1, 2);
328 "
329 db close
330 file size test.db
331 } [expr $pgsz*2]
332
333 do_test wal-6.$sector.$pgsz.2 {
dan3de777f2010-04-17 12:31:37 +0000334 log_deleted test.db-wal
335 } {1}
dan7c246102010-04-12 19:00:29 +0000336 }
337}
338
339do_test wal-7.1 {
340 file delete -force test.db test.db-wal
341 sqlite3_wal db test.db
342 execsql {
343 PRAGMA page_size = 1024;
344 CREATE TABLE t1(a, b);
345 INSERT INTO t1 VALUES(1, 2);
346 }
dan7c246102010-04-12 19:00:29 +0000347 list [file size test.db] [file size test.db-wal]
dane04dc882010-04-20 18:53:15 +0000348} [list 1024 [log_file_size 3 1024]]
dan7c246102010-04-12 19:00:29 +0000349do_test wal-7.2 {
350 execsql { PRAGMA checkpoint }
351 list [file size test.db] [file size test.db-wal]
dan97a31352010-04-16 13:59:31 +0000352} [list 2048 [log_file_size 3 1024]]
dan7c246102010-04-12 19:00:29 +0000353
dan7c246102010-04-12 19:00:29 +0000354# Execute some transactions in auto-vacuum mode to test database file
355# truncation.
356#
danb9bf16b2010-04-14 11:23:30 +0000357do_test wal-8.1 {
dan7c246102010-04-12 19:00:29 +0000358 reopen_db
dane04dc882010-04-20 18:53:15 +0000359 catch { db close }
360 file delete -force test.db test.db-wal
361
362 sqlite3 db test.db
363 db function blob blob
dan7c246102010-04-12 19:00:29 +0000364 execsql {
365 PRAGMA auto_vacuum = 1;
dane04dc882010-04-20 18:53:15 +0000366 PRAGMA journal_mode = wal;
dan7c246102010-04-12 19:00:29 +0000367 PRAGMA auto_vacuum;
368 }
dane04dc882010-04-20 18:53:15 +0000369} {wal 1}
danb9bf16b2010-04-14 11:23:30 +0000370do_test wal-8.2 {
dan7c246102010-04-12 19:00:29 +0000371 execsql {
372 PRAGMA page_size = 1024;
373 CREATE TABLE t1(x);
dan67032392010-04-17 15:42:43 +0000374 INSERT INTO t1 VALUES(blob(900));
375 INSERT INTO t1 VALUES(blob(900));
376 INSERT INTO t1 SELECT blob(900) FROM t1; /* 4 */
377 INSERT INTO t1 SELECT blob(900) FROM t1; /* 8 */
378 INSERT INTO t1 SELECT blob(900) FROM t1; /* 16 */
379 INSERT INTO t1 SELECT blob(900) FROM t1; /* 32 */
380 INSERT INTO t1 SELECT blob(900) FROM t1; /* 64 */
dan7c246102010-04-12 19:00:29 +0000381 PRAGMA checkpoint;
382 }
383 file size test.db
dan80a15262010-04-13 11:45:31 +0000384} [expr 68*1024]
danb9bf16b2010-04-14 11:23:30 +0000385do_test wal-8.3 {
dan7c246102010-04-12 19:00:29 +0000386 execsql {
387 DELETE FROM t1 WHERE rowid<54;
danf05c86d2010-04-13 11:56:03 +0000388 PRAGMA checkpoint;
dan7c246102010-04-12 19:00:29 +0000389 }
390 file size test.db
391} [expr 14*1024]
392
393# Run some "warm-body" tests to ensure that log-summary files with more
394# than 256 entries (log summaries that contain index blocks) work Ok.
395#
danb9bf16b2010-04-14 11:23:30 +0000396do_test wal-9.1 {
dan7c246102010-04-12 19:00:29 +0000397 reopen_db
398 execsql {
dan7c246102010-04-12 19:00:29 +0000399 CREATE TABLE t1(x PRIMARY KEY);
dan67032392010-04-17 15:42:43 +0000400 INSERT INTO t1 VALUES(blob(900));
401 INSERT INTO t1 VALUES(blob(900));
402 INSERT INTO t1 SELECT blob(900) FROM t1; /* 4 */
403 INSERT INTO t1 SELECT blob(900) FROM t1; /* 8 */
404 INSERT INTO t1 SELECT blob(900) FROM t1; /* 16 */
405 INSERT INTO t1 SELECT blob(900) FROM t1; /* 32 */
406 INSERT INTO t1 SELECT blob(900) FROM t1; /* 64 */
407 INSERT INTO t1 SELECT blob(900) FROM t1; /* 128 */
408 INSERT INTO t1 SELECT blob(900) FROM t1; /* 256 */
dan7c246102010-04-12 19:00:29 +0000409 }
410 file size test.db
dane04dc882010-04-20 18:53:15 +0000411} 1024
danb9bf16b2010-04-14 11:23:30 +0000412do_test wal-9.2 {
dan7c246102010-04-12 19:00:29 +0000413 sqlite3_wal db2 test.db
414 execsql {PRAGMA integrity_check } db2
415} {ok}
416
danb9bf16b2010-04-14 11:23:30 +0000417do_test wal-9.3 {
dan7c246102010-04-12 19:00:29 +0000418 file delete -force test2.db test2.db-wal
419 file copy test.db test2.db
420 file copy test.db-wal test2.db-wal
421 sqlite3_wal db3 test2.db
422 execsql {PRAGMA integrity_check } db3
423} {ok}
424db3 close
425
danb9bf16b2010-04-14 11:23:30 +0000426do_test wal-9.4 {
dan7c246102010-04-12 19:00:29 +0000427 execsql { PRAGMA checkpoint }
428 db2 close
429 sqlite3_wal db2 test.db
430 execsql {PRAGMA integrity_check } db2
431} {ok}
432
dan80a15262010-04-13 11:45:31 +0000433foreach handle {db db2 db3} { catch { $handle close } }
434unset handle
435
danb9bf16b2010-04-14 11:23:30 +0000436#-------------------------------------------------------------------------
437# The following block of tests - wal-10.* - test that the WAL locking
dane264d982010-04-14 18:06:50 +0000438# scheme works in simple cases. This block of tests is run twice. Once
439# using multiple connections in the address space of the current process,
440# and once with all connections except one running in external processes.
danb9bf16b2010-04-14 11:23:30 +0000441#
dane264d982010-04-14 18:06:50 +0000442foreach code [list {
443 set ::code2_chan [launch_testfixture]
444 set ::code3_chan [launch_testfixture]
445 proc code2 {tcl} { testfixture $::code2_chan $tcl }
446 proc code3 {tcl} { testfixture $::code3_chan $tcl }
447 set tn 1
448} {
449 proc code2 {tcl} { uplevel #0 $tcl }
450 proc code3 {tcl} { uplevel #0 $tcl }
451 set tn 2
452}] {
danb9bf16b2010-04-14 11:23:30 +0000453
dane264d982010-04-14 18:06:50 +0000454 eval $code
455 reopen_db
456
457 # Open connections [db2] and [db3]. Depending on which iteration this
458 # is, the connections may be created in this interpreter, or in
459 # interpreters running in other OS processes. As such, the [db2] and [db3]
460 # commands should only be accessed within [code2] and [code3] blocks,
461 # respectively.
462 #
463 code2 { sqlite3 db2 test.db ; db2 eval { PRAGMA journal_mode = WAL } }
464 code3 { sqlite3 db3 test.db ; db3 eval { PRAGMA journal_mode = WAL } }
465
466 # Shorthand commands. Execute SQL using database connection [db2] or
467 # [db3]. Return the results.
468 #
469 proc sql2 {sql} { code2 [list db2 eval $sql] }
470 proc sql3 {sql} { code3 [list db3 eval $sql] }
471
472 # Initialize the database schema and contents.
473 #
474 do_test wal-10.$tn.1 {
475 execsql {
476 CREATE TABLE t1(a, b);
477 INSERT INTO t1 VALUES(1, 2);
danb9bf16b2010-04-14 11:23:30 +0000478 SELECT * FROM t1;
dane264d982010-04-14 18:06:50 +0000479 }
480 } {1 2}
danb9bf16b2010-04-14 11:23:30 +0000481
dane264d982010-04-14 18:06:50 +0000482 # Open a transaction and write to the database using [db]. Check that [db2]
483 # is still able to read the snapshot before the transaction was opened.
484 #
485 do_test wal-10.$tn.2 {
486 execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); }
487 sql2 {SELECT * FROM t1}
488 } {1 2}
489
490 # Have [db] commit the transaction. Check that [db2] is now seeing the
491 # new, updated snapshot.
492 #
493 do_test wal-10.$tn.3 {
494 execsql { COMMIT }
495 sql2 {SELECT * FROM t1}
496 } {1 2 3 4}
497
498 # Have [db2] open a read transaction. Then write to the db via [db]. Check
499 # that [db2] is still seeing the original snapshot. Then read with [db3].
500 # [db3] should see the newly committed data.
501 #
502 do_test wal-10.$tn.4 {
503 sql2 { BEGIN ; SELECT * FROM t1}
504 } {1 2 3 4}
505 do_test wal-10.$tn.5 {
506 execsql { INSERT INTO t1 VALUES(5, 6); }
507 sql2 {SELECT * FROM t1}
508 } {1 2 3 4}
509 do_test wal-10.$tn.6 {
510 sql3 {SELECT * FROM t1}
511 } {1 2 3 4 5 6}
512 do_test wal-10.$tn.7 {
513 sql2 COMMIT
514 } {}
515
516 # Have [db2] open a write transaction. Then attempt to write to the
517 # database via [db]. This should fail (writer lock cannot be obtained).
518 #
519 # Then open a read-transaction with [db]. Commit the [db2] transaction
520 # to disk. Verify that [db] still cannot write to the database (because
521 # it is reading an old snapshot).
522 #
523 # Close the current [db] transaction. Open a new one. [db] can now write
524 # to the database (as it is not locked and [db] is reading the latest
525 # snapshot).
526 #
527 do_test wal-10.$tn.7 {
528 sql2 { BEGIN; INSERT INTO t1 VALUES(7, 8) ; }
529 catchsql { INSERT INTO t1 VALUES(9, 10) }
530 } {1 {database is locked}}
531 do_test wal-10.$tn.8 {
532 execsql { BEGIN ; SELECT * FROM t1 }
533 } {1 2 3 4 5 6}
534 do_test wal-10.$tn.9 {
535 sql2 COMMIT
536 catchsql { INSERT INTO t1 VALUES(9, 10) }
537 } {1 {database is locked}}
538 do_test wal-10.$tn.10 {
539 execsql { COMMIT; BEGIN; INSERT INTO t1 VALUES(9, 10); COMMIT; }
540 execsql { SELECT * FROM t1 }
541 } {1 2 3 4 5 6 7 8 9 10}
542
543 # Open a read transaction with [db2]. Check that this prevents [db] from
544 # checkpointing the database. But not from writing to it.
545 #
546 do_test wal-10.$tn.11 {
547 sql2 { BEGIN; SELECT * FROM t1 }
548 } {1 2 3 4 5 6 7 8 9 10}
549 do_test wal-10.$tn.12 {
550 catchsql { PRAGMA checkpoint }
551 } {1 {database is locked}}
552 do_test wal-10.$tn.13 {
553 execsql { INSERT INTO t1 VALUES(11, 12) }
554 sql2 {SELECT * FROM t1}
555 } {1 2 3 4 5 6 7 8 9 10}
556
557 # Connection [db2] is holding a lock on a snapshot, preventing [db] from
558 # checkpointing the database. Add a busy-handler to [db]. If [db2] completes
559 # its transaction from within the busy-handler, [db] is able to complete
560 # the checkpoint operation.
561 #
562 proc busyhandler x {
563 if {$x==4} { sql2 COMMIT }
564 if {$x<5} { return 0 }
565 return 1
danb9bf16b2010-04-14 11:23:30 +0000566 }
dane264d982010-04-14 18:06:50 +0000567 db busy busyhandler
568 do_test wal-10.$tn.14 {
569 execsql { PRAGMA checkpoint }
570 } {}
danb9bf16b2010-04-14 11:23:30 +0000571
dane264d982010-04-14 18:06:50 +0000572 # Similar to the test above. Except this time, a new read transaction is
573 # started (db3) while the checkpointer is waiting for an old one (db2) to
574 # finish. The checkpointer can finish, but any subsequent write operations
575 # must wait until after db3 has closed the read transaction, as db3 is a
576 # "region D" writer.
577 #
578 db busy {}
579 do_test wal-10.$tn.15 {
580 sql2 { BEGIN; SELECT * FROM t1; }
581 } {1 2 3 4 5 6 7 8 9 10 11 12}
582 do_test wal-10.$tn.16 {
583 catchsql { PRAGMA checkpoint }
584 } {1 {database is locked}}
585 proc busyhandler x {
586 if {$x==3} { sql3 { BEGIN; SELECT * FROM t1 } }
587 if {$x==4} { sql2 COMMIT }
588 if {$x<5} { return 0 }
589 return 1
590 }
591 db busy busyhandler
dan49320f82010-04-14 18:50:08 +0000592 do_test wal-10.$tn.17 {
dane264d982010-04-14 18:06:50 +0000593 execsql { PRAGMA checkpoint }
594 } {}
dan49320f82010-04-14 18:50:08 +0000595 do_test wal-10.$tn.18 {
dane264d982010-04-14 18:06:50 +0000596 sql3 { SELECT * FROM t1 }
597 } {1 2 3 4 5 6 7 8 9 10 11 12}
dan49320f82010-04-14 18:50:08 +0000598 do_test wal-10.$tn.19 {
dane264d982010-04-14 18:06:50 +0000599 catchsql { INSERT INTO t1 VALUES(13, 14) }
600 } {1 {database is locked}}
dan49320f82010-04-14 18:50:08 +0000601 do_test wal-10.$tn.20 {
dane264d982010-04-14 18:06:50 +0000602 execsql { SELECT * FROM t1 }
603 } {1 2 3 4 5 6 7 8 9 10 11 12}
dan49320f82010-04-14 18:50:08 +0000604 do_test wal-10.$tn.21 {
dane264d982010-04-14 18:06:50 +0000605 sql3 COMMIT
606 } {}
dan49320f82010-04-14 18:50:08 +0000607 do_test wal-10.$tn.22 {
dane264d982010-04-14 18:06:50 +0000608 execsql { INSERT INTO t1 VALUES(13, 14) }
609 execsql { SELECT * FROM t1 }
610 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
danb9bf16b2010-04-14 11:23:30 +0000611
dan49320f82010-04-14 18:50:08 +0000612 # Set [db3] up as a "region D" reader again. Then upgrade it to a writer
613 # and back down to a reader. Then, check that a checkpoint is not possible
614 # (as [db3] still has a snapshot locked).
615 #
616 do_test wal-10.$tn.23 {
617 execsql { PRAGMA checkpoint }
618 } {}
619 do_test wal-10.$tn.24 {
620 sql2 { BEGIN; SELECT * FROM t1; }
621 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
622 do_test wal-10.$tn.25 {
623 execsql { PRAGMA checkpoint }
624 } {}
625 do_test wal-10.$tn.26 {
626 catchsql { INSERT INTO t1 VALUES(15, 16) }
627 } {1 {database is locked}}
628 do_test wal-10.$tn.27 {
629 sql3 { INSERT INTO t1 VALUES(15, 16) }
630 } {}
631 do_test wal-10.$tn.28 {
632 code3 {
633 set ::STMT [sqlite3_prepare db3 "SELECT * FROM t1" -1 TAIL]
634 sqlite3_step $::STMT
635 }
636 sql3 COMMIT
637 execsql { SELECT * FROM t1 }
638 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
639 db busy {}
640 do_test wal-10.$tn.29 {
641 execsql { INSERT INTO t1 VALUES(17, 18) }
642 catchsql { PRAGMA checkpoint }
643 } {1 {database is locked}}
644 do_test wal-10.$tn.30 {
645 code3 { sqlite3_finalize $::STMT }
646 execsql { PRAGMA checkpoint }
647 } {}
648
649 # At one point, if a reader failed to upgrade to a writer because it
650 # was reading an old snapshot, the write-locks were not being released.
651 # Test that this bug has been fixed.
652 #
653 do_test wal-10.$tn.31 {
654 execsql { BEGIN ; SELECT * FROM t1 }
655 sql2 { INSERT INTO t1 VALUES(19, 20) }
656 catchsql { INSERT INTO t1 VALUES(21, 22) }
657 } {1 {database is locked}}
658 do_test wal-10.$tn.32 {
659 # This statement would fail when the bug was present.
660 sql2 { INSERT INTO t1 VALUES(21, 22) }
661 } {}
662 do_test wal-10.$tn.33 {
663 execsql { SELECT * FROM t1 ; COMMIT }
664 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18}
665 do_test wal-10.$tn.34 {
666 execsql { SELECT * FROM t1 }
667 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22}
668
dan8b348af2010-04-27 18:43:16 +0000669 # Test that if a checkpointer cannot obtain the required locks, it
670 # releases all locks before returning a busy error.
671 #
672 do_test wal-10.$tn.35 {
673 execsql {
674 DELETE FROM t1;
675 INSERT INTO t1 VALUES('a', 'b');
676 INSERT INTO t1 VALUES('c', 'd');
677 }
678 sql2 {
679 BEGIN;
680 SELECT * FROM t1;
681 }
682 } {a b c d}
683 proc busyhandler x { return 1 }
684 db busy busyhandler
685 do_test wal-10.$tn.36 {
686 catchsql { PRAGMA checkpoint }
687 } {1 {database is locked}}
688 do_test wal-10.$tn.36 {
689 sql3 { INSERT INTO t1 VALUES('e', 'f') }
690 sql2 { SELECT * FROM t1 }
691 } {a b c d}
692 do_test wal-10.$tn.37 {
693 sql2 COMMIT
694 execsql { PRAGMA checkpoint }
695 } {}
696
dane264d982010-04-14 18:06:50 +0000697 catch { db close }
698 catch { code2 { db2 close } }
699 catch { code3 { db3 close } }
700 catch { close $::code2_chan }
701 catch { close $::code3_chan }
702}
703
dan4cc6fb62010-04-15 16:45:34 +0000704#-------------------------------------------------------------------------
705# This block of tests, wal-11.*, test that nothing goes terribly wrong
706# if frames must be written to the log file before a transaction is
707# committed (in order to free up memory).
708#
709do_test wal-11.1 {
710 reopen_db
711 execsql {
712 PRAGMA cache_size = 10;
713 PRAGMA page_size = 1024;
714 CREATE TABLE t1(x PRIMARY KEY);
715 }
716 list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
dane04dc882010-04-20 18:53:15 +0000717} {1 3}
dan4cc6fb62010-04-15 16:45:34 +0000718do_test wal-11.2 {
719 execsql { PRAGMA checkpoint }
dan97a31352010-04-16 13:59:31 +0000720 list [expr [file size test.db]/1024] [file size test.db-wal]
721} [list 3 [log_file_size 3 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000722do_test wal-11.3 {
dan67032392010-04-17 15:42:43 +0000723 execsql { INSERT INTO t1 VALUES( blob(900) ) }
dan97a31352010-04-16 13:59:31 +0000724 list [expr [file size test.db]/1024] [file size test.db-wal]
725} [list 3 [log_file_size 4 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000726
727do_test wal-11.4 {
728 execsql {
729 BEGIN;
dan67032392010-04-17 15:42:43 +0000730 INSERT INTO t1 SELECT blob(900) FROM t1; -- 2
731 INSERT INTO t1 SELECT blob(900) FROM t1; -- 4
732 INSERT INTO t1 SELECT blob(900) FROM t1; -- 8
733 INSERT INTO t1 SELECT blob(900) FROM t1; -- 16
dan4cc6fb62010-04-15 16:45:34 +0000734 }
dan97a31352010-04-16 13:59:31 +0000735 list [expr [file size test.db]/1024] [file size test.db-wal]
dan67032392010-04-17 15:42:43 +0000736} [list 3 [log_file_size 32 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000737do_test wal-11.5 {
738 execsql {
739 SELECT count(*) FROM t1;
740 PRAGMA integrity_check;
741 }
742} {16 ok}
743do_test wal-11.6 {
744 execsql COMMIT
dan97a31352010-04-16 13:59:31 +0000745 list [expr [file size test.db]/1024] [file size test.db-wal]
dan67032392010-04-17 15:42:43 +0000746} [list 3 [log_file_size 41 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000747do_test wal-11.7 {
748 execsql {
749 SELECT count(*) FROM t1;
750 PRAGMA integrity_check;
751 }
752} {16 ok}
753do_test wal-11.8 {
754 execsql { PRAGMA checkpoint }
dan97a31352010-04-16 13:59:31 +0000755 list [expr [file size test.db]/1024] [file size test.db-wal]
dan67032392010-04-17 15:42:43 +0000756} [list 37 [log_file_size 41 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000757do_test wal-11.9 {
758 db close
dan3de777f2010-04-17 12:31:37 +0000759 list [expr [file size test.db]/1024] [log_deleted test.db-wal]
760} {37 1}
dan67032392010-04-17 15:42:43 +0000761sqlite3_wal db test.db
dan4cc6fb62010-04-15 16:45:34 +0000762do_test wal-11.10 {
763 execsql {
764 PRAGMA cache_size = 10;
765 BEGIN;
dan67032392010-04-17 15:42:43 +0000766 INSERT INTO t1 SELECT blob(900) FROM t1; -- 32
dan4cc6fb62010-04-15 16:45:34 +0000767 SELECT count(*) FROM t1;
768 }
dan97a31352010-04-16 13:59:31 +0000769 list [expr [file size test.db]/1024] [file size test.db-wal]
dan4cd78b42010-04-26 16:57:10 +0000770} [list 37 [log_file_size 37 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000771do_test wal-11.11 {
772 execsql {
773 SELECT count(*) FROM t1;
774 ROLLBACK;
775 SELECT count(*) FROM t1;
776 }
777} {32 16}
778do_test wal-11.12 {
dan97a31352010-04-16 13:59:31 +0000779 list [expr [file size test.db]/1024] [file size test.db-wal]
dan4cd78b42010-04-26 16:57:10 +0000780} [list 37 [log_file_size 37 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000781do_test wal-11.13 {
782 execsql {
dan67032392010-04-17 15:42:43 +0000783 INSERT INTO t1 VALUES( blob(900) );
dan4cc6fb62010-04-15 16:45:34 +0000784 SELECT count(*) FROM t1;
785 PRAGMA integrity_check;
786 }
787} {17 ok}
788do_test wal-11.14 {
dan97a31352010-04-16 13:59:31 +0000789 list [expr [file size test.db]/1024] [file size test.db-wal]
dan4cd78b42010-04-26 16:57:10 +0000790} [list 37 [log_file_size 37 1024]]
dan4cc6fb62010-04-15 16:45:34 +0000791
792
dan4a4b01d2010-04-16 11:30:18 +0000793#-------------------------------------------------------------------------
dan97a31352010-04-16 13:59:31 +0000794# This block of tests, wal-12.*, tests the fix for a problem that
795# could occur if a log that is a prefix of an older log is written
796# into a reused log file.
dan4a4b01d2010-04-16 11:30:18 +0000797#
798reopen_db
799do_test wal-12.1 {
800 execsql {
801 PRAGMA page_size = 1024;
802 CREATE TABLE t1(x, y);
803 CREATE TABLE t2(x, y);
804 INSERT INTO t1 VALUES('A', 1);
805 }
dan97a31352010-04-16 13:59:31 +0000806 list [expr [file size test.db]/1024] [file size test.db-wal]
dane04dc882010-04-20 18:53:15 +0000807} [list 1 [log_file_size 5 1024]]
dan4a4b01d2010-04-16 11:30:18 +0000808do_test wal-12.2 {
809 db close
dane04dc882010-04-20 18:53:15 +0000810 sqlite3 db test.db
dan4a4b01d2010-04-16 11:30:18 +0000811 execsql {
dane04dc882010-04-20 18:53:15 +0000812 PRAGMA synchronous = normal;
dan4a4b01d2010-04-16 11:30:18 +0000813 UPDATE t1 SET y = 0 WHERE x = 'A';
814 }
815 list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
816} {3 1}
817do_test wal-12.3 {
818 execsql { INSERT INTO t2 VALUES('B', 1) }
819 list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
820} {3 2}
dan4a4b01d2010-04-16 11:30:18 +0000821do_test wal-12.4 {
822 file copy -force test.db test2.db
823 file copy -force test.db-wal test2.db-wal
824 sqlite3_wal db2 test2.db
dan4a4b01d2010-04-16 11:30:18 +0000825 execsql { SELECT * FROM t2 } db2
826} {B 1}
827db2 close
dan4a4b01d2010-04-16 11:30:18 +0000828do_test wal-12.5 {
829 execsql {
830 PRAGMA checkpoint;
831 UPDATE t2 SET y = 2 WHERE x = 'B';
832 PRAGMA checkpoint;
833 UPDATE t1 SET y = 1 WHERE x = 'A';
834 PRAGMA checkpoint;
835 UPDATE t1 SET y = 0 WHERE x = 'A';
836 SELECT * FROM t2;
837 }
838} {B 2}
dance4f05f2010-04-22 19:14:13 +0000839do_test wal-12.6 {
dan4a4b01d2010-04-16 11:30:18 +0000840 file copy -force test.db test2.db
841 file copy -force test.db-wal test2.db-wal
842 sqlite3_wal db2 test2.db
843 execsql { SELECT * FROM t2 } db2
844} {B 2}
845db2 close
dance4f05f2010-04-22 19:14:13 +0000846db close
847
848#-------------------------------------------------------------------------
849# Test large log summaries.
850#
dan31f98fc2010-04-27 05:42:32 +0000851set sqlite_walsummary_mmap_incr 64
852do_test wal-13.1.1 {
dance4f05f2010-04-22 19:14:13 +0000853 list [file exists test.db] [file exists test.db-wal]
854} {1 0}
dan31f98fc2010-04-27 05:42:32 +0000855do_test wal-13.1.2 {
dance4f05f2010-04-22 19:14:13 +0000856 set fd [open test.db-wal w]
857 seek $fd [expr 200*1024*1024]
858 puts $fd ""
859 close $fd
860 sqlite3 db test.db
861 execsql { SELECT * FROM t2 }
862} {B 2}
dan31f98fc2010-04-27 05:42:32 +0000863do_test wal-13.1.3 {
dance4f05f2010-04-22 19:14:13 +0000864 db close
865 file exists test.db-wal
866} {0}
dan31f98fc2010-04-27 05:42:32 +0000867do_test wal-13.1.4 {
dance4f05f2010-04-22 19:14:13 +0000868 sqlite3 db test.db
869 execsql { SELECT count(*) FROM t2 }
870} {1}
dan31f98fc2010-04-27 05:42:32 +0000871do_test wal-13.1.5 {
872 for {set i 0} {$i < 6} {incr i} {
dance4f05f2010-04-22 19:14:13 +0000873 execsql { INSERT INTO t2 SELECT randomblob(400), randomblob(400) FROM t2 }
874 }
875 execsql { SELECT count(*) FROM t2 }
dan31f98fc2010-04-27 05:42:32 +0000876} [expr int(pow(2, 6))]
877do_test wal-13.1.6 {
878 file size test.db-wal
879} [log_file_size 80 1024]
dance4f05f2010-04-22 19:14:13 +0000880
dan31f98fc2010-04-27 05:42:32 +0000881foreach code [list {
882 set tn 2
883 proc buddy {tcl} { uplevel #0 $tcl }
884} {
885 set tn 3
886 set ::buddy [launch_testfixture]
887 proc buddy {tcl} { testfixture $::buddy $tcl }
888}] {
889
890 eval $code
891 reopen_db
892
893 do_test wal-13.$tn.0 {
894 buddy { sqlite3 db2 test.db }
895 execsql {
896 PRAGMA journal_mode = WAL;
897 CREATE TABLE t1(x);
898 INSERT INTO t1 SELECT randomblob(400);
899 }
900 execsql { SELECT count(*) FROM t1 }
901 } {1}
902
903 for {set ii 1} {$ii<16} {incr ii} {
904 do_test wal-13.$tn.$ii.a {
905 buddy { db2 eval { INSERT INTO t1 SELECT randomblob(400) FROM t1 } }
906 buddy { db2 eval { SELECT count(*) FROM t1 } }
907 } [expr (1<<$ii)]
908 do_test wal-13.$tn.$ii.b {
909 db eval { SELECT count(*) FROM t1 }
910 } [expr (1<<$ii)]
911 do_test wal-13.$tn.$ii.c {
912 db eval { SELECT count(*) FROM t1 }
913 } [expr (1<<$ii)]
914 }
915
916 catch { db2 close }
917 catch { close $::buddy }
918 db close
919}
dan4a4b01d2010-04-16 11:30:18 +0000920
dan31c03902010-04-29 14:51:33 +0000921#-------------------------------------------------------------------------
922# Check a fun corruption case has been fixed.
923#
924# The problem was that after performing a checkpoint using a connection
925# that had an out-of-date pager-cache, the next time the connection was
926# used it did not realize the cache was out-of-date and proceeded to
927# operate with an inconsistent cache. Leading to corruption.
928#
929
930catch { db close }
931catch { db2 close }
932catch { db3 close }
933file delete -force test.db test.db-wal
934sqlite3 db test.db
935sqlite3 db2 test.db
936
937do_test wal-14 {
938 execsql {
939 PRAGMA journal_mode = WAL;
940 CREATE TABLE t1(a PRIMARY KEY, b);
941 INSERT INTO t1 VALUES(randomblob(10), randomblob(100));
942 INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
943 INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
944 INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
945 }
946
947 db2 eval {
948 INSERT INTO t1 SELECT randomblob(10), randomblob(100);
949 INSERT INTO t1 SELECT randomblob(10), randomblob(100);
950 INSERT INTO t1 SELECT randomblob(10), randomblob(100);
951 INSERT INTO t1 SELECT randomblob(10), randomblob(100);
952 }
953
954 # After executing the "PRAGMA checkpoint", connection [db] was being
955 # left with an inconsistent cache. Running the CREATE INDEX statement
956 # in this state led to database corruption.
957 catchsql {
958 PRAGMA checkpoint;
959 CREATE INDEX i1 on t1(b);
960 }
961
962 db2 eval { PRAGMA integrity_check }
963} {ok}
964
965
dan7c246102010-04-12 19:00:29 +0000966finish_test
967