1: # 2010 May 03
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: #
15:
16: set testdir [file dirname $argv0]
17: source $testdir/tester.tcl
18: source $testdir/malloc_common.tcl
19: source $testdir/lock_common.tcl
20:
21: ifcapable !wal {finish_test ; return }
22:
23: #-------------------------------------------------------------------------
24: # This test case, walfault-1-*, simulates faults while executing a
25: #
26: # PRAGMA journal_mode = WAL;
27: #
28: # statement immediately after creating a new database.
29: #
30: do_test walfault-1-pre-1 {
31: faultsim_delete_and_reopen
32: faultsim_save_and_close
33: } {}
34: do_faultsim_test walfault-1 -prep {
35: faultsim_restore_and_reopen
36: } -body {
37: db eval { PRAGMA main.journal_mode = WAL }
38: } -test {
39:
40: faultsim_test_result {0 wal}
41:
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.
45: #
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.
52: #
53: if {[permutation] != "inmemory_journal"} {
54: set jm [db one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}]
55: sqlite3 db2 test.db
56: set jm2 [db2 one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}]
57: db2 close
58:
59: if { $jm!=$jm2 } { error "Journal modes do not match: $jm $jm2" }
60: if { $testrc==0 && $jm!="wal" } { error "Journal mode is not WAL" }
61: }
62: }
63:
64: #--------------------------------------------------------------------------
65: # Test case walfault-2-* tests fault injection during recovery of a
66: # short WAL file (a dozen frames or thereabouts).
67: #
68: do_test walfault-2-pre-1 {
69: sqlite3 db test.db
70: execsql {
71: PRAGMA journal_mode = WAL;
72: BEGIN;
73: CREATE TABLE x(y, z, UNIQUE(y, z));
74: INSERT INTO x VALUES(randomblob(100), randomblob(100));
75: COMMIT;
76: PRAGMA wal_checkpoint;
77:
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;
81: }
82: execsql {
83: SELECT count(*) FROM x
84: }
85: } {8}
86: do_test walfault-2-pre-2 {
87: faultsim_save_and_close
88: faultsim_restore_and_reopen
89: execsql { SELECT count(*) FROM x }
90: } {8}
91: do_faultsim_test walfault-2 -prep {
92: faultsim_restore_and_reopen
93: } -body {
94: execsql { SELECT count(*) FROM x }
95: } -test {
96: faultsim_test_result {0 8}
97: faultsim_integrity_check
98: }
99:
100: #--------------------------------------------------------------------------
101: # Test fault injection while writing and checkpointing a small WAL file.
102: #
103: do_test walfault-3-pre-1 {
104: sqlite3 db test.db
105: execsql {
106: PRAGMA auto_vacuum = 1;
107: PRAGMA journal_mode = WAL;
108: CREATE TABLE abc(a PRIMARY KEY);
109: INSERT INTO abc VALUES(randomblob(1500));
110: }
111: db close
112: faultsim_save_and_close
113: } {}
114: do_faultsim_test walfault-3 -prep {
115: faultsim_restore_and_reopen
116: } -body {
117: db eval {
118: DELETE FROM abc;
119: PRAGMA wal_checkpoint;
120: }
121: set {} {}
122: } -test {
123: faultsim_test_result {0 {}}
124: }
125:
126: #--------------------------------------------------------------------------
127: #
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
133: } -body {
134: execsql {
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;
140: SELECT * FROM t1;
141: }
142: } -test {
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
147: }
148: }
149:
150: #--------------------------------------------------------------------------
151: #
152: do_test walfault-5-pre-1 {
153: faultsim_delete_and_reopen
154: execsql {
155: PRAGMA page_size = 512;
156: PRAGMA journal_mode = WAL;
157: }
158: faultsim_save_and_close
159: } {}
160: do_faultsim_test walfault-5 -faults shmerr* -prep {
161: faultsim_restore_and_reopen
162: execsql { PRAGMA wal_autocheckpoint = 0 }
163: shmfault filter xShmMap
164: } -body {
165: execsql {
166: CREATE TABLE t1(x);
167: BEGIN;
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 */
183: COMMIT;
184: SELECT count(*) FROM t1;
185: }
186: } -test {
187: faultsim_test_result {0 16384}
188: faultsim_integrity_check
189: }
190:
191: #--------------------------------------------------------------------------
192: #
193: do_test walfault-6-pre-1 {
194: faultsim_delete_and_reopen
195: execsql {
196: PRAGMA page_size = 512;
197: PRAGMA journal_mode = WAL;
198: PRAGMA wal_autocheckpoint = 0;
199: CREATE TABLE t1(x);
200: BEGIN;
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 */
216: COMMIT;
217: }
218: faultsim_save_and_close
219: } {}
220: do_faultsim_test walfault-6 -faults shmerr* -prep {
221: faultsim_restore_and_reopen
222: shmfault filter xShmMap
223: } -body {
224: execsql { SELECT count(*) FROM t1 }
225: } -test {
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" }
230: }
231:
232: #--------------------------------------------------------------------------
233: #
234: do_test walfault-7-pre-1 {
235: faultsim_delete_and_reopen
236: execsql {
237: PRAGMA page_size = 512;
238: PRAGMA journal_mode = WAL;
239: PRAGMA wal_autocheckpoint = 0;
240: CREATE TABLE t1(x);
241: BEGIN;
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 */
245: COMMIT;
246: }
247: faultsim_save_and_close
248: } {}
249: do_faultsim_test walfault-7 -prep {
250: faultsim_restore_and_reopen
251: } -body {
252: execsql { SELECT count(*) FROM t1 }
253: } -test {
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" }
257: }
258:
259: #--------------------------------------------------------------------------
260: #
261: do_test walfault-8-pre-1 {
262: faultsim_delete_and_reopen
263: execsql {
264: PRAGMA journal_mode = WAL;
265: CREATE TABLE abc(a PRIMARY KEY);
266: INSERT INTO abc VALUES(randomblob(900));
267: }
268: faultsim_save_and_close
269: } {}
270: do_faultsim_test walfault-8 -prep {
271: faultsim_restore_and_reopen
272: execsql { PRAGMA cache_size = 10 }
273: } -body {
274: execsql {
275: BEGIN;
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 */
280: ROLLBACK;
281: SELECT count(*) FROM abc;
282: }
283: } -test {
284: faultsim_test_result {0 1}
285:
286: faultsim_integrity_check
287: catch { db eval ROLLBACK }
288: faultsim_integrity_check
289:
290: set n [db one {SELECT count(*) FROM abc}]
291: if {$n != 1} { error "Incorrect number of rows: $n" }
292: }
293:
294: #--------------------------------------------------------------------------
295: #
296: do_test walfault-9-pre-1 {
297: faultsim_delete_and_reopen
298: execsql {
299: PRAGMA journal_mode = WAL;
300: CREATE TABLE abc(a PRIMARY KEY);
301: INSERT INTO abc VALUES(randomblob(900));
302: }
303: faultsim_save_and_close
304: } {}
305: do_faultsim_test walfault-9 -prep {
306: #if {$iFail<73} { set iFail 73 }
307: #if {$iFail>73} { exit }
308:
309: faultsim_restore_and_reopen
310: execsql { PRAGMA cache_size = 10 }
311: } -body {
312: execsql {
313: BEGIN;
314: INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
315: SAVEPOINT spoint;
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 */
319: ROLLBACK TO spoint;
320: COMMIT;
321: SELECT count(*) FROM abc;
322: }
323: } -test {
324: faultsim_test_result {0 2}
325: faultsim_integrity_check
326:
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" }
331: }
332:
333: do_test walfault-10-pre1 {
334: faultsim_delete_and_reopen
335: execsql {
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;
347: }
348: faultsim_save_and_close
349: } {}
350: do_faultsim_test walfault-10 -prep {
351: faultsim_restore_and_reopen
352: execsql {
353: PRAGMA cache_size = 10;
354: BEGIN;
355: UPDATE z SET zzz = randomblob(799);
356: }
357:
358: set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1]
359: sqlite3_step $::stmt
360: } -body {
361: execsql { INSERT INTO z VALUES(NULL, NULL) }
362: } -test {
363: sqlite3_finalize $::stmt
364: faultsim_integrity_check
365:
366: faultsim_test_result {0 {}}
367: catch { db eval { ROLLBACK } }
368: faultsim_integrity_check
369:
370: set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}]
371: if {$n != "64 51200"} { error "Incorrect data: $n" }
372: }
373:
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
379: # for IO errors.
380: #
381: # To speed this up, IO errors are only simulated within xShmMap() calls.
382: #
383: do_test walfault-11-pre-1 {
384: sqlite3 db test.db
385: execsql {
386: PRAGMA journal_mode = WAL;
387: PRAGMA wal_autocheckpoint = 0;
388: BEGIN;
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
403: COMMIT;
404: }
405: faultsim_save_and_close
406: } {}
407: do_faultsim_test walfault-11 -faults shmerr* -prep {
408: catch { db2 close }
409: faultsim_restore_and_reopen
410: shmfault filter xShmMap
411: } -body {
412: db eval { SELECT count(*) FROM abc }
413: sqlite3 db2 test.db -vfs shmfault
414: db2 eval { PRAGMA wal_checkpoint }
415: set {} {}
416: } -test {
417: faultsim_test_result {0 {}}
418: }
419:
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().
424: #
425: do_test walfault-12-pre-1 {
426: faultsim_delete_and_reopen
427: execsql {
428: PRAGMA journal_mode = WAL;
429: PRAGMA wal_autocheckpoint = 0;
430: BEGIN;
431: CREATE TABLE abc(a PRIMARY KEY);
432: INSERT INTO abc VALUES(randomblob(1500));
433: INSERT INTO abc VALUES(randomblob(1500));
434: COMMIT;
435: }
436: faultsim_save_and_close
437: } {}
438: do_faultsim_test walfault-12 -prep {
439: if {[info commands shmfault] == ""} {
440: testvfs shmfault -default true
441: }
442: faultsim_restore_and_reopen
443: db eval { SELECT * FROM sqlite_master }
444: shmfault shm test.db [string repeat "\000" 40]
445: } -body {
446: set rc [sqlite3_wal_checkpoint db]
447: if {$rc != "SQLITE_OK"} { error [sqlite3_errmsg db] }
448: } -test {
449: db close
450: faultsim_test_result {0 {}}
451: }
452:
453: #-------------------------------------------------------------------------
454: # Test simple recovery, reading and writing a database file using a
455: # heap-memory wal-index.
456: #
457: do_test walfault-13-pre-1 {
458: faultsim_delete_and_reopen
459: execsql {
460: PRAGMA journal_mode = WAL;
461: PRAGMA wal_autocheckpoint = 0;
462: BEGIN;
463: CREATE TABLE abc(a PRIMARY KEY);
464: INSERT INTO abc VALUES(randomblob(1500));
465: INSERT INTO abc VALUES(randomblob(1500));
466: COMMIT;
467: }
468: faultsim_save_and_close
469: delete_file sv_test.db-shm
470: } {}
471:
472: do_faultsim_test walfault-13.1 -prep {
473: faultsim_restore_and_reopen
474: } -body {
475: db eval { PRAGMA locking_mode = exclusive }
476: db eval { SELECT count(*) FROM abc }
477: } -test {
478: faultsim_test_result {0 2}
479: if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
480: faultsim_integrity_check
481: }
482:
483: do_faultsim_test walfault-13.2 -prep {
484: faultsim_restore_and_reopen
485: db eval { PRAGMA locking_mode = exclusive }
486: } -body {
487: db eval { PRAGMA journal_mode = delete }
488: } -test {
489: faultsim_test_result {0 delete}
490: if {[file exists test.db-shm]} { error "Not using heap-memory mode" }
491: faultsim_integrity_check
492: }
493:
494: do_test walfault-13-pre-2 {
495: faultsim_delete_and_reopen
496: execsql {
497: BEGIN;
498: CREATE TABLE abc(a PRIMARY KEY);
499: INSERT INTO abc VALUES(randomblob(1500));
500: INSERT INTO abc VALUES(randomblob(1500));
501: COMMIT;
502: }
503: faultsim_save_and_close
504: } {}
505:
506: do_faultsim_test walfault-13.3 -prep {
507: faultsim_restore_and_reopen
508: } -body {
509: db eval {
510: PRAGMA locking_mode = exclusive;
511: PRAGMA journal_mode = WAL;
512: INSERT INTO abc VALUES(randomblob(1500));
513: }
514: } -test {
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" }
520: }
521:
522: #-------------------------------------------------------------------------
523: # Test fault-handling when wrapping around to the start of a WAL file.
524: #
525: do_test walfault-14-pre {
526: faultsim_delete_and_reopen
527: execsql {
528: PRAGMA auto_vacuum = 0;
529: PRAGMA journal_mode = WAL;
530: BEGIN;
531: CREATE TABLE abc(a PRIMARY KEY);
532: INSERT INTO abc VALUES(randomblob(1500));
533: INSERT INTO abc VALUES(randomblob(1500));
534: COMMIT;
535: }
536: faultsim_save_and_close
537: } {}
538: do_faultsim_test walfault-14 -prep {
539: faultsim_restore_and_reopen
540: } -body {
541: db eval {
542: PRAGMA wal_checkpoint = full;
543: INSERT INTO abc VALUES(randomblob(1500));
544: }
545: } -test {
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" }
550: }
551: finish_test
552:
553: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>