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 {}}
127 #--------------------------------------------------------------------------
129 if {[permutation] != "inmemory_journal"} {
130 faultsim_delete_and_reopen
131 faultsim_save_and_close
132 do_faultsim_test walfault-4 -prep {
133 faultsim_restore_and_reopen
136 PRAGMA auto_vacuum = 0;
137 PRAGMA journal_mode = WAL;
138 CREATE TABLE t1(a PRIMARY KEY, b);
139 INSERT INTO t1 VALUES('a', 'b');
140 PRAGMA wal_checkpoint;
144 faultsim_test_result {0 {wal 0 7 7 a b}}
145 faultsim_integrity_check
149 #--------------------------------------------------------------------------
151 do_test walfault-5-pre-1 {
152 faultsim_delete_and_reopen
154 PRAGMA page_size = 512;
155 PRAGMA journal_mode = WAL;
157 faultsim_save_and_close
159 do_faultsim_test walfault-5 -faults shmerr* -prep {
160 faultsim_restore_and_reopen
161 execsql { PRAGMA wal_autocheckpoint = 0 }
162 shmfault filter xShmMap
167 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
168 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
169 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
170 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */
171 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */
172 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */
173 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */
174 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */
175 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */
176 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */
177 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */
178 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */
179 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */
180 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
181 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
183 SELECT count(*) FROM t1;
186 faultsim_test_result {0 16384}
187 faultsim_integrity_check
190 #--------------------------------------------------------------------------
192 do_test walfault-6-pre-1 {
193 faultsim_delete_and_reopen
195 PRAGMA page_size = 512;
196 PRAGMA journal_mode = WAL;
197 PRAGMA wal_autocheckpoint = 0;
200 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
201 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
202 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
203 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */
204 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */
205 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */
206 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */
207 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */
208 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */
209 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */
210 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */
211 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */
212 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */
213 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
214 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
217 faultsim_save_and_close
219 do_faultsim_test walfault-6 -faults shmerr* -prep {
220 faultsim_restore_and_reopen
221 shmfault filter xShmMap
223 execsql { SELECT count(*) FROM t1 }
225 faultsim_test_result {0 16384}
226 faultsim_integrity_check
227 set n [db one {SELECT count(*) FROM t1}]
228 if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" }
231 #--------------------------------------------------------------------------
233 do_test walfault-7-pre-1 {
234 faultsim_delete_and_reopen
236 PRAGMA page_size = 512;
237 PRAGMA journal_mode = WAL;
238 PRAGMA wal_autocheckpoint = 0;
241 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
242 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */
243 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
246 faultsim_save_and_close
248 do_faultsim_test walfault-7 -prep {
249 faultsim_restore_and_reopen
251 execsql { SELECT count(*) FROM t1 }
253 faultsim_test_result {0 4}
254 set n [db one {SELECT count(*) FROM t1}]
255 if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" }
258 #--------------------------------------------------------------------------
260 do_test walfault-8-pre-1 {
261 faultsim_delete_and_reopen
263 PRAGMA journal_mode = WAL;
264 CREATE TABLE abc(a PRIMARY KEY);
265 INSERT INTO abc VALUES(randomblob(900));
267 faultsim_save_and_close
269 do_faultsim_test walfault-8 -prep {
270 faultsim_restore_and_reopen
271 execsql { PRAGMA cache_size = 10 }
275 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
276 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
277 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
278 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
280 SELECT count(*) FROM abc;
283 faultsim_test_result {0 1}
285 faultsim_integrity_check
286 catch { db eval ROLLBACK }
287 faultsim_integrity_check
289 set n [db one {SELECT count(*) FROM abc}]
290 if {$n != 1} { error "Incorrect number of rows: $n" }
293 #--------------------------------------------------------------------------
295 do_test walfault-9-pre-1 {
296 faultsim_delete_and_reopen
298 PRAGMA journal_mode = WAL;
299 CREATE TABLE abc(a PRIMARY KEY);
300 INSERT INTO abc VALUES(randomblob(900));
302 faultsim_save_and_close
304 do_faultsim_test walfault-9 -prep {
305 #if {$iFail<73} { set iFail 73 }
306 #if {$iFail>73} { exit }
308 faultsim_restore_and_reopen
309 execsql { PRAGMA cache_size = 10 }
313 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
315 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */
316 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
317 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
320 SELECT count(*) FROM abc;
323 faultsim_test_result {0 2}
324 faultsim_integrity_check
326 catch { db eval { ROLLBACK TO spoint } }
327 catch { db eval { COMMIT } }
328 set n [db one {SELECT count(*) FROM abc}]
329 if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" }
332 do_test walfault-10-pre1 {
333 faultsim_delete_and_reopen
335 PRAGMA journal_mode = WAL;
336 PRAGMA wal_autocheckpoint = 0;
337 CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB);
338 CREATE INDEX zzzz ON z(zzz);
339 INSERT INTO z VALUES(NULL, randomblob(800));
340 INSERT INTO z VALUES(NULL, randomblob(800));
341 INSERT INTO z SELECT NULL, randomblob(800) FROM z;
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;
347 faultsim_save_and_close
349 do_faultsim_test walfault-10 -prep {
350 faultsim_restore_and_reopen
352 PRAGMA cache_size = 10;
354 UPDATE z SET zzz = randomblob(799);
357 set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1]
360 execsql { INSERT INTO z VALUES(NULL, NULL) }
362 sqlite3_finalize $::stmt
363 faultsim_integrity_check
365 faultsim_test_result {0 {}}
366 catch { db eval { ROLLBACK } }
367 faultsim_integrity_check
369 set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}]
370 if {$n != "64 51200"} { error "Incorrect data: $n" }
373 #--------------------------------------------------------------------------
374 # Test fault injection while checkpointing a large WAL file, if the
375 # checkpoint is the first operation run after opening the database.
376 # This means that some of the required wal-index pages are mapped as part of
377 # the checkpoint process, which means there are a few more opportunities
380 # To speed this up, IO errors are only simulated within xShmMap() calls.
382 do_test walfault-11-pre-1 {
385 PRAGMA journal_mode = WAL;
386 PRAGMA wal_autocheckpoint = 0;
388 CREATE TABLE abc(a PRIMARY KEY);
389 INSERT INTO abc VALUES(randomblob(1500));
390 INSERT INTO abc VALUES(randomblob(1500));
391 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4
392 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 8
393 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 16
394 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 32
395 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 64
396 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 128
397 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 256
398 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 512
399 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 1024
400 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 2048
401 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4096
404 faultsim_save_and_close
406 do_faultsim_test walfault-11 -faults shmerr* -prep {
408 faultsim_restore_and_reopen
409 shmfault filter xShmMap
411 db eval { SELECT count(*) FROM abc }
412 sqlite3 db2 test.db -vfs shmfault
413 db2 eval { PRAGMA wal_checkpoint }
416 faultsim_test_result {0 {}}
419 #-------------------------------------------------------------------------
420 # Test the handling of the various IO/OOM/SHM errors that may occur during
421 # a log recovery operation undertaken as part of a call to
422 # sqlite3_wal_checkpoint().
424 do_test walfault-12-pre-1 {
425 faultsim_delete_and_reopen
427 PRAGMA journal_mode = WAL;
428 PRAGMA wal_autocheckpoint = 0;
430 CREATE TABLE abc(a PRIMARY KEY);
431 INSERT INTO abc VALUES(randomblob(1500));
432 INSERT INTO abc VALUES(randomblob(1500));
435 faultsim_save_and_close
437 do_faultsim_test walfault-12 -prep {
438 if {[info commands shmfault] == ""} {
439 testvfs shmfault -default true
441 faultsim_restore_and_reopen
442 db eval { SELECT * FROM sqlite_master }
443 shmfault shm test.db [string repeat "\000" 40]
445 set rc [sqlite3_wal_checkpoint db]
446 if {$rc != "SQLITE_OK"} { error [sqlite3_errmsg db] }
449 faultsim_test_result {0 {}}
452 #-------------------------------------------------------------------------
453 # Test simple recovery, reading and writing a database file using a
454 # heap-memory wal-index.
456 do_test walfault-13-pre-1 {
457 faultsim_delete_and_reopen
459 PRAGMA journal_mode = WAL;
460 PRAGMA wal_autocheckpoint = 0;
462 CREATE TABLE abc(a PRIMARY KEY);
463 INSERT INTO abc VALUES(randomblob(1500));
464 INSERT INTO abc VALUES(randomblob(1500));
467 faultsim_save_and_close
468 file delete sv_test.db-shm
471 do_faultsim_test walfault-13.1 -prep {
472 faultsim_restore_and_reopen
474 db eval { PRAGMA locking_mode = exclusive }
475 db eval { SELECT count(*) FROM abc }
477 faultsim_test_result {0 2}
478 if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
479 faultsim_integrity_check
482 do_faultsim_test walfault-13.2 -prep {
483 faultsim_restore_and_reopen
484 db eval { PRAGMA locking_mode = exclusive }
486 db eval { PRAGMA journal_mode = delete }
488 faultsim_test_result {0 delete}
489 if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
490 faultsim_integrity_check
493 do_test walfault-13-pre-2 {
494 faultsim_delete_and_reopen
497 CREATE TABLE abc(a PRIMARY KEY);
498 INSERT INTO abc VALUES(randomblob(1500));
499 INSERT INTO abc VALUES(randomblob(1500));
502 faultsim_save_and_close
505 do_faultsim_test walfault-13.3 -prep {
506 faultsim_restore_and_reopen
509 PRAGMA locking_mode = exclusive;
510 PRAGMA journal_mode = WAL;
511 INSERT INTO abc VALUES(randomblob(1500));
514 faultsim_test_result {0 {exclusive wal}}
515 if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
516 faultsim_integrity_check
517 set nRow [db eval {SELECT count(*) FROM abc}]
518 if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }
521 #-------------------------------------------------------------------------
522 # Test fault-handling when wrapping around to the start of a WAL file.
524 do_test walfault-14-pre {
525 faultsim_delete_and_reopen
527 PRAGMA auto_vacuum = 0;
528 PRAGMA journal_mode = WAL;
530 CREATE TABLE abc(a PRIMARY KEY);
531 INSERT INTO abc VALUES(randomblob(1500));
532 INSERT INTO abc VALUES(randomblob(1500));
535 faultsim_save_and_close
537 do_faultsim_test walfault-14 -prep {
538 faultsim_restore_and_reopen
541 PRAGMA wal_checkpoint = full;
542 INSERT INTO abc VALUES(randomblob(1500));
545 faultsim_test_result {0 {0 10 10}}
546 faultsim_integrity_check
547 set nRow [db eval {SELECT count(*) FROM abc}]
548 if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" }