3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
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.
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.
16 set testdir [file dirname $argv0]
17 source $testdir/tester.tcl
18 source $testdir/malloc_common.tcl
19 source $testdir/lock_common.tcl
21 ifcapable !wal {finish_test ; return }
23 #-------------------------------------------------------------------------
24 # This test case, walfault-1-*, simulates faults while executing a
26 # PRAGMA journal_mode = WAL;
28 # statement immediately after creating a new database.
30 do_test walfault-1-pre-1 {
31 faultsim_delete_and_reopen
32 faultsim_save_and_close
34 do_faultsim_test walfault-1 -prep {
35 faultsim_restore_and_reopen
37 db eval { PRAGMA main.journal_mode = WAL }
40 faultsim_test_result {0 wal}
42 # Test that the connection that encountered an error as part of
43 # "PRAGMA journal_mode = WAL" and a new connection use the same
44 # journal mode when accessing the database.
46 # If "PRAGMA journal_mode" is executed immediately, connection [db] (the
47 # one that hit the error in journal_mode="WAL") might return "wal" even
48 # if it failed to switch the database to WAL mode. This is not considered
49 # a problem. When it tries to read the database, connection [db] correctly
50 # recognizes that it is a rollback database and switches back to a
51 # rollback compatible journal mode.
53 if {[permutation] != "inmemory_journal"} {
54 set jm [db one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}]
56 set jm2 [db2 one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}]
59 if { $jm!=$jm2 } { error "Journal modes do not match: $jm $jm2" }
60 if { $testrc==0 && $jm!="wal" } { error "Journal mode is not WAL" }
64 #--------------------------------------------------------------------------
65 # Test case walfault-2-* tests fault injection during recovery of a
66 # short WAL file (a dozen frames or thereabouts).
68 do_test walfault-2-pre-1 {
71 PRAGMA journal_mode = WAL;
73 CREATE TABLE x(y, z, UNIQUE(y, z));
74 INSERT INTO x VALUES(randomblob(100), randomblob(100));
76 PRAGMA wal_checkpoint;
78 INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x;
79 INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x;
80 INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x;
83 SELECT count(*) FROM x
86 do_test walfault-2-pre-2 {
87 faultsim_save_and_close
88 faultsim_restore_and_reopen
89 execsql { SELECT count(*) FROM x }
91 do_faultsim_test walfault-2 -prep {
92 faultsim_restore_and_reopen
94 execsql { SELECT count(*) FROM x }
96 faultsim_test_result {0 8}
97 faultsim_integrity_check
100 #--------------------------------------------------------------------------
101 # Test fault injection while writing and checkpointing a small WAL file.
103 do_test walfault-3-pre-1 {
106 PRAGMA auto_vacuum = 1;
107 PRAGMA journal_mode = WAL;
108 CREATE TABLE abc(a PRIMARY KEY);
109 INSERT INTO abc VALUES(randomblob(1500));
112 faultsim_save_and_close
114 do_faultsim_test walfault-3 -prep {
115 faultsim_restore_and_reopen
119 PRAGMA wal_checkpoint;
123 faultsim_test_result {0 {}}
126 #--------------------------------------------------------------------------
128 if {[permutation] != "inmemory_journal"} {
129 faultsim_delete_and_reopen
130 faultsim_save_and_close
131 do_faultsim_test walfault-4 -prep {
132 faultsim_restore_and_reopen
135 PRAGMA auto_vacuum = 0;
136 PRAGMA journal_mode = WAL;
137 CREATE TABLE t1(a PRIMARY KEY, b);
138 INSERT INTO t1 VALUES('a', 'b');
139 PRAGMA wal_checkpoint;
143 # Update: The following changed from {0 {wal 0 7 7 a b}} as a result
144 # of PSOW being set by default.
145 faultsim_test_result {0 {wal 0 5 5 a b}}
146 faultsim_integrity_check
150 #--------------------------------------------------------------------------
152 do_test walfault-5-pre-1 {
153 faultsim_delete_and_reopen
155 PRAGMA page_size = 512;
156 PRAGMA journal_mode = WAL;
158 faultsim_save_and_close
160 do_faultsim_test walfault-5 -faults shmerr* -prep {
161 faultsim_restore_and_reopen
162 execsql { PRAGMA wal_autocheckpoint = 0 }
163 shmfault filter xShmMap
168 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
169 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
170 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
171 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */
172 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */
173 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */
174 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */
175 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */
176 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */
177 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */
178 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */
179 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */
180 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */
181 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
182 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
184 SELECT count(*) FROM t1;
187 faultsim_test_result {0 16384}
188 faultsim_integrity_check
191 #--------------------------------------------------------------------------
193 do_test walfault-6-pre-1 {
194 faultsim_delete_and_reopen
196 PRAGMA page_size = 512;
197 PRAGMA journal_mode = WAL;
198 PRAGMA wal_autocheckpoint = 0;
201 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
202 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
203 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
204 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */
205 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */
206 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */
207 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */
208 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */
209 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */
210 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */
211 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */
212 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */
213 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */
214 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
215 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
218 faultsim_save_and_close
220 do_faultsim_test walfault-6 -faults shmerr* -prep {
221 faultsim_restore_and_reopen
222 shmfault filter xShmMap
224 execsql { SELECT count(*) FROM t1 }
226 faultsim_test_result {0 16384}
227 faultsim_integrity_check
228 set n [db one {SELECT count(*) FROM t1}]
229 if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" }
232 #--------------------------------------------------------------------------
234 do_test walfault-7-pre-1 {
235 faultsim_delete_and_reopen
237 PRAGMA page_size = 512;
238 PRAGMA journal_mode = WAL;
239 PRAGMA wal_autocheckpoint = 0;
242 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
243 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
244 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
247 faultsim_save_and_close
249 do_faultsim_test walfault-7 -prep {
250 faultsim_restore_and_reopen
252 execsql { SELECT count(*) FROM t1 }
254 faultsim_test_result {0 4}
255 set n [db one {SELECT count(*) FROM t1}]
256 if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" }
259 #--------------------------------------------------------------------------
261 do_test walfault-8-pre-1 {
262 faultsim_delete_and_reopen
264 PRAGMA journal_mode = WAL;
265 CREATE TABLE abc(a PRIMARY KEY);
266 INSERT INTO abc VALUES(randomblob(900));
268 faultsim_save_and_close
270 do_faultsim_test walfault-8 -prep {
271 faultsim_restore_and_reopen
272 execsql { PRAGMA cache_size = 10 }
276 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
277 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
278 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
279 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
281 SELECT count(*) FROM abc;
284 faultsim_test_result {0 1}
286 faultsim_integrity_check
287 catch { db eval ROLLBACK }
288 faultsim_integrity_check
290 set n [db one {SELECT count(*) FROM abc}]
291 if {$n != 1} { error "Incorrect number of rows: $n" }
294 #--------------------------------------------------------------------------
296 do_test walfault-9-pre-1 {
297 faultsim_delete_and_reopen
299 PRAGMA journal_mode = WAL;
300 CREATE TABLE abc(a PRIMARY KEY);
301 INSERT INTO abc VALUES(randomblob(900));
303 faultsim_save_and_close
305 do_faultsim_test walfault-9 -prep {
306 #if {$iFail<73} { set iFail 73 }
307 #if {$iFail>73} { exit }
309 faultsim_restore_and_reopen
310 execsql { PRAGMA cache_size = 10 }
314 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
316 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
317 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
318 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
321 SELECT count(*) FROM abc;
324 faultsim_test_result {0 2}
325 faultsim_integrity_check
327 catch { db eval { ROLLBACK TO spoint } }
328 catch { db eval { COMMIT } }
329 set n [db one {SELECT count(*) FROM abc}]
330 if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" }
333 do_test walfault-10-pre1 {
334 faultsim_delete_and_reopen
336 PRAGMA journal_mode = WAL;
337 PRAGMA wal_autocheckpoint = 0;
338 CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB);
339 CREATE INDEX zzzz ON z(zzz);
340 INSERT INTO z VALUES(NULL, randomblob(800));
341 INSERT INTO z VALUES(NULL, randomblob(800));
342 INSERT INTO z SELECT NULL, randomblob(800) FROM z;
343 INSERT INTO z SELECT NULL, randomblob(800) FROM z;
344 INSERT INTO z SELECT NULL, randomblob(800) FROM z;
345 INSERT INTO z SELECT NULL, randomblob(800) FROM z;
346 INSERT INTO z SELECT NULL, randomblob(800) FROM z;
348 faultsim_save_and_close
350 do_faultsim_test walfault-10 -prep {
351 faultsim_restore_and_reopen
353 PRAGMA cache_size = 10;
355 UPDATE z SET zzz = randomblob(799);
358 set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1]
361 execsql { INSERT INTO z VALUES(NULL, NULL) }
363 sqlite3_finalize $::stmt
364 faultsim_integrity_check
366 faultsim_test_result {0 {}}
367 catch { db eval { ROLLBACK } }
368 faultsim_integrity_check
370 set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}]
371 if {$n != "64 51200"} { error "Incorrect data: $n" }
374 #--------------------------------------------------------------------------
375 # Test fault injection while checkpointing a large WAL file, if the
376 # checkpoint is the first operation run after opening the database.
377 # This means that some of the required wal-index pages are mapped as part of
378 # the checkpoint process, which means there are a few more opportunities
381 # To speed this up, IO errors are only simulated within xShmMap() calls.
383 do_test walfault-11-pre-1 {
386 PRAGMA journal_mode = WAL;
387 PRAGMA wal_autocheckpoint = 0;
389 CREATE TABLE abc(a PRIMARY KEY);
390 INSERT INTO abc VALUES(randomblob(1500));
391 INSERT INTO abc VALUES(randomblob(1500));
392 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4
393 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 8
394 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 16
395 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 32
396 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 64
397 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 128
398 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 256
399 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 512
400 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 1024
401 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 2048
402 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4096
405 faultsim_save_and_close
407 do_faultsim_test walfault-11 -faults shmerr* -prep {
409 faultsim_restore_and_reopen
410 shmfault filter xShmMap
412 db eval { SELECT count(*) FROM abc }
413 sqlite3 db2 test.db -vfs shmfault
414 db2 eval { PRAGMA wal_checkpoint }
417 faultsim_test_result {0 {}}
420 #-------------------------------------------------------------------------
421 # Test the handling of the various IO/OOM/SHM errors that may occur during
422 # a log recovery operation undertaken as part of a call to
423 # sqlite3_wal_checkpoint().
425 do_test walfault-12-pre-1 {
426 faultsim_delete_and_reopen
428 PRAGMA journal_mode = WAL;
429 PRAGMA wal_autocheckpoint = 0;
431 CREATE TABLE abc(a PRIMARY KEY);
432 INSERT INTO abc VALUES(randomblob(1500));
433 INSERT INTO abc VALUES(randomblob(1500));
436 faultsim_save_and_close
438 do_faultsim_test walfault-12 -prep {
439 if {[info commands shmfault] == ""} {
440 testvfs shmfault -default true
442 faultsim_restore_and_reopen
443 db eval { SELECT * FROM sqlite_master }
444 shmfault shm test.db [string repeat "\000" 40]
446 set rc [sqlite3_wal_checkpoint db]
447 if {$rc != "SQLITE_OK"} { error [sqlite3_errmsg db] }
450 faultsim_test_result {0 {}}
453 #-------------------------------------------------------------------------
454 # Test simple recovery, reading and writing a database file using a
455 # heap-memory wal-index.
457 do_test walfault-13-pre-1 {
458 faultsim_delete_and_reopen
460 PRAGMA journal_mode = WAL;
461 PRAGMA wal_autocheckpoint = 0;
463 CREATE TABLE abc(a PRIMARY KEY);
464 INSERT INTO abc VALUES(randomblob(1500));
465 INSERT INTO abc VALUES(randomblob(1500));
468 faultsim_save_and_close
469 delete_file sv_test.db-shm
472 do_faultsim_test walfault-13.1 -prep {
473 faultsim_restore_and_reopen
475 db eval { PRAGMA locking_mode = exclusive }
476 db eval { SELECT count(*) FROM abc }
478 faultsim_test_result {0 2}
479 if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
480 faultsim_integrity_check
483 do_faultsim_test walfault-13.2 -prep {
484 faultsim_restore_and_reopen
485 db eval { PRAGMA locking_mode = exclusive }
487 db eval { PRAGMA journal_mode = delete }
489 faultsim_test_result {0 delete}
490 if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
491 faultsim_integrity_check
494 do_test walfault-13-pre-2 {
495 faultsim_delete_and_reopen
498 CREATE TABLE abc(a PRIMARY KEY);
499 INSERT INTO abc VALUES(randomblob(1500));
500 INSERT INTO abc VALUES(randomblob(1500));
503 faultsim_save_and_close
506 do_faultsim_test walfault-13.3 -prep {
507 faultsim_restore_and_reopen
510 PRAGMA locking_mode = exclusive;
511 PRAGMA journal_mode = WAL;
512 INSERT INTO abc VALUES(randomblob(1500));
515 faultsim_test_result {0 {exclusive wal}}
516 if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
517 faultsim_integrity_check
518 set nRow [db eval {SELECT count(*) FROM abc}]
519 if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }
522 #-------------------------------------------------------------------------
523 # Test fault-handling when wrapping around to the start of a WAL file.
525 do_test walfault-14-pre {
526 faultsim_delete_and_reopen
528 PRAGMA auto_vacuum = 0;
529 PRAGMA journal_mode = WAL;
531 CREATE TABLE abc(a PRIMARY KEY);
532 INSERT INTO abc VALUES(randomblob(1500));
533 INSERT INTO abc VALUES(randomblob(1500));
536 faultsim_save_and_close
538 do_faultsim_test walfault-14 -prep {
539 faultsim_restore_and_reopen
542 PRAGMA wal_checkpoint = full;
543 INSERT INTO abc VALUES(randomblob(1500));
546 faultsim_test_result {0 {0 9 9}}
547 faultsim_integrity_check
548 set nRow [db eval {SELECT count(*) FROM abc}]
549 if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }
552 #-------------------------------------------------------------------------
553 # Test fault-handling when switching out of exclusive-locking mode.
555 do_test walfault-15-pre {
556 faultsim_delete_and_reopen
558 PRAGMA auto_vacuum = 0;
559 PRAGMA journal_mode = WAL;
561 CREATE TABLE abc(a PRIMARY KEY);
562 INSERT INTO abc VALUES(randomblob(1500));
563 INSERT INTO abc VALUES(randomblob(1500));
566 faultsim_save_and_close
568 do_faultsim_test walfault-15 -prep {
569 faultsim_restore_and_reopen
571 SELECT count(*) FROM abc;
572 PRAGMA locking_mode = exclusive;
574 INSERT INTO abc VALUES(randomblob(1500));
579 PRAGMA locking_mode = normal;
581 INSERT INTO abc VALUES(randomblob(1500));
585 faultsim_integrity_check
586 set nRow [db eval {SELECT count(*) FROM abc}]
587 if {$nRow!=3 && $nRow!=4} { error "Bad db content" }