blob: e7415f064acb91d4dea3093eb2adab4d3c20b4dd [file] [log] [blame]
danb0ac3e32010-06-16 10:55:42 +00001# 2010 June 15
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#
12
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15source $testdir/lock_common.tcl
16source $testdir/malloc_common.tcl
17
18set a_string_counter 1
19proc a_string {n} {
20 global a_string_counter
21 incr a_string_counter
22 string range [string repeat "${a_string_counter}." $n] 1 $n
23}
24db func a_string a_string
25
26#-------------------------------------------------------------------------
27# Test fault-injection while rolling back a hot-journal file.
28#
29do_test pagerfault-1-pre1 {
30 execsql {
31 PRAGMA journal_mode = DELETE;
32 PRAGMA cache_size = 10;
33 CREATE TABLE t1(a UNIQUE, b UNIQUE);
34 INSERT INTO t1 VALUES(a_string(200), a_string(300));
35 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
36 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
37 BEGIN;
38 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
39 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
40 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
41 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
42 }
43 faultsim_save_and_close
44} {}
45do_faultsim_test pagerfault-1 -prep {
46 faultsim_restore_and_reopen
47} -body {
48 execsql { SELECT count(*) FROM t1 }
49} -test {
50 faultsim_test_result {0 4}
51 faultsim_integrity_check
52 if {[db one { SELECT count(*) FROM t1 }] != 4} {
53 error "Database content appears incorrect"
54 }
55}
56
57#-------------------------------------------------------------------------
dande4996e2010-06-19 11:30:41 +000058# Test fault-injection while rolling back a hot-journal file with a
59# page-size different from the current value stored on page 1 of the
60# database file.
61#
62do_test pagerfault-2-pre1 {
63 testvfs tv -default 1
64 tv filter xSync
65 tv script xSyncCb
66 proc xSyncCb {filename args} {
67 if {[string match *journal filename]==0} faultsim_save
68 }
69 faultsim_delete_and_reopen
70 execsql {
71 PRAGMA page_size = 4096;
72 BEGIN;
73 CREATE TABLE abc(a, b, c);
74 INSERT INTO abc VALUES('o', 't', 't');
75 INSERT INTO abc VALUES('f', 'f', 's');
76 INSERT INTO abc SELECT * FROM abc; -- 4
77 INSERT INTO abc SELECT * FROM abc; -- 8
78 INSERT INTO abc SELECT * FROM abc; -- 16
79 INSERT INTO abc SELECT * FROM abc; -- 32
80 INSERT INTO abc SELECT * FROM abc; -- 64
81 INSERT INTO abc SELECT * FROM abc; -- 128
82 INSERT INTO abc SELECT * FROM abc; -- 256
83 COMMIT;
84 PRAGMA page_size = 1024;
85 VACUUM;
86 }
87 db close
88 tv delete
89} {}
90do_faultsim_test pagerfault-2 -prep {
91 faultsim_restore_and_reopen
92} -body {
93 execsql { SELECT * FROM abc }
94} -test {
95 set answer [split [string repeat "ottffs" 128] ""]
96 faultsim_test_result [list 0 $answer]
97 faultsim_integrity_check
98 set res [db eval { SELECT * FROM abc }]
99 if {$res != $answer} { error "Database content appears incorrect ($res)" }
danec6ffc12010-06-24 19:16:06 +0000100}
dande4996e2010-06-19 11:30:41 +0000101
102#-------------------------------------------------------------------------
danb0ac3e32010-06-16 10:55:42 +0000103# Test fault-injection while rolling back hot-journals that were created
104# as part of a multi-file transaction.
105#
dande4996e2010-06-19 11:30:41 +0000106do_test pagerfault-3-pre1 {
danb0ac3e32010-06-16 10:55:42 +0000107 testvfs tstvfs -default 1
108 tstvfs filter xDelete
109 tstvfs script xDeleteCallback
110
111 proc xDeleteCallback {method file args} {
112 set file [file tail $file]
113 if { [string match *mj* $file] } { faultsim_save }
114 }
115
116 faultsim_delete_and_reopen
117 db func a_string a_string
118
119 execsql {
120 ATTACH 'test.db2' AS aux;
121 PRAGMA journal_mode = DELETE;
122 PRAGMA main.cache_size = 10;
123 PRAGMA aux.cache_size = 10;
124
125 CREATE TABLE t1(a UNIQUE, b UNIQUE);
126 CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
127 INSERT INTO t1 VALUES(a_string(200), a_string(300));
128 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
129 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
130 INSERT INTO t2 SELECT * FROM t1;
131
132 BEGIN;
133 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
134 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
135 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
136 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
137 REPLACE INTO t2 SELECT * FROM t1;
138 COMMIT;
139 }
140
141 db close
142 tstvfs delete
143} {}
danec6ffc12010-06-24 19:16:06 +0000144do_faultsim_test pagerfault-3 -prep {
danb0ac3e32010-06-16 10:55:42 +0000145 faultsim_restore_and_reopen
146} -body {
147 execsql {
148 ATTACH 'test.db2' AS aux;
149 SELECT count(*) FROM t2;
150 SELECT count(*) FROM t1;
151 }
152} -test {
153 faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}}
154 faultsim_integrity_check
danb0ac3e32010-06-16 10:55:42 +0000155 catchsql { ATTACH 'test.db2' AS aux }
156 if {[db one { SELECT count(*) FROM t1 }] != 4
157 || [db one { SELECT count(*) FROM t2 }] != 4
158 } {
159 error "Database content appears incorrect"
160 }
161}
162
dande4996e2010-06-19 11:30:41 +0000163#-------------------------------------------------------------------------
164# Test fault-injection as part of a vanilla, no-transaction, INSERT
165# statement.
166#
167do_faultsim_test pagerfault-4 -prep {
168 faultsim_delete_and_reopen
169} -body {
170 execsql {
171 CREATE TABLE x(y);
172 INSERT INTO x VALUES('z');
173 SELECT * FROM x;
174 }
175} -test {
176 faultsim_test_result {0 z}
177 faultsim_integrity_check
178}
179
180#-------------------------------------------------------------------------
181# Test fault-injection as part of a commit when using journal_mode=PERSIST.
dan146ed782010-06-19 17:26:37 +0000182# Three different cases:
183#
184# pagerfault-5.1: With no journal_size_limit configured.
185# pagerfault-5.2: With a journal_size_limit configured.
186# pagerfault-5.4: Multi-file transaction. One connection has a
187# journal_size_limit of 0, the other has no limit.
dande4996e2010-06-19 11:30:41 +0000188#
189do_test pagerfault-5-pre1 {
190 faultsim_delete_and_reopen
191 db func a_string a_string
192 execsql {
193 CREATE TABLE t1(a UNIQUE, b UNIQUE);
194 INSERT INTO t1 VALUES(a_string(200), a_string(300));
195 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
196 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
197 }
198 faultsim_save_and_close
199} {}
200do_faultsim_test pagerfault-5.1 -prep {
201 faultsim_restore_and_reopen
202 db func a_string a_string
203 execsql { PRAGMA journal_mode = PERSIST }
204} -body {
205 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
206} -test {
207 faultsim_test_result {0 {}}
208 faultsim_integrity_check
209}
210do_faultsim_test pagerfault-5.2 -prep {
211 faultsim_restore_and_reopen
212 db func a_string a_string
213 execsql {
214 PRAGMA journal_mode = PERSIST;
215 PRAGMA journal_size_limit = 2048;
216 }
217} -body {
218 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
219} -test {
220 faultsim_test_result {0 {}}
221 faultsim_integrity_check
222}
danec6ffc12010-06-24 19:16:06 +0000223do_faultsim_test pagerfault-5.3 -faults oom-transient -prep {
dande4996e2010-06-19 11:30:41 +0000224 faultsim_restore_and_reopen
225 db func a_string a_string
226 file delete -force test2.db test2.db-journal test2.db-wal
227 execsql {
228 PRAGMA journal_mode = PERSIST;
229 ATTACH 'test2.db' AS aux;
230 PRAGMA aux.journal_mode = PERSIST;
231 PRAGMA aux.journal_size_limit = 0;
232 }
233} -body {
234 execsql {
235 BEGIN;
236 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
237 CREATE TABLE aux.t2 AS SELECT * FROM t1;
238 COMMIT;
239 }
240} -test {
241 faultsim_test_result {0 {}}
danec6ffc12010-06-24 19:16:06 +0000242 faultsim_integrity_check
243
244 set res ""
245 set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }]
246 if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"}
dande4996e2010-06-19 11:30:41 +0000247}
248
danec6ffc12010-06-24 19:16:06 +0000249
dan153eda02010-06-21 07:45:47 +0000250#-------------------------------------------------------------------------
251# Test fault-injection as part of a commit when using
252# journal_mode=TRUNCATE.
253#
254do_test pagerfault-6-pre1 {
255 faultsim_delete_and_reopen
256 db func a_string a_string
257 execsql {
258 CREATE TABLE t1(a UNIQUE, b UNIQUE);
259 INSERT INTO t1 VALUES(a_string(200), a_string(300));
260 }
261 faultsim_save_and_close
262} {}
263do_faultsim_test pagerfault-6.1 -prep {
264 faultsim_restore_and_reopen
265 db func a_string a_string
266 execsql { PRAGMA journal_mode = TRUNCATE }
267} -body {
268 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
269} -test {
270 faultsim_test_result {0 {}}
271 faultsim_integrity_check
272}
273
dan146ed782010-06-19 17:26:37 +0000274# The following was an attempt to get a bitvec malloc to fail. Didn't work.
275#
276# do_test pagerfault-6-pre1 {
277# faultsim_delete_and_reopen
278# execsql {
279# CREATE TABLE t1(x, y, UNIQUE(x, y));
280# INSERT INTO t1 VALUES(1, randomblob(1501));
281# INSERT INTO t1 VALUES(2, randomblob(1502));
282# INSERT INTO t1 VALUES(3, randomblob(1503));
283# INSERT INTO t1 VALUES(4, randomblob(1504));
284# INSERT INTO t1
285# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
286# INSERT INTO t1
287# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
288# INSERT INTO t1
289# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
290# INSERT INTO t1
291# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
292# }
293# faultsim_save_and_close
294# } {}
295# do_faultsim_test pagerfault-6 -prep {
296# faultsim_restore_and_reopen
297# } -body {
298# execsql {
299# BEGIN;
300# UPDATE t1 SET x=x+4 WHERE x=1;
301# SAVEPOINT one;
302# UPDATE t1 SET x=x+4 WHERE x=2;
303# SAVEPOINT three;
304# UPDATE t1 SET x=x+4 WHERE x=3;
305# SAVEPOINT four;
306# UPDATE t1 SET x=x+4 WHERE x=4;
307# RELEASE three;
308# COMMIT;
309# SELECT DISTINCT x FROM t1;
310# }
311# } -test {
312# faultsim_test_result {0 {5 6 7 8}}
313# faultsim_integrity_check
314# }
dan346e4262010-06-23 19:27:36 +0000315#
dandca321a2010-06-24 10:50:17 +0000316
317# This is designed to provoke a special case in the pager code:
318#
319# If an error (specifically, a FULL or IOERR error) occurs while writing a
320# dirty page to the file-system in order to free up memory, the pager enters
321# the "error state". An IO error causes SQLite to roll back the current
322# transaction (exiting the error state). A FULL error, however, may only
323# rollback the current statement.
324#
325# This block tests that nothing goes wrong if a FULL error occurs while
326# writing a dirty page out to free memory from within a statement that has
327# opened a statement transaction.
328#
dan346e4262010-06-23 19:27:36 +0000329do_test pagerfault-7-pre1 {
330 faultsim_delete_and_reopen
331 execsql {
332 CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
333 BEGIN;
334 INSERT INTO t2 VALUES(NULL, randomblob(1500));
335 INSERT INTO t2 VALUES(NULL, randomblob(1500));
336 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 4
337 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 8
338 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 16
339 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 32
340 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 64
341 COMMIT;
342 CREATE TABLE t1(a PRIMARY KEY, b);
343 INSERT INTO t1 SELECT * FROM t2;
344 DROP TABLE t2;
345 }
346 faultsim_save_and_close
347} {}
danec6ffc12010-06-24 19:16:06 +0000348do_faultsim_test pagerfault-7 -prep {
dan346e4262010-06-23 19:27:36 +0000349 faultsim_restore_and_reopen
350 execsql {
351 PRAGMA cache_size = 10;
352 BEGIN;
353 UPDATE t1 SET b = randomblob(1500);
354 }
355} -body {
356 execsql { UPDATE t1 SET a = 65, b = randomblob(1500) WHERE (a+1)>200 }
357 execsql COMMIT
358} -test {
359 faultsim_test_result {0 {}}
360 faultsim_integrity_check
361}
dan146ed782010-06-19 17:26:37 +0000362
dandca321a2010-06-24 10:50:17 +0000363do_test pagerfault-8-pre1 {
364 faultsim_delete_and_reopen
365 execsql {
366 PRAGMA auto_vacuum = 1;
367 CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
368 BEGIN;
369 INSERT INTO t1 VALUES(NULL, randomblob(1500));
370 INSERT INTO t1 VALUES(NULL, randomblob(1500));
371 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 4
372 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 8
373 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 16
374 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 32
375 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 64
376 COMMIT;
377 }
378 faultsim_save_and_close
379 set filesize [file size test.db]
380 set {} {}
381} {}
382do_test pagerfault-8-pre2 {
383 faultsim_restore_and_reopen
384 execsql { DELETE FROM t1 WHERE a>32 }
385 expr {[file size test.db] < $filesize}
386} {1}
dandca321a2010-06-24 10:50:17 +0000387do_faultsim_test pagerfault-8 -prep {
388 faultsim_restore_and_reopen
389 execsql {
390 BEGIN;
391 DELETE FROM t1 WHERE a>32;
392 }
393} -body {
394 execsql COMMIT
395} -test {
396 faultsim_test_result {0 {}}
397 faultsim_integrity_check
398}
399
dan0a6052e2010-06-24 13:24:26 +0000400do_test pagerfault-9-pre1 {
401 faultsim_delete_and_reopen
402 execsql {
403 PRAGMA auto_vacuum = incremental;
404 CREATE TABLE t1(x);
405 CREATE TABLE t2(y);
406 CREATE TABLE t3(z);
407
408 INSERT INTO t1 VALUES(randomblob(900));
409 INSERT INTO t1 VALUES(randomblob(900));
410 DELETE FROM t1;
411 }
412 faultsim_save_and_close
413} {}
414
danec6ffc12010-06-24 19:16:06 +0000415do_faultsim_test pagerfault-9 -prep {
dan0a6052e2010-06-24 13:24:26 +0000416 faultsim_restore_and_reopen
417 execsql {
418 BEGIN;
419 INSERT INTO t1 VALUES(randomblob(900));
420 INSERT INTO t1 VALUES(randomblob(900));
421 DROP TABLE t3;
422 DROP TABLE t2;
423 SAVEPOINT abc;
424 PRAGMA incremental_vacuum;
425 }
426} -body {
427 execsql {
428 ROLLBACK TO abc;
429 COMMIT;
430 PRAGMA freelist_count
431 }
432} -test {
433 faultsim_test_result {0 2}
434 faultsim_integrity_check
435
436 set sl [db one { SELECT COALESCE(sum(length(x)), 'null') FROM t1 }]
437 if {$sl!="null" && $sl!=1800} {
438 error "Content looks no good... ($sl)"
439 }
440}
441
danb0ac3e32010-06-16 10:55:42 +0000442finish_test