OLD | NEW |
| (Empty) |
1 # 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 | |
13 set testdir [file dirname $argv0] | |
14 source $testdir/tester.tcl | |
15 source $testdir/lock_common.tcl | |
16 source $testdir/malloc_common.tcl | |
17 | |
18 if {[permutation] == "inmemory_journal"} { | |
19 finish_test | |
20 return | |
21 } | |
22 | |
23 if {$::tcl_platform(platform)=="windows"} { | |
24 finish_test | |
25 return | |
26 } | |
27 | |
28 set a_string_counter 1 | |
29 proc a_string {n} { | |
30 global a_string_counter | |
31 incr a_string_counter | |
32 string range [string repeat "${a_string_counter}." $n] 1 $n | |
33 } | |
34 db func a_string a_string | |
35 | |
36 #------------------------------------------------------------------------- | |
37 # Test fault-injection while rolling back a hot-journal file. | |
38 # | |
39 do_test pagerfault-1-pre1 { | |
40 execsql { | |
41 PRAGMA journal_mode = DELETE; | |
42 PRAGMA cache_size = 10; | |
43 CREATE TABLE t1(a UNIQUE, b UNIQUE); | |
44 INSERT INTO t1 VALUES(a_string(200), a_string(300)); | |
45 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
46 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
47 BEGIN; | |
48 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; | |
49 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; | |
50 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; | |
51 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; | |
52 } | |
53 faultsim_save_and_close | |
54 } {} | |
55 do_faultsim_test pagerfault-1 -prep { | |
56 faultsim_restore_and_reopen | |
57 } -body { | |
58 execsql { SELECT count(*) FROM t1 } | |
59 } -test { | |
60 faultsim_test_result {0 4} | |
61 faultsim_integrity_check | |
62 if {[db one { SELECT count(*) FROM t1 }] != 4} { | |
63 error "Database content appears incorrect" | |
64 } | |
65 } | |
66 | |
67 #------------------------------------------------------------------------- | |
68 # Test fault-injection while rolling back a hot-journal file with a | |
69 # page-size different from the current value stored on page 1 of the | |
70 # database file. | |
71 # | |
72 do_test pagerfault-2-pre1 { | |
73 testvfs tv -default 1 | |
74 tv filter xSync | |
75 tv script xSyncCb | |
76 proc xSyncCb {filename args} { | |
77 if {[string match *journal filename]==0} faultsim_save | |
78 } | |
79 faultsim_delete_and_reopen | |
80 execsql { | |
81 PRAGMA page_size = 4096; | |
82 BEGIN; | |
83 CREATE TABLE abc(a, b, c); | |
84 INSERT INTO abc VALUES('o', 't', 't'); | |
85 INSERT INTO abc VALUES('f', 'f', 's'); | |
86 INSERT INTO abc SELECT * FROM abc; -- 4 | |
87 INSERT INTO abc SELECT * FROM abc; -- 8 | |
88 INSERT INTO abc SELECT * FROM abc; -- 16 | |
89 INSERT INTO abc SELECT * FROM abc; -- 32 | |
90 INSERT INTO abc SELECT * FROM abc; -- 64 | |
91 INSERT INTO abc SELECT * FROM abc; -- 128 | |
92 INSERT INTO abc SELECT * FROM abc; -- 256 | |
93 COMMIT; | |
94 PRAGMA page_size = 1024; | |
95 VACUUM; | |
96 } | |
97 db close | |
98 tv delete | |
99 } {} | |
100 do_faultsim_test pagerfault-2 -prep { | |
101 faultsim_restore_and_reopen | |
102 } -body { | |
103 execsql { SELECT * FROM abc } | |
104 } -test { | |
105 set answer [split [string repeat "ottffs" 128] ""] | |
106 faultsim_test_result [list 0 $answer] | |
107 faultsim_integrity_check | |
108 set res [db eval { SELECT * FROM abc }] | |
109 if {$res != $answer} { error "Database content appears incorrect ($res)" } | |
110 } | |
111 | |
112 #------------------------------------------------------------------------- | |
113 # Test fault-injection while rolling back hot-journals that were created | |
114 # as part of a multi-file transaction. | |
115 # | |
116 do_test pagerfault-3-pre1 { | |
117 testvfs tstvfs -default 1 | |
118 tstvfs filter xDelete | |
119 tstvfs script xDeleteCallback | |
120 | |
121 proc xDeleteCallback {method file args} { | |
122 set file [file tail $file] | |
123 if { [string match *mj* $file] } { faultsim_save } | |
124 } | |
125 | |
126 faultsim_delete_and_reopen | |
127 db func a_string a_string | |
128 | |
129 execsql { | |
130 ATTACH 'test.db2' AS aux; | |
131 PRAGMA journal_mode = DELETE; | |
132 PRAGMA main.cache_size = 10; | |
133 PRAGMA aux.cache_size = 10; | |
134 | |
135 CREATE TABLE t1(a UNIQUE, b UNIQUE); | |
136 CREATE TABLE aux.t2(a UNIQUE, b UNIQUE); | |
137 INSERT INTO t1 VALUES(a_string(200), a_string(300)); | |
138 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
139 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
140 INSERT INTO t2 SELECT * FROM t1; | |
141 | |
142 BEGIN; | |
143 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; | |
144 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; | |
145 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; | |
146 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; | |
147 REPLACE INTO t2 SELECT * FROM t1; | |
148 COMMIT; | |
149 } | |
150 | |
151 db close | |
152 tstvfs delete | |
153 } {} | |
154 do_faultsim_test pagerfault-3 -prep { | |
155 faultsim_restore_and_reopen | |
156 } -body { | |
157 execsql { | |
158 ATTACH 'test.db2' AS aux; | |
159 SELECT count(*) FROM t2; | |
160 SELECT count(*) FROM t1; | |
161 } | |
162 } -test { | |
163 faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}} | |
164 faultsim_integrity_check | |
165 catchsql { ATTACH 'test.db2' AS aux } | |
166 if {[db one { SELECT count(*) FROM t1 }] != 4 | |
167 || [db one { SELECT count(*) FROM t2 }] != 4 | |
168 } { | |
169 error "Database content appears incorrect" | |
170 } | |
171 } | |
172 | |
173 #------------------------------------------------------------------------- | |
174 # Test fault-injection as part of a vanilla, no-transaction, INSERT | |
175 # statement. | |
176 # | |
177 do_faultsim_test pagerfault-4 -prep { | |
178 faultsim_delete_and_reopen | |
179 } -body { | |
180 execsql { | |
181 CREATE TABLE x(y); | |
182 INSERT INTO x VALUES('z'); | |
183 SELECT * FROM x; | |
184 } | |
185 } -test { | |
186 faultsim_test_result {0 z} | |
187 faultsim_integrity_check | |
188 } | |
189 | |
190 #------------------------------------------------------------------------- | |
191 # Test fault-injection as part of a commit when using journal_mode=PERSIST. | |
192 # Three different cases: | |
193 # | |
194 # pagerfault-5.1: With no journal_size_limit configured. | |
195 # pagerfault-5.2: With a journal_size_limit configured. | |
196 # pagerfault-5.4: Multi-file transaction. One connection has a | |
197 # journal_size_limit of 0, the other has no limit. | |
198 # | |
199 do_test pagerfault-5-pre1 { | |
200 faultsim_delete_and_reopen | |
201 db func a_string a_string | |
202 execsql { | |
203 CREATE TABLE t1(a UNIQUE, b UNIQUE); | |
204 INSERT INTO t1 VALUES(a_string(200), a_string(300)); | |
205 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
206 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
207 } | |
208 faultsim_save_and_close | |
209 } {} | |
210 do_faultsim_test pagerfault-5.1 -prep { | |
211 faultsim_restore_and_reopen | |
212 db func a_string a_string | |
213 execsql { PRAGMA journal_mode = PERSIST } | |
214 } -body { | |
215 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } | |
216 } -test { | |
217 faultsim_test_result {0 {}} | |
218 faultsim_integrity_check | |
219 } | |
220 do_faultsim_test pagerfault-5.2 -prep { | |
221 faultsim_restore_and_reopen | |
222 db func a_string a_string | |
223 execsql { | |
224 PRAGMA journal_mode = PERSIST; | |
225 PRAGMA journal_size_limit = 2048; | |
226 } | |
227 } -body { | |
228 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } | |
229 } -test { | |
230 faultsim_test_result {0 {}} | |
231 faultsim_integrity_check | |
232 } | |
233 do_faultsim_test pagerfault-5.3 -faults oom-transient -prep { | |
234 faultsim_restore_and_reopen | |
235 db func a_string a_string | |
236 forcedelete test2.db test2.db-journal test2.db-wal | |
237 execsql { | |
238 PRAGMA journal_mode = PERSIST; | |
239 ATTACH 'test2.db' AS aux; | |
240 PRAGMA aux.journal_mode = PERSIST; | |
241 PRAGMA aux.journal_size_limit = 0; | |
242 } | |
243 } -body { | |
244 execsql { | |
245 BEGIN; | |
246 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; | |
247 CREATE TABLE aux.t2 AS SELECT * FROM t1; | |
248 COMMIT; | |
249 } | |
250 } -test { | |
251 faultsim_test_result {0 {}} | |
252 | |
253 catchsql { COMMIT } | |
254 catchsql { ROLLBACK } | |
255 | |
256 faultsim_integrity_check | |
257 set res "" | |
258 set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }] | |
259 if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"} | |
260 } | |
261 | |
262 #------------------------------------------------------------------------- | |
263 # Test fault-injection as part of a commit when using | |
264 # journal_mode=TRUNCATE. | |
265 # | |
266 do_test pagerfault-6-pre1 { | |
267 faultsim_delete_and_reopen | |
268 db func a_string a_string | |
269 execsql { | |
270 CREATE TABLE t1(a UNIQUE, b UNIQUE); | |
271 INSERT INTO t1 VALUES(a_string(200), a_string(300)); | |
272 } | |
273 faultsim_save_and_close | |
274 } {} | |
275 | |
276 do_faultsim_test pagerfault-6.1 -prep { | |
277 faultsim_restore_and_reopen | |
278 db func a_string a_string | |
279 execsql { PRAGMA journal_mode = TRUNCATE } | |
280 } -body { | |
281 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } | |
282 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } | |
283 } -test { | |
284 faultsim_test_result {0 {}} | |
285 faultsim_integrity_check | |
286 } | |
287 | |
288 # The unix vfs xAccess() method considers a file zero bytes in size to | |
289 # "not exist". This proc overrides that behaviour so that a zero length | |
290 # file is considered to exist. | |
291 # | |
292 proc xAccess {method filename op args} { | |
293 if {$op != "SQLITE_ACCESS_EXISTS"} { return "" } | |
294 return [file exists $filename] | |
295 } | |
296 do_faultsim_test pagerfault-6.2 -faults cantopen-* -prep { | |
297 shmfault filter xAccess | |
298 shmfault script xAccess | |
299 | |
300 faultsim_restore_and_reopen | |
301 db func a_string a_string | |
302 execsql { PRAGMA journal_mode = TRUNCATE } | |
303 } -body { | |
304 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } | |
305 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } | |
306 } -test { | |
307 faultsim_test_result {0 {}} | |
308 faultsim_integrity_check | |
309 } | |
310 | |
311 # The following was an attempt to get a bitvec malloc to fail. Didn't work. | |
312 # | |
313 # do_test pagerfault-6-pre1 { | |
314 # faultsim_delete_and_reopen | |
315 # execsql { | |
316 # CREATE TABLE t1(x, y, UNIQUE(x, y)); | |
317 # INSERT INTO t1 VALUES(1, randomblob(1501)); | |
318 # INSERT INTO t1 VALUES(2, randomblob(1502)); | |
319 # INSERT INTO t1 VALUES(3, randomblob(1503)); | |
320 # INSERT INTO t1 VALUES(4, randomblob(1504)); | |
321 # INSERT INTO t1 | |
322 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; | |
323 # INSERT INTO t1 | |
324 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; | |
325 # INSERT INTO t1 | |
326 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; | |
327 # INSERT INTO t1 | |
328 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; | |
329 # } | |
330 # faultsim_save_and_close | |
331 # } {} | |
332 # do_faultsim_test pagerfault-6 -prep { | |
333 # faultsim_restore_and_reopen | |
334 # } -body { | |
335 # execsql { | |
336 # BEGIN; | |
337 # UPDATE t1 SET x=x+4 WHERE x=1; | |
338 # SAVEPOINT one; | |
339 # UPDATE t1 SET x=x+4 WHERE x=2; | |
340 # SAVEPOINT three; | |
341 # UPDATE t1 SET x=x+4 WHERE x=3; | |
342 # SAVEPOINT four; | |
343 # UPDATE t1 SET x=x+4 WHERE x=4; | |
344 # RELEASE three; | |
345 # COMMIT; | |
346 # SELECT DISTINCT x FROM t1; | |
347 # } | |
348 # } -test { | |
349 # faultsim_test_result {0 {5 6 7 8}} | |
350 # faultsim_integrity_check | |
351 # } | |
352 # | |
353 | |
354 # This is designed to provoke a special case in the pager code: | |
355 # | |
356 # If an error (specifically, a FULL or IOERR error) occurs while writing a | |
357 # dirty page to the file-system in order to free up memory, the pager enters | |
358 # the "error state". An IO error causes SQLite to roll back the current | |
359 # transaction (exiting the error state). A FULL error, however, may only | |
360 # rollback the current statement. | |
361 # | |
362 # This block tests that nothing goes wrong if a FULL error occurs while | |
363 # writing a dirty page out to free memory from within a statement that has | |
364 # opened a statement transaction. | |
365 # | |
366 do_test pagerfault-7-pre1 { | |
367 faultsim_delete_and_reopen | |
368 execsql { | |
369 CREATE TABLE t2(a INTEGER PRIMARY KEY, b); | |
370 BEGIN; | |
371 INSERT INTO t2 VALUES(NULL, randomblob(1500)); | |
372 INSERT INTO t2 VALUES(NULL, randomblob(1500)); | |
373 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 4 | |
374 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 8 | |
375 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 16 | |
376 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 32 | |
377 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 64 | |
378 COMMIT; | |
379 CREATE TABLE t1(a PRIMARY KEY, b); | |
380 INSERT INTO t1 SELECT * FROM t2; | |
381 DROP TABLE t2; | |
382 } | |
383 faultsim_save_and_close | |
384 } {} | |
385 do_faultsim_test pagerfault-7 -prep { | |
386 faultsim_restore_and_reopen | |
387 execsql { | |
388 PRAGMA cache_size = 10; | |
389 BEGIN; | |
390 UPDATE t1 SET b = randomblob(1500); | |
391 } | |
392 } -body { | |
393 execsql { UPDATE t1 SET a = 65, b = randomblob(1500) WHERE (a+1)>200 } | |
394 execsql COMMIT | |
395 } -test { | |
396 faultsim_test_result {0 {}} | |
397 faultsim_integrity_check | |
398 } | |
399 | |
400 do_test pagerfault-8-pre1 { | |
401 faultsim_delete_and_reopen | |
402 execsql { | |
403 PRAGMA auto_vacuum = 1; | |
404 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); | |
405 BEGIN; | |
406 INSERT INTO t1 VALUES(NULL, randomblob(1500)); | |
407 INSERT INTO t1 VALUES(NULL, randomblob(1500)); | |
408 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 4 | |
409 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 8 | |
410 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 16 | |
411 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 32 | |
412 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 64 | |
413 COMMIT; | |
414 } | |
415 faultsim_save_and_close | |
416 set filesize [file size test.db] | |
417 set {} {} | |
418 } {} | |
419 do_test pagerfault-8-pre2 { | |
420 faultsim_restore_and_reopen | |
421 execsql { DELETE FROM t1 WHERE a>32 } | |
422 expr {[file size test.db] < $filesize} | |
423 } {1} | |
424 do_faultsim_test pagerfault-8 -prep { | |
425 faultsim_restore_and_reopen | |
426 execsql { | |
427 BEGIN; | |
428 DELETE FROM t1 WHERE a>32; | |
429 } | |
430 } -body { | |
431 execsql COMMIT | |
432 } -test { | |
433 faultsim_test_result {0 {}} | |
434 faultsim_integrity_check | |
435 } | |
436 | |
437 #------------------------------------------------------------------------- | |
438 # This test case is specially designed so that during a savepoint | |
439 # rollback, a new cache entry must be allocated (see comments surrounding | |
440 # the call to sqlite3PagerAcquire() from within pager_playback_one_page() | |
441 # for details). Test the effects of injecting an OOM at this point. | |
442 # | |
443 do_test pagerfault-9-pre1 { | |
444 faultsim_delete_and_reopen | |
445 execsql { | |
446 PRAGMA auto_vacuum = incremental; | |
447 CREATE TABLE t1(x); | |
448 CREATE TABLE t2(y); | |
449 CREATE TABLE t3(z); | |
450 | |
451 INSERT INTO t1 VALUES(randomblob(900)); | |
452 INSERT INTO t1 VALUES(randomblob(900)); | |
453 DELETE FROM t1; | |
454 } | |
455 faultsim_save_and_close | |
456 } {} | |
457 do_faultsim_test pagerfault-9.1 -prep { | |
458 faultsim_restore_and_reopen | |
459 execsql { | |
460 BEGIN; | |
461 INSERT INTO t1 VALUES(randomblob(900)); | |
462 INSERT INTO t1 VALUES(randomblob(900)); | |
463 DROP TABLE t3; | |
464 DROP TABLE t2; | |
465 SAVEPOINT abc; | |
466 PRAGMA incremental_vacuum; | |
467 } | |
468 } -body { | |
469 execsql { | |
470 ROLLBACK TO abc; | |
471 COMMIT; | |
472 PRAGMA freelist_count | |
473 } | |
474 } -test { | |
475 faultsim_test_result {0 2} | |
476 faultsim_integrity_check | |
477 | |
478 set sl [db one { SELECT COALESCE(sum(length(x)), 'null') FROM t1 }] | |
479 if {$sl!="null" && $sl!=1800} { | |
480 error "Content looks no good... ($sl)" | |
481 } | |
482 } | |
483 | |
484 #------------------------------------------------------------------------- | |
485 # Test fault injection with a temporary database file. | |
486 # | |
487 foreach v {a b} { | |
488 do_faultsim_test pagerfault-10$v -prep { | |
489 sqlite3 db "" | |
490 db func a_string a_string; | |
491 execsql { | |
492 PRAGMA cache_size = 10; | |
493 BEGIN; | |
494 CREATE TABLE xx(a, b, UNIQUE(a, b)); | |
495 INSERT INTO xx VALUES(a_string(200), a_string(200)); | |
496 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; | |
497 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; | |
498 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; | |
499 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; | |
500 COMMIT; | |
501 } | |
502 } -body { | |
503 execsql { UPDATE xx SET a = a_string(300) } | |
504 } -test { | |
505 faultsim_test_result {0 {}} | |
506 if {$::v == "b"} { execsql { PRAGMA journal_mode = TRUNCATE } } | |
507 faultsim_integrity_check | |
508 faultsim_integrity_check | |
509 } | |
510 } | |
511 | |
512 #------------------------------------------------------------------------- | |
513 # Test fault injection with transaction savepoints (savepoints created | |
514 # when a SAVEPOINT command is executed outside of any other savepoint | |
515 # or transaction context). | |
516 # | |
517 do_test pagerfault-9-pre1 { | |
518 faultsim_delete_and_reopen | |
519 db func a_string a_string; | |
520 execsql { | |
521 PRAGMA auto_vacuum = on; | |
522 CREATE TABLE t1(x UNIQUE); | |
523 CREATE TABLE t2(y UNIQUE); | |
524 CREATE TABLE t3(z UNIQUE); | |
525 BEGIN; | |
526 INSERT INTO t1 VALUES(a_string(202)); | |
527 INSERT INTO t2 VALUES(a_string(203)); | |
528 INSERT INTO t3 VALUES(a_string(204)); | |
529 INSERT INTO t1 SELECT a_string(202) FROM t1; | |
530 INSERT INTO t1 SELECT a_string(203) FROM t1; | |
531 INSERT INTO t1 SELECT a_string(204) FROM t1; | |
532 INSERT INTO t1 SELECT a_string(205) FROM t1; | |
533 INSERT INTO t2 SELECT a_string(length(x)) FROM t1; | |
534 INSERT INTO t3 SELECT a_string(length(x)) FROM t1; | |
535 COMMIT; | |
536 } | |
537 faultsim_save_and_close | |
538 } {} | |
539 do_faultsim_test pagerfault-11 -prep { | |
540 faultsim_restore_and_reopen | |
541 execsql { PRAGMA cache_size = 10 } | |
542 } -body { | |
543 execsql { | |
544 SAVEPOINT trans; | |
545 UPDATE t2 SET y = y||'2'; | |
546 INSERT INTO t3 SELECT * FROM t2; | |
547 DELETE FROM t1; | |
548 ROLLBACK TO trans; | |
549 UPDATE t1 SET x = x||'3'; | |
550 INSERT INTO t2 SELECT * FROM t1; | |
551 DELETE FROM t3; | |
552 RELEASE trans; | |
553 } | |
554 } -test { | |
555 faultsim_test_result {0 {}} | |
556 faultsim_integrity_check | |
557 } | |
558 | |
559 | |
560 #------------------------------------------------------------------------- | |
561 # Test fault injection when writing to a database file that resides on | |
562 # a file-system with a sector-size larger than the database page-size. | |
563 # | |
564 do_test pagerfault-12-pre1 { | |
565 testvfs ss_layer -default 1 | |
566 ss_layer sectorsize 4096 | |
567 faultsim_delete_and_reopen | |
568 db func a_string a_string; | |
569 | |
570 execsql { | |
571 PRAGMA page_size = 1024; | |
572 PRAGMA journal_mode = PERSIST; | |
573 PRAGMA cache_size = 10; | |
574 BEGIN; | |
575 CREATE TABLE t1(x, y UNIQUE); | |
576 INSERT INTO t1 VALUES(a_string(333), a_string(444)); | |
577 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; | |
578 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; | |
579 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; | |
580 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; | |
581 INSERT INTO t1 SELECT a_string(44), a_string(55) FROM t1 LIMIT 13; | |
582 COMMIT; | |
583 } | |
584 faultsim_save_and_close | |
585 } {} | |
586 | |
587 do_faultsim_test pagerfault-12a -prep { | |
588 faultsim_restore_and_reopen | |
589 execsql { PRAGMA cache_size = 10 } | |
590 db func a_string a_string; | |
591 } -body { | |
592 execsql { | |
593 UPDATE t1 SET x = a_string(length(x)), y = a_string(length(y)); | |
594 } | |
595 } -test { | |
596 faultsim_test_result {0 {}} | |
597 faultsim_integrity_check | |
598 } | |
599 | |
600 do_test pagerfault-12-pre2 { | |
601 faultsim_restore_and_reopen | |
602 execsql { | |
603 CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 10; | |
604 } | |
605 faultsim_save_and_close | |
606 } {} | |
607 do_faultsim_test pagerfault-12b -prep { | |
608 faultsim_restore_and_reopen | |
609 db func a_string a_string; | |
610 execsql { SELECT * FROM t1 } | |
611 } -body { | |
612 set sql(1) { UPDATE t2 SET x = a_string(280) } | |
613 set sql(2) { UPDATE t1 SET x = a_string(280) WHERE rowid = 5 } | |
614 | |
615 db eval { SELECT rowid FROM t1 LIMIT 2 } { db eval $sql($rowid) } | |
616 | |
617 } -test { | |
618 faultsim_test_result {0 {}} | |
619 faultsim_integrity_check | |
620 } | |
621 | |
622 catch { db close } | |
623 ss_layer delete | |
624 | |
625 | |
626 #------------------------------------------------------------------------- | |
627 # Test fault injection when SQLite opens a database where the size of the | |
628 # database file is zero bytes but the accompanying journal file is larger | |
629 # than that. In this scenario SQLite should delete the journal file | |
630 # without rolling it back, even if it is in all other respects a valid | |
631 # hot-journal file. | |
632 # | |
633 do_test pagerfault-13-pre1 { | |
634 faultsim_delete_and_reopen | |
635 db func a_string a_string; | |
636 execsql { | |
637 PRAGMA journal_mode = PERSIST; | |
638 BEGIN; | |
639 CREATE TABLE t1(x, y UNIQUE); | |
640 INSERT INTO t1 VALUES(a_string(333), a_string(444)); | |
641 COMMIT; | |
642 } | |
643 db close | |
644 forcedelete test.db | |
645 faultsim_save | |
646 } {} | |
647 do_faultsim_test pagerfault-13 -prep { | |
648 faultsim_restore_and_reopen | |
649 } -body { | |
650 execsql { CREATE TABLE xx(a, b) } | |
651 } -test { | |
652 faultsim_test_result {0 {}} | |
653 } | |
654 | |
655 #--------------------------------------------------------------------------- | |
656 # Test fault injection into a small backup operation. | |
657 # | |
658 do_test pagerfault-14-pre1 { | |
659 faultsim_delete_and_reopen | |
660 db func a_string a_string; | |
661 execsql { | |
662 PRAGMA journal_mode = PERSIST; | |
663 ATTACH 'test.db2' AS two; | |
664 BEGIN; | |
665 CREATE TABLE t1(x, y UNIQUE); | |
666 CREATE TABLE two.t2(x, y UNIQUE); | |
667 INSERT INTO t1 VALUES(a_string(333), a_string(444)); | |
668 INSERT INTO t2 VALUES(a_string(333), a_string(444)); | |
669 COMMIT; | |
670 } | |
671 faultsim_save_and_close | |
672 } {} | |
673 | |
674 do_faultsim_test pagerfault-14a -prep { | |
675 faultsim_restore_and_reopen | |
676 } -body { | |
677 if {[catch {db backup test.db2} msg]} { error [regsub {.*: } $msg {}] } | |
678 } -test { | |
679 faultsim_test_result {0 {}} {1 {}} {1 {SQL logic error or missing database}} | |
680 } | |
681 | |
682 # If TEMP_STORE is 2 or greater, then the database [db2] will be created | |
683 # as an in-memory database. This test will not work in that case, as it | |
684 # is not possible to change the page-size of an in-memory database. Even | |
685 # using the backup API. | |
686 # | |
687 if {$TEMP_STORE<2} { | |
688 do_faultsim_test pagerfault-14b -prep { | |
689 catch { db2 close } | |
690 faultsim_restore_and_reopen | |
691 sqlite3 db2 "" | |
692 db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) } | |
693 } -body { | |
694 sqlite3_backup B db2 main db main | |
695 B step 200 | |
696 set rc [B finish] | |
697 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} | |
698 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } | |
699 set {} {} | |
700 } -test { | |
701 faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}} | |
702 } | |
703 } | |
704 | |
705 do_faultsim_test pagerfault-14c -prep { | |
706 catch { db2 close } | |
707 faultsim_restore_and_reopen | |
708 sqlite3 db2 test.db2 | |
709 db2 eval { | |
710 PRAGMA synchronous = off; | |
711 PRAGMA page_size = 4096; | |
712 CREATE TABLE xx(a); | |
713 } | |
714 } -body { | |
715 sqlite3_backup B db2 main db main | |
716 B step 200 | |
717 set rc [B finish] | |
718 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} | |
719 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } | |
720 set {} {} | |
721 } -test { | |
722 faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}} | |
723 } | |
724 | |
725 do_test pagerfault-15-pre1 { | |
726 faultsim_delete_and_reopen | |
727 db func a_string a_string; | |
728 execsql { | |
729 BEGIN; | |
730 CREATE TABLE t1(x, y UNIQUE); | |
731 INSERT INTO t1 VALUES(a_string(11), a_string(22)); | |
732 INSERT INTO t1 VALUES(a_string(11), a_string(22)); | |
733 COMMIT; | |
734 } | |
735 faultsim_save_and_close | |
736 } {} | |
737 do_faultsim_test pagerfault-15 -prep { | |
738 faultsim_restore_and_reopen | |
739 db func a_string a_string; | |
740 } -body { | |
741 db eval { SELECT * FROM t1 LIMIT 1 } { | |
742 execsql { | |
743 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; | |
744 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; | |
745 } | |
746 } | |
747 } -test { | |
748 faultsim_test_result {0 {}} | |
749 faultsim_integrity_check | |
750 } | |
751 | |
752 | |
753 do_test pagerfault-16-pre1 { | |
754 faultsim_delete_and_reopen | |
755 execsql { CREATE TABLE t1(x, y UNIQUE) } | |
756 faultsim_save_and_close | |
757 } {} | |
758 do_faultsim_test pagerfault-16 -prep { | |
759 faultsim_restore_and_reopen | |
760 } -body { | |
761 execsql { | |
762 PRAGMA locking_mode = exclusive; | |
763 PRAGMA journal_mode = wal; | |
764 INSERT INTO t1 VALUES(1, 2); | |
765 INSERT INTO t1 VALUES(3, 4); | |
766 PRAGMA journal_mode = delete; | |
767 INSERT INTO t1 VALUES(4, 5); | |
768 PRAGMA journal_mode = wal; | |
769 INSERT INTO t1 VALUES(6, 7); | |
770 PRAGMA journal_mode = persist; | |
771 INSERT INTO t1 VALUES(8, 9); | |
772 } | |
773 } -test { | |
774 faultsim_test_result {0 {exclusive wal delete wal persist}} | |
775 faultsim_integrity_check | |
776 } | |
777 | |
778 | |
779 #------------------------------------------------------------------------- | |
780 # Test fault injection while changing into and out of WAL mode. | |
781 # | |
782 do_test pagerfault-17-pre1 { | |
783 faultsim_delete_and_reopen | |
784 execsql { | |
785 CREATE TABLE t1(a PRIMARY KEY, b); | |
786 INSERT INTO t1 VALUES(1862, 'Botha'); | |
787 INSERT INTO t1 VALUES(1870, 'Smuts'); | |
788 INSERT INTO t1 VALUES(1866, 'Hertzog'); | |
789 } | |
790 faultsim_save_and_close | |
791 } {} | |
792 do_faultsim_test pagerfault-17a -prep { | |
793 faultsim_restore_and_reopen | |
794 } -body { | |
795 execsql { | |
796 PRAGMA journal_mode = wal; | |
797 PRAGMA journal_mode = delete; | |
798 } | |
799 } -test { | |
800 faultsim_test_result {0 {wal delete}} | |
801 faultsim_integrity_check | |
802 } | |
803 do_faultsim_test pagerfault-17b -prep { | |
804 faultsim_restore_and_reopen | |
805 execsql { PRAGMA synchronous = OFF } | |
806 } -body { | |
807 execsql { | |
808 PRAGMA journal_mode = wal; | |
809 INSERT INTO t1 VALUES(22, 'Clarke'); | |
810 PRAGMA journal_mode = delete; | |
811 } | |
812 } -test { | |
813 faultsim_test_result {0 {wal delete}} | |
814 faultsim_integrity_check | |
815 } | |
816 do_faultsim_test pagerfault-17c -prep { | |
817 faultsim_restore_and_reopen | |
818 execsql { | |
819 PRAGMA locking_mode = exclusive; | |
820 PRAGMA journal_mode = wal; | |
821 } | |
822 } -body { | |
823 execsql { PRAGMA journal_mode = delete } | |
824 } -test { | |
825 faultsim_test_result {0 delete} | |
826 faultsim_integrity_check | |
827 } | |
828 do_faultsim_test pagerfault-17d -prep { | |
829 catch { db2 close } | |
830 faultsim_restore_and_reopen | |
831 sqlite3 db2 test.db | |
832 execsql { PRAGMA journal_mode = delete } | |
833 execsql { PRAGMA journal_mode = wal } | |
834 execsql { INSERT INTO t1 VALUES(99, 'Bradman') } db2 | |
835 } -body { | |
836 execsql { PRAGMA journal_mode = delete } | |
837 } -test { | |
838 faultsim_test_result {1 {database is locked}} | |
839 faultsim_integrity_check | |
840 } | |
841 do_faultsim_test pagerfault-17e -prep { | |
842 catch { db2 close } | |
843 faultsim_restore_and_reopen | |
844 sqlite3 db2 test.db | |
845 execsql { PRAGMA journal_mode = delete } | |
846 execsql { PRAGMA journal_mode = wal } | |
847 set ::chan [launch_testfixture] | |
848 testfixture $::chan { | |
849 sqlite3 db test.db | |
850 db eval { INSERT INTO t1 VALUES(101, 'Latham') } | |
851 } | |
852 catch { testfixture $::chan sqlite_abort } | |
853 catch { close $::chan } | |
854 } -body { | |
855 execsql { PRAGMA journal_mode = delete } | |
856 } -test { | |
857 faultsim_test_result {0 delete} | |
858 faultsim_integrity_check | |
859 } | |
860 | |
861 #------------------------------------------------------------------------- | |
862 # Test fault-injection when changing from journal_mode=persist to | |
863 # journal_mode=delete (this involves deleting the journal file). | |
864 # | |
865 do_test pagerfault-18-pre1 { | |
866 faultsim_delete_and_reopen | |
867 execsql { | |
868 CREATE TABLE qq(x); | |
869 INSERT INTO qq VALUES('Herbert'); | |
870 INSERT INTO qq VALUES('Macalister'); | |
871 INSERT INTO qq VALUES('Mackenzie'); | |
872 INSERT INTO qq VALUES('Lilley'); | |
873 INSERT INTO qq VALUES('Palmer'); | |
874 } | |
875 faultsim_save_and_close | |
876 } {} | |
877 do_faultsim_test pagerfault-18 -prep { | |
878 faultsim_restore_and_reopen | |
879 execsql { | |
880 PRAGMA journal_mode = PERSIST; | |
881 INSERT INTO qq VALUES('Beatty'); | |
882 } | |
883 } -body { | |
884 execsql { PRAGMA journal_mode = delete } | |
885 } -test { | |
886 faultsim_test_result {0 delete} | |
887 faultsim_integrity_check | |
888 } | |
889 | |
890 do_faultsim_test pagerfault-19a -prep { | |
891 sqlite3 db :memory: | |
892 db func a_string a_string | |
893 execsql { | |
894 PRAGMA auto_vacuum = FULL; | |
895 BEGIN; | |
896 CREATE TABLE t1(a, b); | |
897 INSERT INTO t1 VALUES(a_string(5000), a_string(6000)); | |
898 COMMIT; | |
899 } | |
900 } -body { | |
901 execsql { | |
902 CREATE TABLE t2(a, b); | |
903 INSERT INTO t2 SELECT * FROM t1; | |
904 DELETE FROM t1; | |
905 } | |
906 } -test { | |
907 faultsim_test_result {0 {}} | |
908 } | |
909 | |
910 do_test pagerfault-19-pre1 { | |
911 faultsim_delete_and_reopen | |
912 execsql { | |
913 PRAGMA auto_vacuum = FULL; | |
914 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); | |
915 CREATE TABLE t2(x); INSERT INTO t2 VALUES(2); | |
916 CREATE TABLE t3(x); INSERT INTO t3 VALUES(3); | |
917 CREATE TABLE t4(x); INSERT INTO t4 VALUES(4); | |
918 CREATE TABLE t5(x); INSERT INTO t5 VALUES(5); | |
919 CREATE TABLE t6(x); INSERT INTO t6 VALUES(6); | |
920 } | |
921 faultsim_save_and_close | |
922 } {} | |
923 do_faultsim_test pagerfault-19b -prep { | |
924 faultsim_restore_and_reopen | |
925 } -body { | |
926 execsql { | |
927 BEGIN; | |
928 UPDATE t4 SET x = x+1; | |
929 UPDATE t6 SET x = x+1; | |
930 SAVEPOINT one; | |
931 UPDATE t3 SET x = x+1; | |
932 SAVEPOINT two; | |
933 DROP TABLE t2; | |
934 ROLLBACK TO one; | |
935 COMMIT; | |
936 SELECT * FROM t3; | |
937 SELECT * FROM t4; | |
938 SELECT * FROM t6; | |
939 } | |
940 } -test { | |
941 faultsim_test_result {0 {3 5 7}} | |
942 } | |
943 | |
944 #------------------------------------------------------------------------- | |
945 # This tests fault-injection in a special case in the auto-vacuum code. | |
946 # | |
947 do_test pagerfault-20-pre1 { | |
948 faultsim_delete_and_reopen | |
949 execsql { | |
950 PRAGMA cache_size = 10; | |
951 PRAGMA auto_vacuum = FULL; | |
952 CREATE TABLE t0(a, b); | |
953 } | |
954 faultsim_save_and_close | |
955 } {} | |
956 do_faultsim_test pagerfault-20 -prep { | |
957 faultsim_restore_and_reopen | |
958 } -body { | |
959 execsql { | |
960 BEGIN; | |
961 CREATE TABLE t1(a, b); | |
962 CREATE TABLE t2(a, b); | |
963 DROP TABLE t1; | |
964 COMMIT; | |
965 } | |
966 } -test { | |
967 faultsim_test_result {0 {}} | |
968 } | |
969 | |
970 do_test pagerfault-21-pre1 { | |
971 faultsim_delete_and_reopen | |
972 execsql { | |
973 PRAGMA cache_size = 10; | |
974 CREATE TABLE t0(a PRIMARY KEY, b); | |
975 INSERT INTO t0 VALUES(1, 2); | |
976 } | |
977 faultsim_save_and_close | |
978 } {} | |
979 do_faultsim_test pagerfault-21 -prep { | |
980 faultsim_restore_and_reopen | |
981 } -body { | |
982 db eval { SELECT * FROM t0 LIMIT 1 } { | |
983 db eval { INSERT INTO t0 SELECT a+1, b FROM t0 } | |
984 db eval { INSERT INTO t0 SELECT a+2, b FROM t0 } | |
985 } | |
986 } -test { | |
987 faultsim_test_result {0 {}} | |
988 } | |
989 | |
990 | |
991 #------------------------------------------------------------------------- | |
992 # Test fault-injection and rollback when the nReserve header value | |
993 # is non-zero. | |
994 # | |
995 do_test pagerfault-21-pre1 { | |
996 faultsim_delete_and_reopen | |
997 execsql { | |
998 PRAGMA page_size = 1024; | |
999 PRAGMA journal_mode = WAL; | |
1000 PRAGMA journal_mode = DELETE; | |
1001 } | |
1002 db close | |
1003 hexio_write test.db 20 10 | |
1004 hexio_write test.db 105 03F0 | |
1005 sqlite3 db test.db | |
1006 db func a_string a_string | |
1007 execsql { | |
1008 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); | |
1009 INSERT INTO t0 VALUES(a_string(222), a_string(333)); | |
1010 INSERT INTO t0 VALUES(a_string(223), a_string(334)); | |
1011 INSERT INTO t0 VALUES(a_string(224), a_string(335)); | |
1012 INSERT INTO t0 VALUES(a_string(225), a_string(336)); | |
1013 } | |
1014 faultsim_save_and_close | |
1015 } {} | |
1016 | |
1017 do_faultsim_test pagerfault-21 -prep { | |
1018 faultsim_restore_and_reopen | |
1019 } -body { | |
1020 execsql { INSERT INTO t0 SELECT a||'x', b||'x' FROM t0 } | |
1021 } -test { | |
1022 faultsim_test_result {0 {}} | |
1023 faultsim_integrity_check | |
1024 } | |
1025 ifcapable crashtest { | |
1026 faultsim_delete_and_reopen | |
1027 execsql { | |
1028 PRAGMA page_size = 1024; | |
1029 PRAGMA journal_mode = WAL; | |
1030 PRAGMA journal_mode = DELETE; | |
1031 } | |
1032 db close | |
1033 hexio_write test.db 20 10 | |
1034 hexio_write test.db 105 03F0 | |
1035 | |
1036 sqlite3 db test.db | |
1037 db func a_string a_string | |
1038 execsql { | |
1039 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); | |
1040 INSERT INTO t0 VALUES(a_string(222), a_string(333)); | |
1041 INSERT INTO t0 VALUES(a_string(223), a_string(334)); | |
1042 } | |
1043 faultsim_save_and_close | |
1044 | |
1045 for {set iTest 1} {$iTest<50} {incr iTest} { | |
1046 do_test pagerfault-21.crash.$iTest.1 { | |
1047 crashsql -delay 1 -file test.db -seed $iTest { | |
1048 BEGIN; | |
1049 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); | |
1050 INSERT INTO t1 SELECT a, b FROM t0; | |
1051 COMMIT; | |
1052 } | |
1053 } {1 {child process exited abnormally}} | |
1054 do_test pagerfault-22.$iTest.2 { | |
1055 sqlite3 db test.db | |
1056 execsql { PRAGMA integrity_check } | |
1057 } {ok} | |
1058 db close | |
1059 } | |
1060 } | |
1061 | |
1062 | |
1063 #------------------------------------------------------------------------- | |
1064 # When a 3.7.0 client opens a write-transaction on a database file that | |
1065 # has been appended to or truncated by a pre-370 client, it updates | |
1066 # the db-size in the file header immediately. This test case provokes | |
1067 # errors during that operation. | |
1068 # | |
1069 do_test pagerfault-22-pre1 { | |
1070 faultsim_delete_and_reopen | |
1071 db func a_string a_string | |
1072 execsql { | |
1073 PRAGMA page_size = 1024; | |
1074 PRAGMA auto_vacuum = 0; | |
1075 CREATE TABLE t1(a); | |
1076 CREATE INDEX i1 ON t1(a); | |
1077 INSERT INTO t1 VALUES(a_string(3000)); | |
1078 CREATE TABLE t2(a); | |
1079 INSERT INTO t2 VALUES(1); | |
1080 } | |
1081 db close | |
1082 sql36231 { INSERT INTO t1 VALUES(a_string(3000)) } | |
1083 faultsim_save_and_close | |
1084 } {} | |
1085 do_faultsim_test pagerfault-22 -prep { | |
1086 faultsim_restore_and_reopen | |
1087 } -body { | |
1088 execsql { INSERT INTO t2 VALUES(2) } | |
1089 execsql { SELECT * FROM t2 } | |
1090 } -test { | |
1091 faultsim_test_result {0 {1 2}} | |
1092 faultsim_integrity_check | |
1093 } | |
1094 | |
1095 #------------------------------------------------------------------------- | |
1096 # Provoke an OOM error during a commit of multi-file transaction. One of | |
1097 # the databases written during the transaction is an in-memory database. | |
1098 # This test causes rollback of the in-memory database after CommitPhaseOne() | |
1099 # has successfully returned. i.e. the series of calls for the aborted commit | |
1100 # is: | |
1101 # | |
1102 # PagerCommitPhaseOne(<in-memory-db>) -> SQLITE_OK | |
1103 # PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR | |
1104 # PagerRollback(<in-memory-db>) | |
1105 # PagerRollback(<file-db>) | |
1106 # | |
1107 do_faultsim_test pagerfault-23 -prep { | |
1108 sqlite3 db :memory: | |
1109 foreach f [glob -nocomplain test.db*] { forcedelete $f } | |
1110 db eval { | |
1111 ATTACH 'test.db2' AS aux; | |
1112 CREATE TABLE t1(a, b); | |
1113 CREATE TABLE aux.t2(a, b); | |
1114 } | |
1115 } -body { | |
1116 execsql { | |
1117 BEGIN; | |
1118 INSERT INTO t1 VALUES(1,2); | |
1119 INSERT INTO t2 VALUES(3,4); | |
1120 COMMIT; | |
1121 } | |
1122 } -test { | |
1123 faultsim_test_result {0 {}} | |
1124 faultsim_integrity_check | |
1125 } | |
1126 | |
1127 do_faultsim_test pagerfault-24 -prep { | |
1128 faultsim_delete_and_reopen | |
1129 db eval { PRAGMA temp_store = file } | |
1130 execsql { CREATE TABLE x(a, b) } | |
1131 } -body { | |
1132 execsql { CREATE TEMP TABLE t1(a, b) } | |
1133 } -test { | |
1134 faultsim_test_result {0 {}} \ | |
1135 {1 {unable to open a temporary database file for storing temporary tables}} | |
1136 set ic [db eval { PRAGMA temp.integrity_check }] | |
1137 if {$ic != "ok"} { error "Integrity check: $ic" } | |
1138 } | |
1139 | |
1140 proc lockrows {n} { | |
1141 if {$n==0} { return "" } | |
1142 db eval { SELECT * FROM t1 WHERE oid = $n } { | |
1143 return [lockrows [expr {$n-1}]] | |
1144 } | |
1145 } | |
1146 | |
1147 | |
1148 do_test pagerfault-25-pre1 { | |
1149 faultsim_delete_and_reopen | |
1150 db func a_string a_string | |
1151 execsql { | |
1152 PRAGMA page_size = 1024; | |
1153 PRAGMA auto_vacuum = 0; | |
1154 CREATE TABLE t1(a); | |
1155 INSERT INTO t1 VALUES(a_string(500)); | |
1156 INSERT INTO t1 SELECT a_string(500) FROM t1; | |
1157 INSERT INTO t1 SELECT a_string(500) FROM t1; | |
1158 INSERT INTO t1 SELECT a_string(500) FROM t1; | |
1159 INSERT INTO t1 SELECT a_string(500) FROM t1; | |
1160 INSERT INTO t1 SELECT a_string(500) FROM t1; | |
1161 } | |
1162 faultsim_save_and_close | |
1163 } {} | |
1164 do_faultsim_test pagerfault-25 -prep { | |
1165 faultsim_restore_and_reopen | |
1166 db func a_string a_string | |
1167 set ::channel [db incrblob -readonly t1 a 1] | |
1168 execsql { | |
1169 PRAGMA cache_size = 10; | |
1170 BEGIN; | |
1171 INSERT INTO t1 VALUES(a_string(3000)); | |
1172 INSERT INTO t1 VALUES(a_string(3000)); | |
1173 } | |
1174 } -body { | |
1175 lockrows 30 | |
1176 } -test { | |
1177 catch { lockrows 30 } | |
1178 catch { db eval COMMIT } | |
1179 close $::channel | |
1180 faultsim_test_result {0 {}} | |
1181 } | |
1182 | |
1183 do_faultsim_test pagerfault-26 -prep { | |
1184 faultsim_delete_and_reopen | |
1185 execsql { | |
1186 PRAGMA page_size = 1024; | |
1187 PRAGMA journal_mode = truncate; | |
1188 PRAGMA auto_vacuum = full; | |
1189 PRAGMA locking_mode=exclusive; | |
1190 CREATE TABLE t1(a, b); | |
1191 INSERT INTO t1 VALUES(1, 2); | |
1192 PRAGMA page_size = 4096; | |
1193 } | |
1194 } -body { | |
1195 execsql { | |
1196 VACUUM; | |
1197 } | |
1198 } -test { | |
1199 faultsim_test_result {0 {}} | |
1200 | |
1201 set contents [db eval {SELECT * FROM t1}] | |
1202 if {$contents != "1 2"} { error "Bad database contents ($contents)" } | |
1203 | |
1204 set sz [file size test.db] | |
1205 if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { | |
1206 error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes" | |
1207 } | |
1208 if {$testrc==0 && $sz!=4096*3} { | |
1209 error "Expected file size to be 12288 bytes - actual size $sz bytes" | |
1210 } | |
1211 } | |
1212 | |
1213 do_test pagerfault-27-pre { | |
1214 faultsim_delete_and_reopen | |
1215 db func a_string a_string | |
1216 execsql { | |
1217 PRAGMA page_size = 1024; | |
1218 CREATE TABLE t1(a, b); | |
1219 CREATE TABLE t2(a UNIQUE, b UNIQUE); | |
1220 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); | |
1221 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1222 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1223 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1224 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1225 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1226 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1227 INSERT INTO t1 VALUES (a_string(20000), a_string(20000)); | |
1228 } | |
1229 faultsim_save_and_close | |
1230 } {} | |
1231 do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep { | |
1232 faultsim_restore_and_reopen | |
1233 db func a_string a_string | |
1234 execsql { | |
1235 PRAGMA cache_size = 10; | |
1236 BEGIN EXCLUSIVE; | |
1237 } | |
1238 set ::channel [db incrblob t1 a 1] | |
1239 } -body { | |
1240 puts $::channel [string repeat abc 6000] | |
1241 flush $::channel | |
1242 } -test { | |
1243 catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) } | |
1244 catch { close $::channel } | |
1245 catchsql { ROLLBACK } | |
1246 faultsim_integrity_check | |
1247 } | |
1248 | |
1249 | |
1250 #------------------------------------------------------------------------- | |
1251 # | |
1252 do_test pagerfault-28-pre { | |
1253 faultsim_delete_and_reopen | |
1254 db func a_string a_string | |
1255 execsql { | |
1256 PRAGMA page_size = 512; | |
1257 | |
1258 PRAGMA journal_mode = wal; | |
1259 PRAGMA wal_autocheckpoint = 0; | |
1260 PRAGMA cache_size = 100000; | |
1261 | |
1262 BEGIN; | |
1263 CREATE TABLE t2(a UNIQUE, b UNIQUE); | |
1264 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); | |
1265 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1266 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1267 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1268 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1269 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1270 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1271 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1272 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1273 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1274 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1275 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1276 COMMIT; | |
1277 CREATE TABLE t1(a PRIMARY KEY, b); | |
1278 } | |
1279 expr {[file size test.db-shm] >= 96*1024} | |
1280 } {1} | |
1281 faultsim_save_and_close | |
1282 | |
1283 do_faultsim_test pagerfault-28a -faults oom* -prep { | |
1284 faultsim_restore_and_reopen | |
1285 execsql { PRAGMA mmap_size=0 } | |
1286 | |
1287 sqlite3 db2 test.db | |
1288 db2 eval { SELECT count(*) FROM t2 } | |
1289 | |
1290 db func a_string a_string | |
1291 execsql { | |
1292 BEGIN; | |
1293 INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); | |
1294 INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); | |
1295 } | |
1296 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY] | |
1297 sqlite3_step $::STMT | |
1298 } -body { | |
1299 execsql { ROLLBACK } | |
1300 } -test { | |
1301 db2 close | |
1302 sqlite3_finalize $::STMT | |
1303 catchsql { ROLLBACK } | |
1304 faultsim_integrity_check | |
1305 } | |
1306 | |
1307 faultsim_restore_and_reopen | |
1308 sqlite3 db2 test.db | |
1309 db2 eval {SELECT count(*) FROM t2} | |
1310 db close | |
1311 | |
1312 do_faultsim_test pagerfault-28b -faults oom* -prep { | |
1313 sqlite3 db test.db | |
1314 } -body { | |
1315 execsql { SELECT count(*) FROM t2 } | |
1316 } -test { | |
1317 faultsim_test_result {0 2048} | |
1318 db close | |
1319 } | |
1320 | |
1321 db2 close | |
1322 | |
1323 #------------------------------------------------------------------------- | |
1324 # Try this: | |
1325 # | |
1326 # 1) Put the pager in ERROR state (error during rollback) | |
1327 # | |
1328 # 2) Next time the connection is used inject errors into all xWrite() and | |
1329 # xUnlock() calls. This causes the hot-journal rollback to fail and | |
1330 # the pager to declare its locking state UNKNOWN. | |
1331 # | |
1332 # 3) Same again. | |
1333 # | |
1334 # 4a) Stop injecting errors. Allow the rollback to succeed. Check that | |
1335 # the database is Ok. Or, | |
1336 # | |
1337 # 4b) Close and reopen the db. Check that the db is Ok. | |
1338 # | |
1339 proc custom_injectinstall {} { | |
1340 testvfs custom -default true | |
1341 custom filter {xWrite xUnlock} | |
1342 } | |
1343 proc custom_injectuninstall {} { | |
1344 catch {db close} | |
1345 catch {db2 close} | |
1346 custom delete | |
1347 } | |
1348 proc custom_injectstart {iFail} { | |
1349 custom ioerr $iFail 1 | |
1350 } | |
1351 proc custom_injectstop {} { | |
1352 custom ioerr | |
1353 } | |
1354 set ::FAULTSIM(custom) [list \ | |
1355 -injectinstall custom_injectinstall \ | |
1356 -injectstart custom_injectstart \ | |
1357 -injectstop custom_injectstop \ | |
1358 -injecterrlist {{1 {disk I/O error}}} \ | |
1359 -injectuninstall custom_injectuninstall \ | |
1360 ] | |
1361 | |
1362 do_test pagerfault-29-pre { | |
1363 faultsim_delete_and_reopen | |
1364 db func a_string a_string | |
1365 execsql { | |
1366 PRAGMA page_size = 1024; | |
1367 PRAGMA cache_size = 5; | |
1368 | |
1369 BEGIN; | |
1370 CREATE TABLE t2(a UNIQUE, b UNIQUE); | |
1371 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); | |
1372 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1373 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1374 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1375 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; | |
1376 COMMIT; | |
1377 } | |
1378 expr {[file size test.db] >= 50*1024} | |
1379 } {1} | |
1380 faultsim_save_and_close | |
1381 foreach {tn tt} { | |
1382 29 { catchsql ROLLBACK } | |
1383 30 { db close ; sqlite3 db test.db } | |
1384 } { | |
1385 do_faultsim_test pagerfault-$tn -faults custom -prep { | |
1386 faultsim_restore_and_reopen | |
1387 db func a_string a_string | |
1388 execsql { | |
1389 PRAGMA cache_size = 5; | |
1390 BEGIN; | |
1391 UPDATE t2 SET a = a_string(799); | |
1392 } | |
1393 } -body { | |
1394 catchsql ROLLBACK | |
1395 catchsql ROLLBACK | |
1396 catchsql ROLLBACK | |
1397 } -test { | |
1398 eval $::tt | |
1399 if {"ok" != [db one {PRAGMA integrity_check}]} { | |
1400 error "integrity check failed" | |
1401 } | |
1402 } | |
1403 } | |
1404 | |
1405 do_test pagerfault-31-pre { | |
1406 sqlite3_shutdown | |
1407 sqlite3_config_uri 1 | |
1408 } {SQLITE_OK} | |
1409 do_faultsim_test pagerfault-31 -faults oom* -body { | |
1410 sqlite3 db {file:one?mode=memory&cache=shared} | |
1411 db eval { | |
1412 CREATE TABLE t1(x); | |
1413 INSERT INTO t1 VALUES(1); | |
1414 SELECT * FROM t1; | |
1415 } | |
1416 } -test { | |
1417 faultsim_test_result {0 1} {1 {}} | |
1418 catch { db close } | |
1419 } | |
1420 sqlite3_shutdown | |
1421 sqlite3_config_uri 0 | |
1422 | |
1423 do_test pagerfault-32-pre { | |
1424 reset_db | |
1425 execsql { | |
1426 CREATE TABLE t1(x); | |
1427 INSERT INTO t1 VALUES('one'); | |
1428 } | |
1429 } {} | |
1430 faultsim_save_and_close | |
1431 | |
1432 do_faultsim_test pagerfault-32 -prep { | |
1433 faultsim_restore_and_reopen | |
1434 db eval { SELECT * FROM t1; } | |
1435 } -body { | |
1436 execsql { SELECT * FROM t1; } | |
1437 } -test { | |
1438 faultsim_test_result {0 one} | |
1439 } | |
1440 sqlite3_shutdown | |
1441 sqlite3_config_uri 0 | |
1442 | |
1443 do_faultsim_test pagerfault-33a -prep { | |
1444 sqlite3 db :memory: | |
1445 execsql { | |
1446 CREATE TABLE t1(a, b); | |
1447 INSERT INTO t1 VALUES(1, 2); | |
1448 } | |
1449 } -body { | |
1450 execsql { VACUUM } | |
1451 } -test { | |
1452 faultsim_test_result {0 {}} | |
1453 } | |
1454 do_faultsim_test pagerfault-33b -prep { | |
1455 sqlite3 db "" | |
1456 execsql { | |
1457 CREATE TABLE t1(a, b); | |
1458 INSERT INTO t1 VALUES(1, 2); | |
1459 } | |
1460 } -body { | |
1461 execsql { VACUUM } | |
1462 } -test { | |
1463 faultsim_test_result {0 {}} | |
1464 } | |
1465 | |
1466 do_test pagerfault-34-pre { | |
1467 reset_db | |
1468 execsql { | |
1469 CREATE TABLE t1(x PRIMARY KEY); | |
1470 } | |
1471 } {} | |
1472 faultsim_save_and_close | |
1473 do_faultsim_test pagerfault-34 -prep { | |
1474 faultsim_restore_and_reopen | |
1475 execsql { | |
1476 BEGIN; | |
1477 INSERT INTO t1 VALUES( randomblob(4000) ); | |
1478 DELETE FROM t1; | |
1479 } | |
1480 } -body { | |
1481 execsql COMMIT | |
1482 } -test { | |
1483 faultsim_test_result {0 {}} | |
1484 } | |
1485 | |
1486 do_test pagerfault-35-pre { | |
1487 faultsim_delete_and_reopen | |
1488 execsql { | |
1489 CREATE TABLE t1(x PRIMARY KEY, y); | |
1490 INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); | |
1491 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; | |
1492 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; | |
1493 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; | |
1494 } | |
1495 faultsim_save_and_close | |
1496 } {} | |
1497 testvfs tv -default 1 | |
1498 tv sectorsize 8192; | |
1499 tv devchar [list] | |
1500 do_faultsim_test pagerfault-35 -prep { | |
1501 faultsim_restore_and_reopen | |
1502 } -body { | |
1503 execsql { UPDATE t1 SET x=randomblob(200) } | |
1504 } -test { | |
1505 faultsim_test_result {0 {}} | |
1506 } | |
1507 catch {db close} | |
1508 tv delete | |
1509 | |
1510 sqlite3_shutdown | |
1511 sqlite3_config_uri 1 | |
1512 do_test pagerfault-36-pre { | |
1513 faultsim_delete_and_reopen | |
1514 execsql { | |
1515 CREATE TABLE t1(x PRIMARY KEY, y); | |
1516 INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); | |
1517 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; | |
1518 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; | |
1519 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; | |
1520 } | |
1521 faultsim_save_and_close | |
1522 } {} | |
1523 do_faultsim_test pagerfault-36 -prep { | |
1524 faultsim_restore | |
1525 sqlite3 db file:test.db?cache=shared | |
1526 sqlite3 db2 file:test.db?cache=shared | |
1527 db2 eval { | |
1528 BEGIN; | |
1529 SELECT count(*) FROM sqlite_master; | |
1530 } | |
1531 db eval { | |
1532 PRAGMA cache_size = 1; | |
1533 BEGIN; | |
1534 UPDATE t1 SET x = randomblob(200); | |
1535 } | |
1536 } -body { | |
1537 execsql ROLLBACK db | |
1538 } -test { | |
1539 catch { db eval {UPDATE t1 SET x = randomblob(200)} } | |
1540 faultsim_test_result {0 {}} | |
1541 catch { db close } | |
1542 catch { db2 close } | |
1543 } | |
1544 | |
1545 sqlite3_shutdown | |
1546 sqlite3_config_uri 0 | |
1547 sqlite3_initialize | |
1548 | |
1549 finish_test | |
OLD | NEW |