xref: /sqlite-3.40.0/test/pagerfault.test (revision b8fff29c)
1b0ac3e3aSdan# 2010 June 15
2b0ac3e3aSdan#
3b0ac3e3aSdan# The author disclaims copyright to this source code.  In place of
4b0ac3e3aSdan# a legal notice, here is a blessing:
5b0ac3e3aSdan#
6b0ac3e3aSdan#    May you do good and not evil.
7b0ac3e3aSdan#    May you find forgiveness for yourself and forgive others.
8b0ac3e3aSdan#    May you share freely, never taking more than you give.
9b0ac3e3aSdan#
10b0ac3e3aSdan#***********************************************************************
11b0ac3e3aSdan#
12b0ac3e3aSdan
13b0ac3e3aSdanset testdir [file dirname $argv0]
14b0ac3e3aSdansource $testdir/tester.tcl
15b0ac3e3aSdansource $testdir/lock_common.tcl
16b0ac3e3aSdansource $testdir/malloc_common.tcl
17b0ac3e3aSdan
18b3f4351fSdanif {[permutation] == "inmemory_journal"} {
19b3f4351fSdan  finish_test
20b3f4351fSdan  return
21b3f4351fSdan}
22b3f4351fSdan
23b2f20bfcSshanehif {$::tcl_platform(platform)=="windows"} {
24b2f20bfcSshaneh  finish_test
25b2f20bfcSshaneh  return
26b2f20bfcSshaneh}
27b2f20bfcSshaneh
28b0ac3e3aSdanset a_string_counter 1
29b0ac3e3aSdanproc a_string {n} {
30b0ac3e3aSdan  global a_string_counter
31b0ac3e3aSdan  incr a_string_counter
32b0ac3e3aSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
33b0ac3e3aSdan}
34b0ac3e3aSdandb func a_string a_string
35b0ac3e3aSdan
36b0ac3e3aSdan#-------------------------------------------------------------------------
37b0ac3e3aSdan# Test fault-injection while rolling back a hot-journal file.
38b0ac3e3aSdan#
39b0ac3e3aSdando_test pagerfault-1-pre1 {
40b0ac3e3aSdan  execsql {
41b0ac3e3aSdan    PRAGMA journal_mode = DELETE;
42b0ac3e3aSdan    PRAGMA cache_size = 10;
43b0ac3e3aSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
44b0ac3e3aSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
45b0ac3e3aSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
46b0ac3e3aSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
47b0ac3e3aSdan    BEGIN;
48b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
49b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
50b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
51b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
52b0ac3e3aSdan  }
53b0ac3e3aSdan  faultsim_save_and_close
54b0ac3e3aSdan} {}
55b0ac3e3aSdando_faultsim_test pagerfault-1 -prep {
56b0ac3e3aSdan  faultsim_restore_and_reopen
57b0ac3e3aSdan} -body {
58b0ac3e3aSdan  execsql { SELECT count(*) FROM t1 }
59b0ac3e3aSdan} -test {
60b0ac3e3aSdan  faultsim_test_result {0 4}
61b0ac3e3aSdan  faultsim_integrity_check
62b0ac3e3aSdan  if {[db one { SELECT count(*) FROM t1 }] != 4} {
63b0ac3e3aSdan    error "Database content appears incorrect"
64b0ac3e3aSdan  }
65b0ac3e3aSdan}
66b0ac3e3aSdan
67b0ac3e3aSdan#-------------------------------------------------------------------------
68de4996e2Sdan# Test fault-injection while rolling back a hot-journal file with a
69de4996e2Sdan# page-size different from the current value stored on page 1 of the
70de4996e2Sdan# database file.
71de4996e2Sdan#
72de4996e2Sdando_test pagerfault-2-pre1 {
73de4996e2Sdan  testvfs tv -default 1
74de4996e2Sdan  tv filter xSync
75de4996e2Sdan  tv script xSyncCb
76de4996e2Sdan  proc xSyncCb {filename args} {
77de4996e2Sdan    if {[string match *journal filename]==0} faultsim_save
78de4996e2Sdan  }
79de4996e2Sdan  faultsim_delete_and_reopen
80de4996e2Sdan  execsql {
81de4996e2Sdan    PRAGMA page_size = 4096;
82de4996e2Sdan    BEGIN;
83de4996e2Sdan      CREATE TABLE abc(a, b, c);
84de4996e2Sdan      INSERT INTO abc VALUES('o', 't', 't');
85de4996e2Sdan      INSERT INTO abc VALUES('f', 'f', 's');
86de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 4
87de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 8
88de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 16
89de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 32
90de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 64
91de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 128
92de4996e2Sdan      INSERT INTO abc SELECT * FROM abc; -- 256
93de4996e2Sdan    COMMIT;
94de4996e2Sdan    PRAGMA page_size = 1024;
95de4996e2Sdan    VACUUM;
96de4996e2Sdan  }
97de4996e2Sdan  db close
98de4996e2Sdan  tv delete
99de4996e2Sdan} {}
100de4996e2Sdando_faultsim_test pagerfault-2 -prep {
101de4996e2Sdan  faultsim_restore_and_reopen
102de4996e2Sdan} -body {
103de4996e2Sdan  execsql { SELECT * FROM abc }
104de4996e2Sdan} -test {
105de4996e2Sdan  set answer [split [string repeat "ottffs" 128] ""]
106de4996e2Sdan  faultsim_test_result [list 0 $answer]
107de4996e2Sdan  faultsim_integrity_check
108de4996e2Sdan  set res [db eval { SELECT * FROM abc }]
109de4996e2Sdan  if {$res != $answer} { error "Database content appears incorrect ($res)" }
110ec6ffc1aSdan}
111de4996e2Sdan
112de4996e2Sdan#-------------------------------------------------------------------------
113b0ac3e3aSdan# Test fault-injection while rolling back hot-journals that were created
114b0ac3e3aSdan# as part of a multi-file transaction.
115b0ac3e3aSdan#
116de4996e2Sdando_test pagerfault-3-pre1 {
117b0ac3e3aSdan  testvfs tstvfs -default 1
118b0ac3e3aSdan  tstvfs filter xDelete
119b0ac3e3aSdan  tstvfs script xDeleteCallback
120b0ac3e3aSdan
121b0ac3e3aSdan  proc xDeleteCallback {method file args} {
122b0ac3e3aSdan    set file [file tail $file]
123b0ac3e3aSdan    if { [string match *mj* $file] } { faultsim_save }
124b0ac3e3aSdan  }
125b0ac3e3aSdan
126b0ac3e3aSdan  faultsim_delete_and_reopen
127b0ac3e3aSdan  db func a_string a_string
128b0ac3e3aSdan
129b0ac3e3aSdan  execsql {
130b0ac3e3aSdan    ATTACH 'test.db2' AS aux;
131b0ac3e3aSdan    PRAGMA journal_mode = DELETE;
132b0ac3e3aSdan    PRAGMA main.cache_size = 10;
133b0ac3e3aSdan    PRAGMA aux.cache_size = 10;
134b0ac3e3aSdan
135b0ac3e3aSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
136b0ac3e3aSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
137b0ac3e3aSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
138b0ac3e3aSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
139b0ac3e3aSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
140b0ac3e3aSdan    INSERT INTO t2 SELECT * FROM t1;
141b0ac3e3aSdan
142b0ac3e3aSdan    BEGIN;
143b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
144b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
145b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
146b0ac3e3aSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
147b0ac3e3aSdan      REPLACE INTO t2 SELECT * FROM t1;
148b0ac3e3aSdan    COMMIT;
149b0ac3e3aSdan  }
150b0ac3e3aSdan
151b0ac3e3aSdan  db close
152b0ac3e3aSdan  tstvfs delete
153b0ac3e3aSdan} {}
154ec6ffc1aSdando_faultsim_test pagerfault-3 -prep {
155b0ac3e3aSdan  faultsim_restore_and_reopen
156b0ac3e3aSdan} -body {
157b0ac3e3aSdan  execsql {
158b0ac3e3aSdan    ATTACH 'test.db2' AS aux;
159b0ac3e3aSdan    SELECT count(*) FROM t2;
160b0ac3e3aSdan    SELECT count(*) FROM t1;
161b0ac3e3aSdan  }
162b0ac3e3aSdan} -test {
163b0ac3e3aSdan  faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}}
164b0ac3e3aSdan  faultsim_integrity_check
165b0ac3e3aSdan  catchsql { ATTACH 'test.db2' AS aux }
166b0ac3e3aSdan  if {[db one { SELECT count(*) FROM t1 }] != 4
167b0ac3e3aSdan   || [db one { SELECT count(*) FROM t2 }] != 4
168b0ac3e3aSdan  } {
169b0ac3e3aSdan    error "Database content appears incorrect"
170b0ac3e3aSdan  }
171b0ac3e3aSdan}
172b0ac3e3aSdan
173de4996e2Sdan#-------------------------------------------------------------------------
174de4996e2Sdan# Test fault-injection as part of a vanilla, no-transaction, INSERT
175de4996e2Sdan# statement.
176de4996e2Sdan#
177de4996e2Sdando_faultsim_test pagerfault-4 -prep {
178de4996e2Sdan  faultsim_delete_and_reopen
179de4996e2Sdan} -body {
180de4996e2Sdan  execsql {
181de4996e2Sdan    CREATE TABLE x(y);
182de4996e2Sdan    INSERT INTO x VALUES('z');
183de4996e2Sdan    SELECT * FROM x;
184de4996e2Sdan  }
185de4996e2Sdan} -test {
186de4996e2Sdan  faultsim_test_result {0 z}
187de4996e2Sdan  faultsim_integrity_check
188de4996e2Sdan}
189de4996e2Sdan
190de4996e2Sdan#-------------------------------------------------------------------------
191de4996e2Sdan# Test fault-injection as part of a commit when using journal_mode=PERSIST.
192146ed78bSdan# Three different cases:
193146ed78bSdan#
194146ed78bSdan#    pagerfault-5.1: With no journal_size_limit configured.
195146ed78bSdan#    pagerfault-5.2: With a journal_size_limit configured.
196146ed78bSdan#    pagerfault-5.4: Multi-file transaction. One connection has a
197146ed78bSdan#                    journal_size_limit of 0, the other has no limit.
198de4996e2Sdan#
199de4996e2Sdando_test pagerfault-5-pre1 {
200de4996e2Sdan  faultsim_delete_and_reopen
201de4996e2Sdan  db func a_string a_string
202de4996e2Sdan  execsql {
203de4996e2Sdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
204de4996e2Sdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
205de4996e2Sdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
206de4996e2Sdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
207de4996e2Sdan  }
208de4996e2Sdan  faultsim_save_and_close
209de4996e2Sdan} {}
210de4996e2Sdando_faultsim_test pagerfault-5.1 -prep {
211de4996e2Sdan  faultsim_restore_and_reopen
212de4996e2Sdan  db func a_string a_string
213de4996e2Sdan  execsql { PRAGMA journal_mode = PERSIST }
214de4996e2Sdan} -body {
215de4996e2Sdan  execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
216de4996e2Sdan} -test {
217de4996e2Sdan  faultsim_test_result {0 {}}
218de4996e2Sdan  faultsim_integrity_check
219de4996e2Sdan}
220de4996e2Sdando_faultsim_test pagerfault-5.2 -prep {
221de4996e2Sdan  faultsim_restore_and_reopen
222de4996e2Sdan  db func a_string a_string
223de4996e2Sdan  execsql {
224de4996e2Sdan    PRAGMA journal_mode = PERSIST;
225de4996e2Sdan    PRAGMA journal_size_limit = 2048;
226de4996e2Sdan  }
227de4996e2Sdan} -body {
228de4996e2Sdan  execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
229de4996e2Sdan} -test {
230de4996e2Sdan  faultsim_test_result {0 {}}
231de4996e2Sdan  faultsim_integrity_check
232de4996e2Sdan}
233ec6ffc1aSdando_faultsim_test pagerfault-5.3 -faults oom-transient -prep {
234de4996e2Sdan  faultsim_restore_and_reopen
235de4996e2Sdan  db func a_string a_string
236fda06befSmistachkin  forcedelete test2.db test2.db-journal test2.db-wal
237de4996e2Sdan  execsql {
238de4996e2Sdan    PRAGMA journal_mode = PERSIST;
239de4996e2Sdan    ATTACH 'test2.db' AS aux;
240de4996e2Sdan    PRAGMA aux.journal_mode = PERSIST;
241de4996e2Sdan    PRAGMA aux.journal_size_limit = 0;
242de4996e2Sdan  }
243de4996e2Sdan} -body {
244de4996e2Sdan  execsql {
245de4996e2Sdan    BEGIN;
246de4996e2Sdan      INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
247de4996e2Sdan      CREATE TABLE aux.t2 AS SELECT * FROM t1;
248de4996e2Sdan    COMMIT;
249de4996e2Sdan  }
250de4996e2Sdan} -test {
251de4996e2Sdan  faultsim_test_result {0 {}}
252ec6ffc1aSdan
253f43d7fceSdan  catchsql { COMMIT }
254f43d7fceSdan  catchsql { ROLLBACK }
255f43d7fceSdan
256f43d7fceSdan  faultsim_integrity_check
257ec6ffc1aSdan  set res ""
258ec6ffc1aSdan  set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }]
259ec6ffc1aSdan  if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"}
260de4996e2Sdan}
261de4996e2Sdan
262153eda0aSdan#-------------------------------------------------------------------------
263153eda0aSdan# Test fault-injection as part of a commit when using
264153eda0aSdan# journal_mode=TRUNCATE.
265153eda0aSdan#
266153eda0aSdando_test pagerfault-6-pre1 {
267153eda0aSdan  faultsim_delete_and_reopen
268153eda0aSdan  db func a_string a_string
269153eda0aSdan  execsql {
270153eda0aSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
271153eda0aSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
272153eda0aSdan  }
273153eda0aSdan  faultsim_save_and_close
274153eda0aSdan} {}
275f9b4419dSdan
276153eda0aSdando_faultsim_test pagerfault-6.1 -prep {
277153eda0aSdan  faultsim_restore_and_reopen
278153eda0aSdan  db func a_string a_string
279153eda0aSdan  execsql { PRAGMA journal_mode = TRUNCATE }
280153eda0aSdan} -body {
281153eda0aSdan  execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
282f9b4419dSdan  execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
283f9b4419dSdan} -test {
284f9b4419dSdan  faultsim_test_result {0 {}}
285f9b4419dSdan  faultsim_integrity_check
286f9b4419dSdan}
287f9b4419dSdan
288f9b4419dSdan# The unix vfs xAccess() method considers a file zero bytes in size to
289f9b4419dSdan# "not exist". This proc overrides that behaviour so that a zero length
290f9b4419dSdan# file is considered to exist.
291f9b4419dSdan#
292f9b4419dSdanproc xAccess {method filename op args} {
293f9b4419dSdan  if {$op != "SQLITE_ACCESS_EXISTS"} { return "" }
294f9b4419dSdan  return [file exists $filename]
295f9b4419dSdan}
296f9b4419dSdando_faultsim_test pagerfault-6.2 -faults cantopen-* -prep {
297f9b4419dSdan  shmfault filter xAccess
298f9b4419dSdan  shmfault script xAccess
299f9b4419dSdan
300f9b4419dSdan  faultsim_restore_and_reopen
301f9b4419dSdan  db func a_string a_string
302f9b4419dSdan  execsql { PRAGMA journal_mode = TRUNCATE }
303f9b4419dSdan} -body {
304f9b4419dSdan  execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
305f9b4419dSdan  execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
306153eda0aSdan} -test {
307153eda0aSdan  faultsim_test_result {0 {}}
308153eda0aSdan  faultsim_integrity_check
309153eda0aSdan}
310153eda0aSdan
311146ed78bSdan# The following was an attempt to get a bitvec malloc to fail. Didn't work.
312146ed78bSdan#
313146ed78bSdan# do_test pagerfault-6-pre1 {
314146ed78bSdan#   faultsim_delete_and_reopen
315146ed78bSdan#   execsql {
316146ed78bSdan#     CREATE TABLE t1(x, y, UNIQUE(x, y));
317146ed78bSdan#     INSERT INTO t1 VALUES(1, randomblob(1501));
318146ed78bSdan#     INSERT INTO t1 VALUES(2, randomblob(1502));
319146ed78bSdan#     INSERT INTO t1 VALUES(3, randomblob(1503));
320146ed78bSdan#     INSERT INTO t1 VALUES(4, randomblob(1504));
321146ed78bSdan#     INSERT INTO t1
322146ed78bSdan#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
323146ed78bSdan#     INSERT INTO t1
324146ed78bSdan#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
325146ed78bSdan#     INSERT INTO t1
326146ed78bSdan#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
327146ed78bSdan#     INSERT INTO t1
328146ed78bSdan#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
329146ed78bSdan#   }
330146ed78bSdan#   faultsim_save_and_close
331146ed78bSdan# } {}
332146ed78bSdan# do_faultsim_test pagerfault-6 -prep {
333146ed78bSdan#   faultsim_restore_and_reopen
334146ed78bSdan# } -body {
335146ed78bSdan#   execsql {
336146ed78bSdan#     BEGIN;
337146ed78bSdan#       UPDATE t1 SET x=x+4 WHERE x=1;
338146ed78bSdan#       SAVEPOINT one;
339146ed78bSdan#         UPDATE t1 SET x=x+4 WHERE x=2;
340146ed78bSdan#         SAVEPOINT three;
341146ed78bSdan#           UPDATE t1 SET x=x+4 WHERE x=3;
342146ed78bSdan#           SAVEPOINT four;
343146ed78bSdan#             UPDATE t1 SET x=x+4 WHERE x=4;
344146ed78bSdan#         RELEASE three;
345146ed78bSdan#     COMMIT;
346146ed78bSdan#     SELECT DISTINCT x FROM t1;
347146ed78bSdan#   }
348146ed78bSdan# } -test {
349146ed78bSdan#   faultsim_test_result {0 {5 6 7 8}}
350146ed78bSdan#   faultsim_integrity_check
351146ed78bSdan# }
352346e4267Sdan#
353dca321aeSdan
354dca321aeSdan# This is designed to provoke a special case in the pager code:
355dca321aeSdan#
356dca321aeSdan# If an error (specifically, a FULL or IOERR error) occurs while writing a
357dca321aeSdan# dirty page to the file-system in order to free up memory, the pager enters
358dca321aeSdan# the "error state". An IO error causes SQLite to roll back the current
359dca321aeSdan# transaction (exiting the error state). A FULL error, however, may only
360dca321aeSdan# rollback the current statement.
361dca321aeSdan#
362dca321aeSdan# This block tests that nothing goes wrong if a FULL error occurs while
363dca321aeSdan# writing a dirty page out to free memory from within a statement that has
364dca321aeSdan# opened a statement transaction.
365dca321aeSdan#
366346e4267Sdando_test pagerfault-7-pre1 {
367346e4267Sdan  faultsim_delete_and_reopen
368346e4267Sdan  execsql {
369346e4267Sdan    CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
370346e4267Sdan    BEGIN;
371346e4267Sdan      INSERT INTO t2 VALUES(NULL, randomblob(1500));
372346e4267Sdan      INSERT INTO t2 VALUES(NULL, randomblob(1500));
373346e4267Sdan      INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2;    --  4
374346e4267Sdan      INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2;    --  8
375346e4267Sdan      INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2;    -- 16
376346e4267Sdan      INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2;    -- 32
377346e4267Sdan      INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2;    -- 64
378346e4267Sdan    COMMIT;
379346e4267Sdan    CREATE TABLE t1(a PRIMARY KEY, b);
380346e4267Sdan    INSERT INTO t1 SELECT * FROM t2;
381346e4267Sdan    DROP TABLE t2;
382346e4267Sdan  }
383346e4267Sdan  faultsim_save_and_close
384346e4267Sdan} {}
385ec6ffc1aSdando_faultsim_test pagerfault-7 -prep {
386346e4267Sdan  faultsim_restore_and_reopen
387346e4267Sdan  execsql {
388346e4267Sdan    PRAGMA cache_size = 10;
389346e4267Sdan    BEGIN;
390346e4267Sdan      UPDATE t1 SET b = randomblob(1500);
391346e4267Sdan  }
392346e4267Sdan} -body {
393346e4267Sdan  execsql { UPDATE t1 SET a = 65, b = randomblob(1500) WHERE (a+1)>200 }
394346e4267Sdan  execsql COMMIT
395346e4267Sdan} -test {
396346e4267Sdan  faultsim_test_result {0 {}}
397346e4267Sdan  faultsim_integrity_check
398346e4267Sdan}
399146ed78bSdan
400dca321aeSdando_test pagerfault-8-pre1 {
401dca321aeSdan  faultsim_delete_and_reopen
402dca321aeSdan  execsql {
403dca321aeSdan    PRAGMA auto_vacuum = 1;
404dca321aeSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
405dca321aeSdan    BEGIN;
406dca321aeSdan      INSERT INTO t1 VALUES(NULL, randomblob(1500));
407dca321aeSdan      INSERT INTO t1 VALUES(NULL, randomblob(1500));
408dca321aeSdan      INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1;    --  4
409dca321aeSdan      INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1;    --  8
410dca321aeSdan      INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1;    -- 16
411dca321aeSdan      INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1;    -- 32
412dca321aeSdan      INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1;    -- 64
413dca321aeSdan    COMMIT;
414dca321aeSdan  }
415dca321aeSdan  faultsim_save_and_close
416dca321aeSdan  set filesize [file size test.db]
417dca321aeSdan  set {} {}
418dca321aeSdan} {}
419dca321aeSdando_test pagerfault-8-pre2 {
420dca321aeSdan  faultsim_restore_and_reopen
421dca321aeSdan  execsql { DELETE FROM t1 WHERE a>32 }
422dca321aeSdan  expr {[file size test.db] < $filesize}
423dca321aeSdan} {1}
424dca321aeSdando_faultsim_test pagerfault-8 -prep {
425dca321aeSdan  faultsim_restore_and_reopen
426dca321aeSdan  execsql {
427dca321aeSdan    BEGIN;
428dca321aeSdan    DELETE FROM t1 WHERE a>32;
429dca321aeSdan  }
430dca321aeSdan} -body {
431dca321aeSdan  execsql COMMIT
432dca321aeSdan} -test {
433dca321aeSdan  faultsim_test_result {0 {}}
434dca321aeSdan  faultsim_integrity_check
435dca321aeSdan}
436dca321aeSdan
437273f3f0dSdan#-------------------------------------------------------------------------
438273f3f0dSdan# This test case is specially designed so that during a savepoint
439273f3f0dSdan# rollback, a new cache entry must be allocated (see comments surrounding
440273f3f0dSdan# the call to sqlite3PagerAcquire() from within pager_playback_one_page()
441273f3f0dSdan# for details). Test the effects of injecting an OOM at this point.
442273f3f0dSdan#
4430a6052ecSdando_test pagerfault-9-pre1 {
4440a6052ecSdan  faultsim_delete_and_reopen
4450a6052ecSdan  execsql {
4460a6052ecSdan    PRAGMA auto_vacuum = incremental;
4470a6052ecSdan    CREATE TABLE t1(x);
4480a6052ecSdan    CREATE TABLE t2(y);
4490a6052ecSdan    CREATE TABLE t3(z);
4500a6052ecSdan
4510a6052ecSdan    INSERT INTO t1 VALUES(randomblob(900));
4520a6052ecSdan    INSERT INTO t1 VALUES(randomblob(900));
4530a6052ecSdan    DELETE FROM t1;
4540a6052ecSdan  }
4550a6052ecSdan  faultsim_save_and_close
4560a6052ecSdan} {}
457273f3f0dSdando_faultsim_test pagerfault-9.1 -prep {
4580a6052ecSdan  faultsim_restore_and_reopen
4590a6052ecSdan  execsql {
4600a6052ecSdan    BEGIN;
4610a6052ecSdan      INSERT INTO t1 VALUES(randomblob(900));
4620a6052ecSdan      INSERT INTO t1 VALUES(randomblob(900));
4630a6052ecSdan      DROP TABLE t3;
4640a6052ecSdan      DROP TABLE t2;
4650a6052ecSdan      SAVEPOINT abc;
4660a6052ecSdan        PRAGMA incremental_vacuum;
4670a6052ecSdan  }
4680a6052ecSdan} -body {
4690a6052ecSdan  execsql {
4700a6052ecSdan    ROLLBACK TO abc;
4710a6052ecSdan    COMMIT;
4720a6052ecSdan    PRAGMA freelist_count
4730a6052ecSdan  }
4740a6052ecSdan} -test {
4750a6052ecSdan  faultsim_test_result {0 2}
4760a6052ecSdan  faultsim_integrity_check
4770a6052ecSdan
4780a6052ecSdan  set sl [db one { SELECT COALESCE(sum(length(x)), 'null') FROM t1 }]
4790a6052ecSdan  if {$sl!="null" && $sl!=1800} {
4800a6052ecSdan    error "Content looks no good... ($sl)"
4810a6052ecSdan  }
4820a6052ecSdan}
4830a6052ecSdan
484273f3f0dSdan#-------------------------------------------------------------------------
485273f3f0dSdan# Test fault injection with a temporary database file.
486273f3f0dSdan#
487c8ce3972Sdanforeach v {a b} {
488c8ce3972Sdan  do_faultsim_test pagerfault-10$v -prep {
489273f3f0dSdan    sqlite3 db ""
490273f3f0dSdan    db func a_string a_string;
491273f3f0dSdan    execsql {
492273f3f0dSdan      PRAGMA cache_size = 10;
493273f3f0dSdan      BEGIN;
494273f3f0dSdan        CREATE TABLE xx(a, b, UNIQUE(a, b));
495273f3f0dSdan        INSERT INTO xx VALUES(a_string(200), a_string(200));
496273f3f0dSdan        INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx;
497273f3f0dSdan        INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx;
498273f3f0dSdan        INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx;
499273f3f0dSdan        INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx;
500273f3f0dSdan      COMMIT;
501273f3f0dSdan    }
502273f3f0dSdan  } -body {
503273f3f0dSdan    execsql { UPDATE xx SET a = a_string(300) }
504273f3f0dSdan  } -test {
505273f3f0dSdan    faultsim_test_result {0 {}}
506c8ce3972Sdan    if {$::v == "b"} { execsql { PRAGMA journal_mode = TRUNCATE } }
507273f3f0dSdan    faultsim_integrity_check
508273f3f0dSdan    faultsim_integrity_check
509273f3f0dSdan  }
510c8ce3972Sdan}
511273f3f0dSdan
512273f3f0dSdan#-------------------------------------------------------------------------
513273f3f0dSdan# Test fault injection with transaction savepoints (savepoints created
514273f3f0dSdan# when a SAVEPOINT command is executed outside of any other savepoint
515273f3f0dSdan# or transaction context).
516273f3f0dSdan#
517273f3f0dSdando_test pagerfault-9-pre1 {
518273f3f0dSdan  faultsim_delete_and_reopen
519273f3f0dSdan  db func a_string a_string;
520273f3f0dSdan  execsql {
521273f3f0dSdan    PRAGMA auto_vacuum = on;
522273f3f0dSdan    CREATE TABLE t1(x UNIQUE);
523273f3f0dSdan    CREATE TABLE t2(y UNIQUE);
524273f3f0dSdan    CREATE TABLE t3(z UNIQUE);
525273f3f0dSdan    BEGIN;
526273f3f0dSdan      INSERT INTO t1 VALUES(a_string(202));
527273f3f0dSdan      INSERT INTO t2 VALUES(a_string(203));
528273f3f0dSdan      INSERT INTO t3 VALUES(a_string(204));
529273f3f0dSdan      INSERT INTO t1 SELECT a_string(202) FROM t1;
530273f3f0dSdan      INSERT INTO t1 SELECT a_string(203) FROM t1;
531273f3f0dSdan      INSERT INTO t1 SELECT a_string(204) FROM t1;
532273f3f0dSdan      INSERT INTO t1 SELECT a_string(205) FROM t1;
533273f3f0dSdan      INSERT INTO t2 SELECT a_string(length(x)) FROM t1;
534273f3f0dSdan      INSERT INTO t3 SELECT a_string(length(x)) FROM t1;
535273f3f0dSdan    COMMIT;
536273f3f0dSdan  }
537273f3f0dSdan  faultsim_save_and_close
538273f3f0dSdan} {}
539273f3f0dSdando_faultsim_test pagerfault-11 -prep {
540273f3f0dSdan  faultsim_restore_and_reopen
541273f3f0dSdan  execsql { PRAGMA cache_size = 10 }
542273f3f0dSdan} -body {
543273f3f0dSdan  execsql {
544273f3f0dSdan    SAVEPOINT trans;
545273f3f0dSdan      UPDATE t2 SET y = y||'2';
546273f3f0dSdan      INSERT INTO t3 SELECT * FROM t2;
547273f3f0dSdan      DELETE FROM t1;
548273f3f0dSdan    ROLLBACK TO trans;
549273f3f0dSdan    UPDATE t1 SET x = x||'3';
550273f3f0dSdan    INSERT INTO t2 SELECT * FROM t1;
551273f3f0dSdan    DELETE FROM t3;
552273f3f0dSdan    RELEASE trans;
553273f3f0dSdan  }
554273f3f0dSdan} -test {
555273f3f0dSdan  faultsim_test_result {0 {}}
556273f3f0dSdan  faultsim_integrity_check
557273f3f0dSdan}
558273f3f0dSdan
559c396d4afSdan
560c8ce3972Sdan#-------------------------------------------------------------------------
561c8ce3972Sdan# Test fault injection when writing to a database file that resides on
562c8ce3972Sdan# a file-system with a sector-size larger than the database page-size.
563c8ce3972Sdan#
564d353331aSdando_test pagerfault-12-pre1 {
565d353331aSdan  testvfs ss_layer -default 1
566d353331aSdan  ss_layer sectorsize 4096
567d353331aSdan  faultsim_delete_and_reopen
568d353331aSdan  db func a_string a_string;
569d353331aSdan
570d353331aSdan  execsql {
571d353331aSdan    PRAGMA page_size = 1024;
572d353331aSdan    PRAGMA journal_mode = PERSIST;
573d353331aSdan    PRAGMA cache_size = 10;
574d353331aSdan    BEGIN;
575d353331aSdan      CREATE TABLE t1(x, y UNIQUE);
576d353331aSdan      INSERT INTO t1 VALUES(a_string(333), a_string(444));
577d353331aSdan      INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1;
578d353331aSdan      INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1;
579d353331aSdan      INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1;
580d353331aSdan      INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1;
581d353331aSdan      INSERT INTO t1 SELECT a_string(44), a_string(55) FROM t1 LIMIT 13;
582d353331aSdan    COMMIT;
583d353331aSdan  }
584d353331aSdan  faultsim_save_and_close
585d353331aSdan} {}
586c396d4afSdan
587c396d4afSdando_faultsim_test pagerfault-12a -prep {
588d353331aSdan  faultsim_restore_and_reopen
589d353331aSdan  execsql { PRAGMA cache_size = 10 }
590d353331aSdan  db func a_string a_string;
591d353331aSdan} -body {
592d353331aSdan  execsql {
593d353331aSdan    UPDATE t1 SET x = a_string(length(x)), y = a_string(length(y));
594d353331aSdan  }
595d353331aSdan} -test {
596d353331aSdan  faultsim_test_result {0 {}}
597d353331aSdan  faultsim_integrity_check
598d353331aSdan}
599d353331aSdan
600c396d4afSdando_test pagerfault-12-pre2 {
601c396d4afSdan  faultsim_restore_and_reopen
602c396d4afSdan  execsql {
603c396d4afSdan    CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 10;
604c396d4afSdan  }
605c396d4afSdan  faultsim_save_and_close
606c396d4afSdan} {}
607c396d4afSdando_faultsim_test pagerfault-12b -prep {
608c396d4afSdan  faultsim_restore_and_reopen
609c396d4afSdan  db func a_string a_string;
610c396d4afSdan  execsql { SELECT * FROM t1 }
611c396d4afSdan} -body {
612c396d4afSdan  set sql(1) { UPDATE t2 SET x = a_string(280) }
613c396d4afSdan  set sql(2) { UPDATE t1 SET x = a_string(280) WHERE rowid = 5 }
614c396d4afSdan
615c396d4afSdan  db eval { SELECT rowid FROM t1 LIMIT 2 } { db eval $sql($rowid) }
616c396d4afSdan
617c396d4afSdan} -test {
618c396d4afSdan  faultsim_test_result {0 {}}
619c396d4afSdan  faultsim_integrity_check
620c396d4afSdan}
621c396d4afSdan
622c396d4afSdancatch { db close }
623c396d4afSdanss_layer delete
624c396d4afSdan
625d353331aSdan
626c8ce3972Sdan#-------------------------------------------------------------------------
627ba3cbf3dSdan# Test fault injection when SQLite opens a database where the size of the
628ba3cbf3dSdan# database file is zero bytes but the accompanying journal file is larger
629ba3cbf3dSdan# than that. In this scenario SQLite should delete the journal file
630ba3cbf3dSdan# without rolling it back, even if it is in all other respects a valid
631ba3cbf3dSdan# hot-journal file.
632c8ce3972Sdan#
633c8ce3972Sdando_test pagerfault-13-pre1 {
634c8ce3972Sdan  faultsim_delete_and_reopen
635c8ce3972Sdan  db func a_string a_string;
636c8ce3972Sdan  execsql {
637c8ce3972Sdan    PRAGMA journal_mode = PERSIST;
638c8ce3972Sdan    BEGIN;
639c8ce3972Sdan      CREATE TABLE t1(x, y UNIQUE);
640c8ce3972Sdan      INSERT INTO t1 VALUES(a_string(333), a_string(444));
641c8ce3972Sdan    COMMIT;
642c8ce3972Sdan  }
643c8ce3972Sdan  db close
644fda06befSmistachkin  forcedelete test.db
645c8ce3972Sdan  faultsim_save
646c8ce3972Sdan} {}
647c8ce3972Sdando_faultsim_test pagerfault-13 -prep {
648c8ce3972Sdan  faultsim_restore_and_reopen
649c8ce3972Sdan} -body {
650c8ce3972Sdan  execsql { CREATE TABLE xx(a, b) }
651c8ce3972Sdan} -test {
652c8ce3972Sdan  faultsim_test_result {0 {}}
653c8ce3972Sdan}
654c8ce3972Sdan
655ba3cbf3dSdan#---------------------------------------------------------------------------
656ba3cbf3dSdan# Test fault injection into a small backup operation.
657ba3cbf3dSdan#
658ba3cbf3dSdando_test pagerfault-14-pre1 {
659ba3cbf3dSdan  faultsim_delete_and_reopen
660ba3cbf3dSdan  db func a_string a_string;
661ba3cbf3dSdan  execsql {
662ba3cbf3dSdan    PRAGMA journal_mode = PERSIST;
663ba3cbf3dSdan    ATTACH 'test.db2' AS two;
664ba3cbf3dSdan    BEGIN;
665ba3cbf3dSdan      CREATE TABLE t1(x, y UNIQUE);
666ba3cbf3dSdan      CREATE TABLE two.t2(x, y UNIQUE);
667ba3cbf3dSdan      INSERT INTO t1 VALUES(a_string(333), a_string(444));
668ba3cbf3dSdan      INSERT INTO t2 VALUES(a_string(333), a_string(444));
669ba3cbf3dSdan    COMMIT;
670c8ce3972Sdan  }
671ba3cbf3dSdan  faultsim_save_and_close
672ba3cbf3dSdan} {}
6736b63ab47Sdan
6746b63ab47Sdando_faultsim_test pagerfault-14a -prep {
675ba3cbf3dSdan  faultsim_restore_and_reopen
676ba3cbf3dSdan} -body {
677ba3cbf3dSdan  if {[catch {db backup test.db2} msg]} { error [regsub {.*: } $msg {}] }
678ba3cbf3dSdan} -test {
679a690ff36Sdrh  faultsim_test_result {0 {}} {1 {}} {1 {SQL logic error}}
680ba3cbf3dSdan}
681ab4f076eSdan
682fa2a4772Sdan# If TEMP_STORE is 2 or greater, then the database [db2] will be created
683fa2a4772Sdan# as an in-memory database. This test will not work in that case, as it
684fa2a4772Sdan# is not possible to change the page-size of an in-memory database. Even
685fa2a4772Sdan# using the backup API.
686fa2a4772Sdan#
6879bf01363Sdan# Update: It is no longer possible to change the page size of any temp
6889bf01363Sdan# database after it has been created.
6899bf01363Sdan#
6906b63ab47Sdando_faultsim_test pagerfault-14b -prep {
691caace926Sshaneh  catch { db2 close }
6926b63ab47Sdan  faultsim_restore_and_reopen
6936b63ab47Sdan    sqlite3 db2 ""
6946b63ab47Sdan    db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) }
6956b63ab47Sdan} -body {
6966b63ab47Sdan  sqlite3_backup B db2 main db main
6976b63ab47Sdan  B step 200
6986b63ab47Sdan  set rc [B finish]
6996b63ab47Sdan  if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR}
7006b63ab47Sdan  if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] }
7016b63ab47Sdan  set {} {}
7026b63ab47Sdan} -test {
7039bf01363Sdan  faultsim_test_result {1 {attempt to write a readonly database}} \
7049bf01363Sdan                       {1 {sqlite3_backup_init() failed}}
705fa2a4772Sdan}
706fa2a4772Sdan
707d0b0d4dcSdando_faultsim_test pagerfault-14c -prep {
708caace926Sshaneh  catch { db2 close }
709d0b0d4dcSdan  faultsim_restore_and_reopen
710d0b0d4dcSdan  sqlite3 db2 test.db2
711d0b0d4dcSdan  db2 eval {
712d0b0d4dcSdan    PRAGMA synchronous = off;
713d0b0d4dcSdan    PRAGMA page_size = 4096;
714d0b0d4dcSdan    CREATE TABLE xx(a);
715d0b0d4dcSdan  }
716d0b0d4dcSdan} -body {
717d0b0d4dcSdan  sqlite3_backup B db2 main db main
718d0b0d4dcSdan  B step 200
719d0b0d4dcSdan  set rc [B finish]
720d0b0d4dcSdan  if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR}
721d0b0d4dcSdan  if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] }
722d0b0d4dcSdan  set {} {}
723d0b0d4dcSdan} -test {
724ab4f076eSdan  faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}}
725d0b0d4dcSdan}
726ba3cbf3dSdan
727ba3cbf3dSdando_test pagerfault-15-pre1 {
728ba3cbf3dSdan  faultsim_delete_and_reopen
729ba3cbf3dSdan  db func a_string a_string;
730ba3cbf3dSdan  execsql {
731ba3cbf3dSdan    BEGIN;
732ba3cbf3dSdan      CREATE TABLE t1(x, y UNIQUE);
733ba3cbf3dSdan      INSERT INTO t1 VALUES(a_string(11), a_string(22));
734ba3cbf3dSdan      INSERT INTO t1 VALUES(a_string(11), a_string(22));
735ba3cbf3dSdan    COMMIT;
736ba3cbf3dSdan  }
737ba3cbf3dSdan  faultsim_save_and_close
738ba3cbf3dSdan} {}
739ba3cbf3dSdando_faultsim_test pagerfault-15 -prep {
740ba3cbf3dSdan  faultsim_restore_and_reopen
741ba3cbf3dSdan  db func a_string a_string;
742ba3cbf3dSdan} -body {
743ba3cbf3dSdan  db eval { SELECT * FROM t1 LIMIT 1 } {
744ba3cbf3dSdan    execsql {
745ba3cbf3dSdan      BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT;
746ba3cbf3dSdan      BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT;
747ba3cbf3dSdan    }
748ba3cbf3dSdan  }
749ba3cbf3dSdan} -test {
750ba3cbf3dSdan  faultsim_test_result {0 {}}
751ba3cbf3dSdan  faultsim_integrity_check
752ba3cbf3dSdan}
753ba3cbf3dSdan
754ba3cbf3dSdan
755ba3cbf3dSdando_test pagerfault-16-pre1 {
756ba3cbf3dSdan  faultsim_delete_and_reopen
757ba3cbf3dSdan  execsql { CREATE TABLE t1(x, y UNIQUE) }
758ba3cbf3dSdan  faultsim_save_and_close
759ba3cbf3dSdan} {}
760ba3cbf3dSdando_faultsim_test pagerfault-16 -prep {
761ba3cbf3dSdan  faultsim_restore_and_reopen
762ba3cbf3dSdan} -body {
763ba3cbf3dSdan  execsql {
764ba3cbf3dSdan    PRAGMA locking_mode = exclusive;
765ba3cbf3dSdan    PRAGMA journal_mode = wal;
766ba3cbf3dSdan    INSERT INTO t1 VALUES(1, 2);
767ba3cbf3dSdan    INSERT INTO t1 VALUES(3, 4);
768ba3cbf3dSdan    PRAGMA journal_mode = delete;
769ba3cbf3dSdan    INSERT INTO t1 VALUES(4, 5);
770ba3cbf3dSdan    PRAGMA journal_mode = wal;
771ba3cbf3dSdan    INSERT INTO t1 VALUES(6, 7);
772ba3cbf3dSdan    PRAGMA journal_mode = persist;
773ba3cbf3dSdan    INSERT INTO t1 VALUES(8, 9);
774ba3cbf3dSdan  }
775ba3cbf3dSdan} -test {
776ba3cbf3dSdan  faultsim_test_result {0 {exclusive wal delete wal persist}}
777ba3cbf3dSdan  faultsim_integrity_check
778ba3cbf3dSdan}
779ba3cbf3dSdan
780c8ce3972Sdan
78189ccf448Sdan#-------------------------------------------------------------------------
78289ccf448Sdan# Test fault injection while changing into and out of WAL mode.
78389ccf448Sdan#
78489ccf448Sdando_test pagerfault-17-pre1 {
78589ccf448Sdan  faultsim_delete_and_reopen
78689ccf448Sdan  execsql {
78789ccf448Sdan    CREATE TABLE t1(a PRIMARY KEY, b);
78889ccf448Sdan    INSERT INTO t1 VALUES(1862, 'Botha');
78989ccf448Sdan    INSERT INTO t1 VALUES(1870, 'Smuts');
79089ccf448Sdan    INSERT INTO t1 VALUES(1866, 'Hertzog');
79189ccf448Sdan  }
79289ccf448Sdan  faultsim_save_and_close
79389ccf448Sdan} {}
79489ccf448Sdando_faultsim_test pagerfault-17a -prep {
79589ccf448Sdan  faultsim_restore_and_reopen
79689ccf448Sdan} -body {
79789ccf448Sdan  execsql {
79889ccf448Sdan    PRAGMA journal_mode = wal;
79989ccf448Sdan    PRAGMA journal_mode = delete;
80089ccf448Sdan  }
80189ccf448Sdan} -test {
80289ccf448Sdan  faultsim_test_result {0 {wal delete}}
80389ccf448Sdan  faultsim_integrity_check
80489ccf448Sdan}
80589ccf448Sdando_faultsim_test pagerfault-17b -prep {
80689ccf448Sdan  faultsim_restore_and_reopen
80789ccf448Sdan  execsql { PRAGMA synchronous = OFF }
80889ccf448Sdan} -body {
80989ccf448Sdan  execsql {
81089ccf448Sdan    PRAGMA journal_mode = wal;
81189ccf448Sdan    INSERT INTO t1 VALUES(22, 'Clarke');
81289ccf448Sdan    PRAGMA journal_mode = delete;
81389ccf448Sdan  }
81489ccf448Sdan} -test {
81589ccf448Sdan  faultsim_test_result {0 {wal delete}}
81689ccf448Sdan  faultsim_integrity_check
81789ccf448Sdan}
81889ccf448Sdando_faultsim_test pagerfault-17c -prep {
81989ccf448Sdan  faultsim_restore_and_reopen
82089ccf448Sdan  execsql {
82189ccf448Sdan    PRAGMA locking_mode = exclusive;
82289ccf448Sdan    PRAGMA journal_mode = wal;
82389ccf448Sdan  }
82489ccf448Sdan} -body {
82589ccf448Sdan  execsql { PRAGMA journal_mode = delete }
82689ccf448Sdan} -test {
82789ccf448Sdan  faultsim_test_result {0 delete}
82889ccf448Sdan  faultsim_integrity_check
82989ccf448Sdan}
83089ccf448Sdando_faultsim_test pagerfault-17d -prep {
831caace926Sshaneh  catch { db2 close }
83289ccf448Sdan  faultsim_restore_and_reopen
83389ccf448Sdan  sqlite3 db2 test.db
83489ccf448Sdan  execsql { PRAGMA journal_mode = delete }
83589ccf448Sdan  execsql { PRAGMA journal_mode = wal }
83689ccf448Sdan  execsql { INSERT INTO t1 VALUES(99, 'Bradman') } db2
83789ccf448Sdan} -body {
83889ccf448Sdan  execsql { PRAGMA journal_mode = delete }
83989ccf448Sdan} -test {
84089ccf448Sdan  faultsim_test_result {1 {database is locked}}
84189ccf448Sdan  faultsim_integrity_check
84289ccf448Sdan}
84389ccf448Sdando_faultsim_test pagerfault-17e -prep {
844caace926Sshaneh  catch { db2 close }
84589ccf448Sdan  faultsim_restore_and_reopen
84689ccf448Sdan  sqlite3 db2 test.db
84789ccf448Sdan  execsql { PRAGMA journal_mode = delete }
84889ccf448Sdan  execsql { PRAGMA journal_mode = wal }
84989ccf448Sdan  set ::chan [launch_testfixture]
85089ccf448Sdan  testfixture $::chan {
85189ccf448Sdan    sqlite3 db test.db
85289ccf448Sdan    db eval { INSERT INTO t1 VALUES(101, 'Latham') }
85389ccf448Sdan  }
85489ccf448Sdan  catch { testfixture $::chan sqlite_abort }
85589ccf448Sdan  catch { close $::chan }
85689ccf448Sdan} -body {
85789ccf448Sdan  execsql { PRAGMA journal_mode = delete }
85889ccf448Sdan} -test {
85989ccf448Sdan  faultsim_test_result {0 delete}
86089ccf448Sdan  faultsim_integrity_check
86189ccf448Sdan}
86289ccf448Sdan
86389ccf448Sdan#-------------------------------------------------------------------------
86489ccf448Sdan# Test fault-injection when changing from journal_mode=persist to
86589ccf448Sdan# journal_mode=delete (this involves deleting the journal file).
86689ccf448Sdan#
86789ccf448Sdando_test pagerfault-18-pre1 {
86889ccf448Sdan  faultsim_delete_and_reopen
86989ccf448Sdan  execsql {
87089ccf448Sdan    CREATE TABLE qq(x);
87189ccf448Sdan    INSERT INTO qq VALUES('Herbert');
87289ccf448Sdan    INSERT INTO qq VALUES('Macalister');
87389ccf448Sdan    INSERT INTO qq VALUES('Mackenzie');
87489ccf448Sdan    INSERT INTO qq VALUES('Lilley');
87589ccf448Sdan    INSERT INTO qq VALUES('Palmer');
87689ccf448Sdan  }
87789ccf448Sdan  faultsim_save_and_close
87889ccf448Sdan} {}
87989ccf448Sdando_faultsim_test pagerfault-18 -prep {
88089ccf448Sdan  faultsim_restore_and_reopen
88189ccf448Sdan  execsql {
88289ccf448Sdan    PRAGMA journal_mode = PERSIST;
88389ccf448Sdan    INSERT INTO qq VALUES('Beatty');
88489ccf448Sdan  }
88589ccf448Sdan} -body {
88689ccf448Sdan  execsql { PRAGMA journal_mode = delete }
88789ccf448Sdan} -test {
88889ccf448Sdan  faultsim_test_result {0 delete}
88989ccf448Sdan  faultsim_integrity_check
89089ccf448Sdan}
89189ccf448Sdan
89289ccf448Sdando_faultsim_test pagerfault-19a -prep {
89389ccf448Sdan  sqlite3 db :memory:
89489ccf448Sdan  db func a_string a_string
89589ccf448Sdan  execsql {
89689ccf448Sdan    PRAGMA auto_vacuum = FULL;
89789ccf448Sdan    BEGIN;
89889ccf448Sdan      CREATE TABLE t1(a, b);
89989ccf448Sdan      INSERT INTO t1 VALUES(a_string(5000), a_string(6000));
90089ccf448Sdan    COMMIT;
90189ccf448Sdan  }
90289ccf448Sdan} -body {
90389ccf448Sdan  execsql {
90489ccf448Sdan    CREATE TABLE t2(a, b);
90589ccf448Sdan    INSERT INTO t2 SELECT * FROM t1;
90689ccf448Sdan    DELETE FROM t1;
90789ccf448Sdan  }
90889ccf448Sdan} -test {
90989ccf448Sdan  faultsim_test_result {0 {}}
91089ccf448Sdan}
91189ccf448Sdan
91289ccf448Sdando_test pagerfault-19-pre1 {
91389ccf448Sdan  faultsim_delete_and_reopen
91489ccf448Sdan  execsql {
91589ccf448Sdan    PRAGMA auto_vacuum = FULL;
91689ccf448Sdan    CREATE TABLE t1(x); INSERT INTO t1 VALUES(1);
91789ccf448Sdan    CREATE TABLE t2(x); INSERT INTO t2 VALUES(2);
91889ccf448Sdan    CREATE TABLE t3(x); INSERT INTO t3 VALUES(3);
91989ccf448Sdan    CREATE TABLE t4(x); INSERT INTO t4 VALUES(4);
92089ccf448Sdan    CREATE TABLE t5(x); INSERT INTO t5 VALUES(5);
92189ccf448Sdan    CREATE TABLE t6(x); INSERT INTO t6 VALUES(6);
92289ccf448Sdan  }
92389ccf448Sdan  faultsim_save_and_close
92489ccf448Sdan} {}
92589ccf448Sdando_faultsim_test pagerfault-19b -prep {
92689ccf448Sdan  faultsim_restore_and_reopen
92789ccf448Sdan} -body {
92889ccf448Sdan  execsql {
92989ccf448Sdan    BEGIN;
93089ccf448Sdan      UPDATE t4 SET x = x+1;
93189ccf448Sdan      UPDATE t6 SET x = x+1;
93289ccf448Sdan      SAVEPOINT one;
93389ccf448Sdan        UPDATE t3 SET x = x+1;
93489ccf448Sdan        SAVEPOINT two;
93589ccf448Sdan          DROP TABLE t2;
93689ccf448Sdan      ROLLBACK TO one;
93789ccf448Sdan    COMMIT;
93889ccf448Sdan    SELECT * FROM t3;
93989ccf448Sdan    SELECT * FROM t4;
94089ccf448Sdan    SELECT * FROM t6;
94189ccf448Sdan  }
94289ccf448Sdan} -test {
94389ccf448Sdan  faultsim_test_result {0 {3 5 7}}
94489ccf448Sdan}
94589ccf448Sdan
946d0b0d4dcSdan#-------------------------------------------------------------------------
947d0b0d4dcSdan# This tests fault-injection in a special case in the auto-vacuum code.
948d0b0d4dcSdan#
94989ccf448Sdando_test pagerfault-20-pre1 {
95089ccf448Sdan  faultsim_delete_and_reopen
95189ccf448Sdan  execsql {
952d0b0d4dcSdan    PRAGMA cache_size = 10;
953d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
954d0b0d4dcSdan    CREATE TABLE t0(a, b);
95589ccf448Sdan  }
95689ccf448Sdan  faultsim_save_and_close
95789ccf448Sdan} {}
95889ccf448Sdando_faultsim_test pagerfault-20 -prep {
95989ccf448Sdan  faultsim_restore_and_reopen
96089ccf448Sdan} -body {
96189ccf448Sdan  execsql {
96289ccf448Sdan    BEGIN;
963d0b0d4dcSdan      CREATE TABLE t1(a, b);
964d0b0d4dcSdan      CREATE TABLE t2(a, b);
965d0b0d4dcSdan      DROP TABLE t1;
96689ccf448Sdan    COMMIT;
96789ccf448Sdan  }
96889ccf448Sdan} -test {
96989ccf448Sdan  faultsim_test_result {0 {}}
97089ccf448Sdan}
971273f3f0dSdan
972d0b0d4dcSdando_test pagerfault-21-pre1 {
973d0b0d4dcSdan  faultsim_delete_and_reopen
974d0b0d4dcSdan  execsql {
975d0b0d4dcSdan    PRAGMA cache_size = 10;
976d0b0d4dcSdan    CREATE TABLE t0(a PRIMARY KEY, b);
977d0b0d4dcSdan    INSERT INTO t0 VALUES(1, 2);
978d0b0d4dcSdan  }
979d0b0d4dcSdan  faultsim_save_and_close
980d0b0d4dcSdan} {}
981d0b0d4dcSdando_faultsim_test pagerfault-21 -prep {
982d0b0d4dcSdan  faultsim_restore_and_reopen
983d0b0d4dcSdan} -body {
984d0b0d4dcSdan  db eval { SELECT * FROM t0 LIMIT 1 } {
985d0b0d4dcSdan    db eval { INSERT INTO t0 SELECT a+1, b FROM t0 }
986d0b0d4dcSdan    db eval { INSERT INTO t0 SELECT a+2, b FROM t0 }
987d0b0d4dcSdan  }
988d0b0d4dcSdan} -test {
989d0b0d4dcSdan  faultsim_test_result {0 {}}
990d0b0d4dcSdan}
991d0b0d4dcSdan
992d0b0d4dcSdan
9939d08d640Sdan#-------------------------------------------------------------------------
9949d08d640Sdan# Test fault-injection and rollback when the nReserve header value
9959d08d640Sdan# is non-zero.
9969d08d640Sdan#
9979d08d640Sdando_test pagerfault-21-pre1 {
9989d08d640Sdan  faultsim_delete_and_reopen
9999d08d640Sdan  execsql {
10009d08d640Sdan    PRAGMA page_size = 1024;
10019d08d640Sdan    PRAGMA journal_mode = WAL;
10029d08d640Sdan    PRAGMA journal_mode = DELETE;
10039d08d640Sdan  }
10049d08d640Sdan  db close
10059d08d640Sdan  hexio_write test.db 20    10
10069d08d640Sdan  hexio_write test.db 105 03F0
10079d08d640Sdan  sqlite3 db test.db
10089d08d640Sdan  db func a_string a_string
10099d08d640Sdan  execsql {
10109d08d640Sdan    CREATE TABLE t0(a PRIMARY KEY, b UNIQUE);
10119d08d640Sdan    INSERT INTO t0 VALUES(a_string(222), a_string(333));
10129d08d640Sdan    INSERT INTO t0 VALUES(a_string(223), a_string(334));
10139d08d640Sdan    INSERT INTO t0 VALUES(a_string(224), a_string(335));
10149d08d640Sdan    INSERT INTO t0 VALUES(a_string(225), a_string(336));
10159d08d640Sdan  }
10169d08d640Sdan  faultsim_save_and_close
10179d08d640Sdan} {}
10189d08d640Sdan
10199d08d640Sdando_faultsim_test pagerfault-21 -prep {
10209d08d640Sdan  faultsim_restore_and_reopen
10219d08d640Sdan} -body {
10229d08d640Sdan  execsql { INSERT INTO t0 SELECT a||'x', b||'x' FROM t0 }
10239d08d640Sdan} -test {
10249d08d640Sdan  faultsim_test_result {0 {}}
10259d08d640Sdan  faultsim_integrity_check
10269d08d640Sdan}
10279d08d640Sdanifcapable crashtest {
10289d08d640Sdan  faultsim_delete_and_reopen
10299d08d640Sdan  execsql {
10309d08d640Sdan    PRAGMA page_size = 1024;
10319d08d640Sdan    PRAGMA journal_mode = WAL;
10329d08d640Sdan    PRAGMA journal_mode = DELETE;
10339d08d640Sdan  }
10349d08d640Sdan  db close
10359d08d640Sdan  hexio_write test.db 20    10
10369d08d640Sdan  hexio_write test.db 105 03F0
10379d08d640Sdan
10389d08d640Sdan  sqlite3 db test.db
10399d08d640Sdan  db func a_string a_string
10409d08d640Sdan  execsql {
10419d08d640Sdan    CREATE TABLE t0(a PRIMARY KEY, b UNIQUE);
10429d08d640Sdan    INSERT INTO t0 VALUES(a_string(222), a_string(333));
10439d08d640Sdan    INSERT INTO t0 VALUES(a_string(223), a_string(334));
10449d08d640Sdan  }
10459d08d640Sdan  faultsim_save_and_close
10469d08d640Sdan
10479d08d640Sdan  for {set iTest 1} {$iTest<50} {incr iTest} {
10489d08d640Sdan    do_test pagerfault-21.crash.$iTest.1 {
10499d08d640Sdan      crashsql -delay 1 -file test.db -seed $iTest {
10509d08d640Sdan        BEGIN;
10519d08d640Sdan          CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
10529d08d640Sdan          INSERT INTO t1 SELECT a, b FROM t0;
10539d08d640Sdan        COMMIT;
10549d08d640Sdan      }
10559d08d640Sdan    } {1 {child process exited abnormally}}
10569d08d640Sdan    do_test pagerfault-22.$iTest.2 {
10579d08d640Sdan      sqlite3 db test.db
10589d08d640Sdan      execsql { PRAGMA integrity_check }
10599d08d640Sdan    } {ok}
10609d08d640Sdan    db close
10619d08d640Sdan  }
10629d08d640Sdan}
10639d08d640Sdan
106459257dc6Sdan
106559257dc6Sdan#-------------------------------------------------------------------------
106659257dc6Sdan# When a 3.7.0 client opens a write-transaction on a database file that
106759257dc6Sdan# has been appended to or truncated by a pre-370 client, it updates
106859257dc6Sdan# the db-size in the file header immediately. This test case provokes
106959257dc6Sdan# errors during that operation.
107059257dc6Sdan#
107159257dc6Sdando_test pagerfault-22-pre1 {
107259257dc6Sdan  faultsim_delete_and_reopen
107359257dc6Sdan  db func a_string a_string
107459257dc6Sdan  execsql {
107559257dc6Sdan    PRAGMA page_size = 1024;
107659257dc6Sdan    PRAGMA auto_vacuum = 0;
107759257dc6Sdan    CREATE TABLE t1(a);
107859257dc6Sdan    CREATE INDEX i1 ON t1(a);
107959257dc6Sdan    INSERT INTO t1 VALUES(a_string(3000));
108059257dc6Sdan    CREATE TABLE t2(a);
108159257dc6Sdan    INSERT INTO t2 VALUES(1);
108259257dc6Sdan  }
108359257dc6Sdan  db close
108459257dc6Sdan  sql36231 { INSERT INTO t1 VALUES(a_string(3000)) }
108559257dc6Sdan  faultsim_save_and_close
108659257dc6Sdan} {}
108759257dc6Sdando_faultsim_test pagerfault-22 -prep {
108859257dc6Sdan  faultsim_restore_and_reopen
108959257dc6Sdan} -body {
109059257dc6Sdan  execsql { INSERT INTO t2 VALUES(2) }
109159257dc6Sdan  execsql { SELECT * FROM t2 }
109259257dc6Sdan} -test {
109359257dc6Sdan  faultsim_test_result {0 {1 2}}
109459257dc6Sdan  faultsim_integrity_check
109559257dc6Sdan}
109622b328b2Sdan
109722b328b2Sdan#-------------------------------------------------------------------------
109822b328b2Sdan# Provoke an OOM error during a commit of multi-file transaction. One of
109922b328b2Sdan# the databases written during the transaction is an in-memory database.
110022b328b2Sdan# This test causes rollback of the in-memory database after CommitPhaseOne()
110122b328b2Sdan# has successfully returned. i.e. the series of calls for the aborted commit
110222b328b2Sdan# is:
110322b328b2Sdan#
110422b328b2Sdan#   PagerCommitPhaseOne(<in-memory-db>)   ->   SQLITE_OK
110522b328b2Sdan#   PagerCommitPhaseOne(<file-db>)        ->   SQLITE_IOERR
110622b328b2Sdan#   PagerRollback(<in-memory-db>)
110722b328b2Sdan#   PagerRollback(<file-db>)
110822b328b2Sdan#
110922b328b2Sdando_faultsim_test pagerfault-23 -prep {
111022b328b2Sdan  sqlite3 db :memory:
1111fda06befSmistachkin  foreach f [glob -nocomplain test.db*] { forcedelete $f }
111222b328b2Sdan  db eval {
111322b328b2Sdan    ATTACH 'test.db2' AS aux;
111422b328b2Sdan    CREATE TABLE t1(a, b);
111522b328b2Sdan    CREATE TABLE aux.t2(a, b);
111622b328b2Sdan  }
111722b328b2Sdan} -body {
111822b328b2Sdan  execsql {
111922b328b2Sdan    BEGIN;
112022b328b2Sdan      INSERT INTO t1 VALUES(1,2);
112122b328b2Sdan      INSERT INTO t2 VALUES(3,4);
112222b328b2Sdan    COMMIT;
112322b328b2Sdan  }
112422b328b2Sdan} -test {
112522b328b2Sdan  faultsim_test_result {0 {}}
112622b328b2Sdan  faultsim_integrity_check
112722b328b2Sdan}
112822b328b2Sdan
112922b328b2Sdando_faultsim_test pagerfault-24 -prep {
113022b328b2Sdan  faultsim_delete_and_reopen
113122b328b2Sdan  db eval { PRAGMA temp_store = file }
113222b328b2Sdan  execsql { CREATE TABLE x(a, b) }
113322b328b2Sdan} -body {
113422b328b2Sdan  execsql { CREATE TEMP TABLE t1(a, b) }
113522b328b2Sdan} -test {
11365653e4daSdan  faultsim_test_result {0 {}} \
11375653e4daSdan    {1 {unable to open a temporary database file for storing temporary tables}}
113822b328b2Sdan  set ic [db eval { PRAGMA temp.integrity_check }]
113922b328b2Sdan  if {$ic != "ok"} { error "Integrity check: $ic" }
114022b328b2Sdan}
114122b328b2Sdan
11425653e4daSdanproc lockrows {n} {
11435653e4daSdan  if {$n==0} { return "" }
11445653e4daSdan  db eval { SELECT * FROM t1 WHERE oid = $n } {
11455653e4daSdan    return [lockrows [expr {$n-1}]]
11465653e4daSdan  }
11475653e4daSdan}
11485653e4daSdan
11491879b088Sdan
11505653e4daSdando_test pagerfault-25-pre1 {
11515653e4daSdan  faultsim_delete_and_reopen
11525653e4daSdan  db func a_string a_string
11535653e4daSdan  execsql {
11545653e4daSdan    PRAGMA page_size = 1024;
11555653e4daSdan    PRAGMA auto_vacuum = 0;
11565653e4daSdan    CREATE TABLE t1(a);
11575653e4daSdan    INSERT INTO t1 VALUES(a_string(500));
11585653e4daSdan    INSERT INTO t1 SELECT a_string(500) FROM t1;
11595653e4daSdan    INSERT INTO t1 SELECT a_string(500) FROM t1;
11605653e4daSdan    INSERT INTO t1 SELECT a_string(500) FROM t1;
11615653e4daSdan    INSERT INTO t1 SELECT a_string(500) FROM t1;
11625653e4daSdan    INSERT INTO t1 SELECT a_string(500) FROM t1;
11635653e4daSdan  }
11645653e4daSdan  faultsim_save_and_close
11655653e4daSdan} {}
11661879b088Sdando_faultsim_test pagerfault-25 -prep {
11675653e4daSdan  faultsim_restore_and_reopen
11685653e4daSdan  db func a_string a_string
11695653e4daSdan  set ::channel [db incrblob -readonly t1 a 1]
11705653e4daSdan  execsql {
11715653e4daSdan    PRAGMA cache_size = 10;
11725653e4daSdan    BEGIN;
11735653e4daSdan      INSERT INTO t1 VALUES(a_string(3000));
11745653e4daSdan      INSERT INTO t1 VALUES(a_string(3000));
11755653e4daSdan  }
11765653e4daSdan} -body {
11775653e4daSdan  lockrows 30
11785653e4daSdan} -test {
11795653e4daSdan  catch { lockrows 30 }
11801879b088Sdan  catch { db eval COMMIT }
11815653e4daSdan  close $::channel
11825653e4daSdan  faultsim_test_result {0 {}}
11835653e4daSdan}
118422b328b2Sdan
11851879b088Sdando_faultsim_test pagerfault-26 -prep {
11861879b088Sdan  faultsim_delete_and_reopen
11871879b088Sdan  execsql {
11881879b088Sdan    PRAGMA page_size = 1024;
11891879b088Sdan    PRAGMA journal_mode = truncate;
11901879b088Sdan    PRAGMA auto_vacuum = full;
11911879b088Sdan    PRAGMA locking_mode=exclusive;
11921879b088Sdan    CREATE TABLE t1(a, b);
11931879b088Sdan    INSERT INTO t1 VALUES(1, 2);
11941879b088Sdan    PRAGMA page_size = 4096;
11951879b088Sdan  }
11961879b088Sdan} -body {
11971879b088Sdan  execsql {
11981879b088Sdan    VACUUM;
11991879b088Sdan  }
12001879b088Sdan} -test {
12011879b088Sdan  faultsim_test_result {0 {}}
12021879b088Sdan
12031879b088Sdan  set contents [db eval {SELECT * FROM t1}]
12041879b088Sdan  if {$contents != "1 2"} { error "Bad database contents ($contents)" }
12051879b088Sdan
1206*b8fff29cSdan  if {[atomic_batch_write test.db]==0} {
12071879b088Sdan    set sz [file size test.db]
12081879b088Sdan    if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} {
1209*b8fff29cSdan      error "Expected file size 3072 or 12288 bytes - actual size $sz bytes"
12101879b088Sdan    }
12111879b088Sdan    if {$testrc==0 && $sz!=4096*3} {
12121879b088Sdan      error "Expected file size to be 12288 bytes - actual size $sz bytes"
12131879b088Sdan    }
12141879b088Sdan  }
1215*b8fff29cSdan}
12161879b088Sdan
1217f5d3df40Sdando_test pagerfault-27-pre {
1218f5d3df40Sdan  faultsim_delete_and_reopen
1219f5d3df40Sdan  db func a_string a_string
1220f5d3df40Sdan  execsql {
1221f5d3df40Sdan    PRAGMA page_size = 1024;
1222f5d3df40Sdan    CREATE TABLE t1(a, b);
1223f5d3df40Sdan    CREATE TABLE t2(a UNIQUE, b UNIQUE);
1224f5d3df40Sdan    INSERT INTO t2 VALUES( a_string(800), a_string(800) );
1225f5d3df40Sdan    INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1226f5d3df40Sdan    INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1227f5d3df40Sdan    INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1228f5d3df40Sdan    INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1229f5d3df40Sdan    INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1230f5d3df40Sdan    INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1231f5d3df40Sdan    INSERT INTO t1 VALUES (a_string(20000), a_string(20000));
1232f5d3df40Sdan  }
1233f5d3df40Sdan  faultsim_save_and_close
1234f5d3df40Sdan} {}
1235f5d3df40Sdando_faultsim_test pagerfault-27 -faults ioerr-persistent -prep {
1236f5d3df40Sdan  faultsim_restore_and_reopen
1237f5d3df40Sdan  db func a_string a_string
1238f5d3df40Sdan  execsql {
1239f5d3df40Sdan    PRAGMA cache_size = 10;
1240f5d3df40Sdan    BEGIN EXCLUSIVE;
1241f5d3df40Sdan  }
1242f5d3df40Sdan  set ::channel [db incrblob t1 a 1]
1243f5d3df40Sdan} -body {
1244f5d3df40Sdan  puts $::channel [string repeat abc 6000]
1245f5d3df40Sdan  flush $::channel
1246f5d3df40Sdan} -test {
12475f848c3aSdan  catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) }
1248f5d3df40Sdan  catch { close $::channel }
12495f848c3aSdan  catchsql { ROLLBACK }
1250f5d3df40Sdan  faultsim_integrity_check
1251f5d3df40Sdan}
125259257dc6Sdan
1253d7a558a9Sdan
1254db082408Sdan#-------------------------------------------------------------------------
1255db082408Sdan#
1256db082408Sdando_test pagerfault-28-pre {
1257db082408Sdan  faultsim_delete_and_reopen
1258db082408Sdan  db func a_string a_string
1259db082408Sdan  execsql {
1260db082408Sdan    PRAGMA page_size = 512;
1261db082408Sdan
1262db082408Sdan    PRAGMA journal_mode = wal;
1263db082408Sdan    PRAGMA wal_autocheckpoint = 0;
1264db082408Sdan    PRAGMA cache_size = 100000;
1265db082408Sdan
1266db082408Sdan    BEGIN;
1267db082408Sdan      CREATE TABLE t2(a UNIQUE, b UNIQUE);
1268db082408Sdan      INSERT INTO t2 VALUES( a_string(800), a_string(800) );
1269db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1270db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1271db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1272db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1273db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1274db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1275db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1276db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1277db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1278db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1279db082408Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1280db082408Sdan    COMMIT;
1281db082408Sdan    CREATE TABLE t1(a PRIMARY KEY, b);
1282db082408Sdan  }
1283db082408Sdan  expr {[file size test.db-shm] >= 96*1024}
1284db082408Sdan} {1}
1285db082408Sdanfaultsim_save_and_close
1286db082408Sdan
1287d7a558a9Sdando_faultsim_test pagerfault-28a -faults oom* -prep {
1288db082408Sdan  faultsim_restore_and_reopen
12899b4c59faSdrh  execsql { PRAGMA mmap_size=0 }
1290db082408Sdan
1291db082408Sdan  sqlite3 db2 test.db
1292db082408Sdan  db2 eval { SELECT count(*) FROM t2 }
1293db082408Sdan
1294db082408Sdan  db func a_string a_string
1295db082408Sdan  execsql {
1296db082408Sdan    BEGIN;
1297db082408Sdan      INSERT INTO t1 VALUES(a_string(2000), a_string(2000));
1298db082408Sdan      INSERT INTO t1 VALUES(a_string(2000), a_string(2000));
1299db082408Sdan  }
1300db082408Sdan  set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY]
1301db082408Sdan  sqlite3_step $::STMT
1302db082408Sdan} -body {
1303db082408Sdan  execsql { ROLLBACK }
1304db082408Sdan} -test {
1305db082408Sdan  db2 close
1306db082408Sdan  sqlite3_finalize $::STMT
1307db082408Sdan  catchsql { ROLLBACK }
1308db082408Sdan  faultsim_integrity_check
1309db082408Sdan}
1310db082408Sdan
1311d7a558a9Sdanfaultsim_restore_and_reopen
1312d7a558a9Sdansqlite3 db2 test.db
1313d7a558a9Sdandb2 eval {SELECT count(*) FROM t2}
1314d7a558a9Sdandb close
1315d7a558a9Sdan
1316d7a558a9Sdando_faultsim_test pagerfault-28b -faults oom* -prep {
1317d7a558a9Sdan  sqlite3 db test.db
1318d7a558a9Sdan} -body {
1319d7a558a9Sdan  execsql { SELECT count(*) FROM t2 }
1320d7a558a9Sdan} -test {
1321d7a558a9Sdan  faultsim_test_result {0 2048}
1322d7a558a9Sdan  db close
1323d7a558a9Sdan}
1324d7a558a9Sdan
1325d7a558a9Sdandb2 close
1326d7a558a9Sdan
1327d7a558a9Sdan#-------------------------------------------------------------------------
1328d7a558a9Sdan# Try this:
1329d7a558a9Sdan#
1330d7a558a9Sdan#    1) Put the pager in ERROR state (error during rollback)
1331d7a558a9Sdan#
1332d7a558a9Sdan#    2) Next time the connection is used inject errors into all xWrite() and
1333d7a558a9Sdan#       xUnlock() calls. This causes the hot-journal rollback to fail and
1334d7a558a9Sdan#       the pager to declare its locking state UNKNOWN.
1335d7a558a9Sdan#
1336d7a558a9Sdan#    3) Same again.
1337d7a558a9Sdan#
1338d7a558a9Sdan#    4a) Stop injecting errors. Allow the rollback to succeed. Check that
1339d7a558a9Sdan#        the database is Ok. Or,
1340d7a558a9Sdan#
1341d7a558a9Sdan#    4b) Close and reopen the db. Check that the db is Ok.
1342d7a558a9Sdan#
1343d7a558a9Sdanproc custom_injectinstall {} {
1344d7a558a9Sdan  testvfs custom -default true
1345d7a558a9Sdan  custom filter {xWrite xUnlock}
1346d7a558a9Sdan}
1347d7a558a9Sdanproc custom_injectuninstall {} {
1348d7a558a9Sdan  catch {db  close}
1349d7a558a9Sdan  catch {db2 close}
1350d7a558a9Sdan  custom delete
1351d7a558a9Sdan}
1352d7a558a9Sdanproc custom_injectstart {iFail} {
1353d7a558a9Sdan  custom ioerr $iFail 1
1354d7a558a9Sdan}
1355d7a558a9Sdanproc custom_injectstop {} {
1356d7a558a9Sdan  custom ioerr
1357d7a558a9Sdan}
1358d7a558a9Sdanset ::FAULTSIM(custom)          [list      \
1359d7a558a9Sdan  -injectinstall   custom_injectinstall    \
1360d7a558a9Sdan  -injectstart     custom_injectstart      \
1361d7a558a9Sdan  -injectstop      custom_injectstop       \
1362d7a558a9Sdan  -injecterrlist   {{1 {disk I/O error}}}  \
1363d7a558a9Sdan  -injectuninstall custom_injectuninstall  \
1364d7a558a9Sdan]
1365d7a558a9Sdan
1366d7a558a9Sdando_test pagerfault-29-pre {
1367d7a558a9Sdan  faultsim_delete_and_reopen
1368d7a558a9Sdan  db func a_string a_string
1369d7a558a9Sdan  execsql {
1370d7a558a9Sdan    PRAGMA page_size = 1024;
1371d7a558a9Sdan    PRAGMA cache_size = 5;
1372d7a558a9Sdan
1373d7a558a9Sdan    BEGIN;
1374d7a558a9Sdan      CREATE TABLE t2(a UNIQUE, b UNIQUE);
1375d7a558a9Sdan      INSERT INTO t2 VALUES( a_string(800), a_string(800) );
1376d7a558a9Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1377d7a558a9Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1378d7a558a9Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1379d7a558a9Sdan      INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
1380d7a558a9Sdan    COMMIT;
1381d7a558a9Sdan  }
1382d7a558a9Sdan  expr {[file size test.db] >= 50*1024}
1383d7a558a9Sdan} {1}
1384d7a558a9Sdanfaultsim_save_and_close
1385d7a558a9Sdanforeach {tn tt} {
1386d7a558a9Sdan  29 { catchsql ROLLBACK }
1387d7a558a9Sdan  30 { db close ; sqlite3 db test.db }
1388d7a558a9Sdan} {
1389d7a558a9Sdan  do_faultsim_test pagerfault-$tn -faults custom -prep {
1390d7a558a9Sdan    faultsim_restore_and_reopen
1391d7a558a9Sdan      db func a_string a_string
1392d7a558a9Sdan      execsql {
1393d7a558a9Sdan        PRAGMA cache_size = 5;
1394d7a558a9Sdan        BEGIN;
1395d7a558a9Sdan        UPDATE t2 SET a = a_string(799);
1396d7a558a9Sdan      }
1397d7a558a9Sdan  } -body {
1398d7a558a9Sdan    catchsql ROLLBACK
1399d7a558a9Sdan    catchsql ROLLBACK
1400d7a558a9Sdan    catchsql ROLLBACK
1401d7a558a9Sdan  } -test {
1402d7a558a9Sdan    eval $::tt
1403d7a558a9Sdan    if {"ok" != [db one {PRAGMA integrity_check}]} {
1404d7a558a9Sdan      error "integrity check failed"
1405d7a558a9Sdan    }
1406d7a558a9Sdan  }
1407d7a558a9Sdan}
1408d7a558a9Sdan
1409d7a558a9Sdando_test pagerfault-31-pre {
1410d7a558a9Sdan  sqlite3_shutdown
1411d7a558a9Sdan  sqlite3_config_uri 1
1412d7a558a9Sdan} {SQLITE_OK}
1413d7a558a9Sdando_faultsim_test pagerfault-31 -faults oom* -body {
1414d7a558a9Sdan  sqlite3 db {file:one?mode=memory&cache=shared}
1415d7a558a9Sdan  db eval {
1416d7a558a9Sdan    CREATE TABLE t1(x);
1417d7a558a9Sdan    INSERT INTO t1 VALUES(1);
1418d7a558a9Sdan    SELECT * FROM t1;
1419d7a558a9Sdan  }
1420d7a558a9Sdan} -test {
1421d7a558a9Sdan  faultsim_test_result {0 1} {1 {}}
1422d7a558a9Sdan  catch { db close }
1423d7a558a9Sdan}
1424d7a558a9Sdansqlite3_shutdown
1425d7a558a9Sdansqlite3_config_uri 0
1426d7a558a9Sdan
1427d7a558a9Sdando_test pagerfault-32-pre {
1428d7a558a9Sdan  reset_db
1429d7a558a9Sdan  execsql {
1430d7a558a9Sdan    CREATE TABLE t1(x);
1431d7a558a9Sdan    INSERT INTO t1 VALUES('one');
1432d7a558a9Sdan  }
1433d7a558a9Sdan} {}
1434d7a558a9Sdanfaultsim_save_and_close
1435d7a558a9Sdan
1436d7a558a9Sdando_faultsim_test pagerfault-32 -prep {
1437d7a558a9Sdan  faultsim_restore_and_reopen
1438d7a558a9Sdan  db eval { SELECT * FROM t1; }
1439d7a558a9Sdan} -body {
1440d7a558a9Sdan  execsql { SELECT * FROM t1; }
1441d7a558a9Sdan} -test {
1442d7a558a9Sdan  faultsim_test_result {0 one}
1443d7a558a9Sdan}
1444d7a558a9Sdansqlite3_shutdown
1445d7a558a9Sdansqlite3_config_uri 0
1446d7a558a9Sdan
1447d7a558a9Sdando_faultsim_test pagerfault-33a -prep {
1448d7a558a9Sdan  sqlite3 db :memory:
1449d7a558a9Sdan  execsql {
1450d7a558a9Sdan    CREATE TABLE t1(a, b);
1451d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
1452d7a558a9Sdan  }
1453d7a558a9Sdan} -body {
1454d7a558a9Sdan  execsql { VACUUM }
1455d7a558a9Sdan} -test {
1456d7a558a9Sdan  faultsim_test_result {0 {}}
1457d7a558a9Sdan}
1458d7a558a9Sdando_faultsim_test pagerfault-33b -prep {
1459d7a558a9Sdan  sqlite3 db ""
1460d7a558a9Sdan  execsql {
1461d7a558a9Sdan    CREATE TABLE t1(a, b);
1462d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
1463d7a558a9Sdan  }
1464d7a558a9Sdan} -body {
1465d7a558a9Sdan  execsql { VACUUM }
1466d7a558a9Sdan} -test {
1467d7a558a9Sdan  faultsim_test_result {0 {}}
1468d7a558a9Sdan}
1469d7a558a9Sdan
1470d7a558a9Sdando_test pagerfault-34-pre {
1471d7a558a9Sdan  reset_db
1472d7a558a9Sdan  execsql {
1473d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
1474d7a558a9Sdan  }
1475d7a558a9Sdan} {}
1476d7a558a9Sdanfaultsim_save_and_close
1477d7a558a9Sdando_faultsim_test pagerfault-34 -prep {
1478d7a558a9Sdan  faultsim_restore_and_reopen
1479d7a558a9Sdan  execsql {
1480d7a558a9Sdan    BEGIN;
1481d7a558a9Sdan      INSERT INTO t1 VALUES( randomblob(4000) );
1482d7a558a9Sdan      DELETE FROM t1;
1483d7a558a9Sdan  }
1484d7a558a9Sdan} -body {
1485d7a558a9Sdan  execsql COMMIT
1486d7a558a9Sdan} -test {
1487d7a558a9Sdan  faultsim_test_result {0 {}}
1488d7a558a9Sdan}
1489d7a558a9Sdan
1490abd6d84aSdando_test pagerfault-35-pre {
1491abd6d84aSdan  faultsim_delete_and_reopen
1492abd6d84aSdan  execsql {
1493abd6d84aSdan    CREATE TABLE t1(x PRIMARY KEY, y);
1494abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
1495abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
1496abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
1497abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
1498abd6d84aSdan  }
1499abd6d84aSdan  faultsim_save_and_close
1500abd6d84aSdan} {}
1501abd6d84aSdantestvfs tv -default 1
1502abd6d84aSdantv sectorsize 8192;
1503abd6d84aSdantv devchar [list]
1504abd6d84aSdando_faultsim_test pagerfault-35 -prep {
1505abd6d84aSdan  faultsim_restore_and_reopen
1506abd6d84aSdan} -body {
1507abd6d84aSdan  execsql { UPDATE t1 SET x=randomblob(200) }
1508abd6d84aSdan} -test {
1509abd6d84aSdan  faultsim_test_result {0 {}}
1510abd6d84aSdan}
1511abd6d84aSdancatch {db close}
1512abd6d84aSdantv delete
1513abd6d84aSdan
1514abd6d84aSdansqlite3_shutdown
1515abd6d84aSdansqlite3_config_uri 1
1516abd6d84aSdando_test pagerfault-36-pre {
1517abd6d84aSdan  faultsim_delete_and_reopen
1518abd6d84aSdan  execsql {
1519abd6d84aSdan    CREATE TABLE t1(x PRIMARY KEY, y);
1520abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
1521abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
1522abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
1523abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
1524abd6d84aSdan  }
1525abd6d84aSdan  faultsim_save_and_close
1526abd6d84aSdan} {}
1527abd6d84aSdando_faultsim_test pagerfault-36 -prep {
1528abd6d84aSdan  faultsim_restore
1529abd6d84aSdan  sqlite3 db file:test.db?cache=shared
1530abd6d84aSdan  sqlite3 db2 file:test.db?cache=shared
1531abd6d84aSdan  db2 eval {
1532abd6d84aSdan    BEGIN;
1533abd6d84aSdan    SELECT count(*) FROM sqlite_master;
1534abd6d84aSdan  }
1535abd6d84aSdan  db eval {
1536abd6d84aSdan    PRAGMA cache_size = 1;
1537abd6d84aSdan    BEGIN;
1538abd6d84aSdan      UPDATE t1 SET x = randomblob(200);
1539abd6d84aSdan  }
1540abd6d84aSdan} -body {
1541abd6d84aSdan  execsql ROLLBACK db
1542abd6d84aSdan} -test {
1543abd6d84aSdan  catch { db eval {UPDATE t1 SET x = randomblob(200)} }
1544abd6d84aSdan  faultsim_test_result {0 {}}
1545abd6d84aSdan  catch { db close }
1546abd6d84aSdan  catch { db2 close }
1547abd6d84aSdan}
1548abd6d84aSdan
1549abd6d84aSdansqlite3_shutdown
1550abd6d84aSdansqlite3_config_uri 0
1551d0879badSdansqlite3_initialize
1552d7a558a9Sdan
1553b0ac3e3aSdanfinish_test
1554