xref: /sqlite-3.40.0/test/pager1.test (revision d0b0d4dc)
1e91a54e1Sdan# 2010 June 15
2e91a54e1Sdan#
3e91a54e1Sdan# The author disclaims copyright to this source code.  In place of
4e91a54e1Sdan# a legal notice, here is a blessing:
5e91a54e1Sdan#
6e91a54e1Sdan#    May you do good and not evil.
7e91a54e1Sdan#    May you find forgiveness for yourself and forgive others.
8e91a54e1Sdan#    May you share freely, never taking more than you give.
9e91a54e1Sdan#
10e91a54e1Sdan#***********************************************************************
11e91a54e1Sdan#
12e91a54e1Sdan
13e91a54e1Sdanset testdir [file dirname $argv0]
14e91a54e1Sdansource $testdir/tester.tcl
15e91a54e1Sdansource $testdir/lock_common.tcl
16e91a54e1Sdansource $testdir/malloc_common.tcl
17153eda0aSdansource $testdir/wal_common.tcl
1868928b6cSdan
1968928b6cSdan# Do not use a codec for tests in this file, as the database file is
2068928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command).
2168928b6cSdan#
2268928b6cSdando_not_use_codec
23e91a54e1Sdan
24b0ac3e3aSdan#
25b0ac3e3aSdan# pager1-1.*: Test inter-process locking (clients in multiple processes).
26b0ac3e3aSdan#
27b0ac3e3aSdan# pager1-2.*: Test intra-process locking (multiple clients in this process).
28b0ac3e3aSdan#
29b0ac3e3aSdan# pager1-3.*: Savepoint related tests.
30b0ac3e3aSdan#
311f4cb65aSdan# pager1-4.*: Hot-journal related tests.
321f4cb65aSdan#
33de4996e2Sdan# pager1-5.*: Cases related to multi-file commits.
34de4996e2Sdan#
35146ed78bSdan# pager1-6.*: Cases related to "PRAGMA max_page_count"
36146ed78bSdan#
37153eda0aSdan# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
38153eda0aSdan#
390e986f51Sdan# pager1-8.*: Cases using temporary and in-memory databases.
400e986f51Sdan#
41dca321aeSdan# pager1-9.*: Tests related to the backup API.
42dca321aeSdan#
43ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to
44ec6ffc1aSdan#              64KB.
45ec6ffc1aSdan#
46d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size"
47d353331aSdan#
48d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST"
49d353331aSdan#
50d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF"
51ec6ffc1aSdan#
52c8ce3972Sdan# pager1-15.*: Varying sqlite3_vfs.szOsFile
53c8ce3972Sdan#
54c8ce3972Sdan# pager1-16.*: Varying sqlite3_vfs.mxPathname
55c8ce3972Sdan#
56c8ce3972Sdan# pager1-17.*: Tests related to "PRAGMA omit_readlock"
57c8ce3972Sdan#
58c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree
59c8ce3972Sdan#              requests an invalid page number (due to db corruption).
60c8ce3972Sdan#
61b0ac3e3aSdan
6253f04f3bSdanset a_string_counter 1
6353f04f3bSdanproc a_string {n} {
6453f04f3bSdan  global a_string_counter
6553f04f3bSdan  incr a_string_counter
6653f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
6753f04f3bSdan}
6853f04f3bSdandb func a_string a_string
6953f04f3bSdan
70a4a9095eSdando_multiclient_test tn {
71e91a54e1Sdan
72e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
73e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
74e91a54e1Sdan  #
75e91a54e1Sdan  do_test pager1-$tn.1 {
76e91a54e1Sdan    sql1 {
77e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
78e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
79d353331aSdan      INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
80e91a54e1Sdan    }
81e91a54e1Sdan  } {}
82e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
83e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
84e91a54e1Sdan
85e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
86e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
87e91a54e1Sdan  # read the database content as it was before the transaction was
88e91a54e1Sdan  # opened. [db] should see the inserted row.
89e91a54e1Sdan  #
90e91a54e1Sdan  do_test pager1-$tn.4 {
91e91a54e1Sdan    sql1 {
92e91a54e1Sdan      BEGIN;
93e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
94e91a54e1Sdan    }
95e91a54e1Sdan  } {}
96e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
97e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
98e91a54e1Sdan
99e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
100e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
101e91a54e1Sdan  #
102e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
103e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
104e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
105e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
106e91a54e1Sdan  #
107e91a54e1Sdan  do_test pager1-$tn.8 {
108e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
109e91a54e1Sdan  } {1 {database is locked}}
110e91a54e1Sdan  do_test pager1-$tn.9 {
111e91a54e1Sdan    csql2 {
112e91a54e1Sdan      BEGIN;
113e91a54e1Sdan      UPDATE t1 SET a = a + 10;
114e91a54e1Sdan    }
115e91a54e1Sdan  } {1 {database is locked}}
116e91a54e1Sdan
117e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
118e91a54e1Sdan  # now see the new database content.
119e91a54e1Sdan  #
120e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
121e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
122e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
123e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
124e91a54e1Sdan
125e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
126e91a54e1Sdan  # after the attempt to write the database failed.
127e91a54e1Sdan  #
128e91a54e1Sdan  do_test pager1-$tn.14 {
129e91a54e1Sdan    csql2 { BEGIN }
130e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
131e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
132e91a54e1Sdan
133e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
134e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
135e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
136e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
137e91a54e1Sdan  #
138e91a54e1Sdan  do_test pager1-$tn.15 {
139e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
140e91a54e1Sdan  } {1 one 2 two 3 three}
141e91a54e1Sdan  do_test pager1-$tn.16 {
142e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
143e91a54e1Sdan  } {1 {database is locked}}
144e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
145e91a54e1Sdan
146e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
147e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
148e91a54e1Sdan  # the SHARED lock [db2] is holding.
149e91a54e1Sdan  #
150e91a54e1Sdan  do_test pager1-$tn.18 {
151e91a54e1Sdan    sql1 {
152e91a54e1Sdan      BEGIN;
153e91a54e1Sdan      UPDATE t1 SET a = a + 10;
154e91a54e1Sdan    }
155e91a54e1Sdan  } {}
156e91a54e1Sdan  do_test pager1-$tn-19 {
157e91a54e1Sdan    sql1 { PRAGMA lock_status }
158e91a54e1Sdan  } {main reserved temp closed}
159e91a54e1Sdan  do_test pager1-$tn-20 {
160e91a54e1Sdan    sql2 { PRAGMA lock_status }
161e91a54e1Sdan  } {main shared temp closed}
162e91a54e1Sdan
163e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
164e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
165e91a54e1Sdan  #
166e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
167e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
168e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
169e91a54e1Sdan
170e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
171e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
172e91a54e1Sdan  # upgrades to a PENDING lock.
173e91a54e1Sdan  #
174e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
175e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
176e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
177e91a54e1Sdan  # the database.
178e91a54e1Sdan  #
179e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
180e91a54e1Sdan  do_test pager1-$tn-25 {
181e91a54e1Sdan    sql1 { PRAGMA lock_status }
182e91a54e1Sdan  } {main pending temp closed}
183e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
184e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
185e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
186e91a54e1Sdan
187e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
188e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
189e91a54e1Sdan  # is still holding a PENDING).
190e91a54e1Sdan  #
191e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
192e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
193e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
194e91a54e1Sdan
195e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
196e91a54e1Sdan  # committed, all three connections can read the new content.
197e91a54e1Sdan  #
198e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
199e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
200e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
201e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
202e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
203d353331aSdan
204d353331aSdan  # Install a busy-handler for connection [db].
205d353331aSdan  #
206d353331aSdan  set ::nbusy [list]
207d353331aSdan  proc busy {n} {
208d353331aSdan    lappend ::nbusy $n
209d353331aSdan    if {$n>5} { sql2 COMMIT }
210d353331aSdan    return 0
211d353331aSdan  }
212d353331aSdan  db busy busy
213d353331aSdan
214d353331aSdan  do_test pager1-$tn.29 {
215d353331aSdan    sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
216d353331aSdan  } {}
217d353331aSdan  do_test pager1-$tn.30 {
218d353331aSdan    sql2 { BEGIN ; SELECT * FROM t1 }
219d353331aSdan  } {21 one 22 two 23 three}
220d353331aSdan  do_test pager1-$tn.31 { sql1 COMMIT } {}
221d353331aSdan  do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
222e91a54e1Sdan}
223e91a54e1Sdan
22453f04f3bSdan#-------------------------------------------------------------------------
22553f04f3bSdan# Savepoint related test cases.
22653f04f3bSdan#
227dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
228dca321aeSdan#                 to grow.
229dca321aeSdan#
230273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
231273f3f0dSdan#                 of a savepoint rollback.
232273f3f0dSdan#
2330e986f51Sdando_test pager1-3.1.1 {
234b0ac3e3aSdan  faultsim_delete_and_reopen
235b0ac3e3aSdan  execsql {
236b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
237b0ac3e3aSdan    CREATE TABLE counter(
238b0ac3e3aSdan      i CHECK (i<5),
239b0ac3e3aSdan      u CHECK (u<10)
240b0ac3e3aSdan    );
241b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
242b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
243b0ac3e3aSdan      UPDATE counter SET i = i+1;
244b0ac3e3aSdan    END;
245b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
246b0ac3e3aSdan      UPDATE counter SET u = u+1;
247b0ac3e3aSdan    END;
248b0ac3e3aSdan  }
249b0ac3e3aSdan  execsql { SELECT * FROM counter }
250b0ac3e3aSdan} {0 0}
251b0ac3e3aSdan
2520e986f51Sdando_execsql_test pager1-3.1.2 {
253d353331aSdan  PRAGMA cache_size = 10;
254b0ac3e3aSdan  BEGIN;
255b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
256b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
257b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
258b0ac3e3aSdan    SELECT * FROM counter;
259b0ac3e3aSdan} {3 0}
2600e986f51Sdando_catchsql_test pager1-3.1.3 {
261b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
262b0ac3e3aSdan} {1 {constraint failed}}
263b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
264b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
265b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
266b0ac3e3aSdan
267273f3f0dSdanforeach {tn sql tcl} {
268d353331aSdan  7  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
269273f3f0dSdan    testvfs tv -default 1
270273f3f0dSdan    tv devchar safe_append
271273f3f0dSdan  }
272d353331aSdan  8  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
273d353331aSdan    testvfs tv -default 1
274d353331aSdan    tv devchar sequential
275d353331aSdan  }
276d353331aSdan  9  { PRAGMA synchronous = FULL } { }
277d353331aSdan  10 { PRAGMA synchronous = NORMAL } { }
278d353331aSdan  11 { PRAGMA synchronous = OFF } { }
279d353331aSdan  12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
280d353331aSdan  13 { PRAGMA synchronous = FULL } {
281d353331aSdan    testvfs tv -default 1
282d353331aSdan    tv devchar sequential
283d353331aSdan  }
2846b63ab47Sdan  14 { PRAGMA locking_mode = EXCLUSIVE } {
2856b63ab47Sdan  }
286273f3f0dSdan} {
287273f3f0dSdan  do_test pager1-3.$tn.1 {
288273f3f0dSdan    eval $tcl
289dca321aeSdan    faultsim_delete_and_reopen
290dca321aeSdan    db func a_string a_string
291273f3f0dSdan    execsql $sql
292dca321aeSdan    execsql {
293dca321aeSdan      PRAGMA auto_vacuum = 2;
294dca321aeSdan      PRAGMA cache_size = 10;
295dca321aeSdan      CREATE TABLE z(x INTEGER PRIMARY KEY, y);
296dca321aeSdan      BEGIN;
297dca321aeSdan        INSERT INTO z VALUES(NULL, a_string(800));
298dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
299dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
300dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
301dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
302dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
303dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
304dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
305dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
306dca321aeSdan      COMMIT;
307dca321aeSdan    }
308dca321aeSdan    execsql { PRAGMA auto_vacuum }
309dca321aeSdan  } {2}
310273f3f0dSdan  do_execsql_test pager1-3.$tn.2 {
311dca321aeSdan    BEGIN;
312dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
313dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
314dca321aeSdan      SAVEPOINT one;
315273f3f0dSdan        UPDATE z SET y = NULL WHERE x>256;
316dca321aeSdan        PRAGMA incremental_vacuum;
317dca321aeSdan        SELECT count(*) FROM z WHERE x < 100;
318dca321aeSdan      ROLLBACK TO one;
319dca321aeSdan    COMMIT;
320dca321aeSdan  } {99}
321dca321aeSdan
322273f3f0dSdan  do_execsql_test pager1-3.$tn.3 {
323273f3f0dSdan    BEGIN;
324273f3f0dSdan      SAVEPOINT one;
325273f3f0dSdan        UPDATE z SET y = y||x;
326273f3f0dSdan      ROLLBACK TO one;
327273f3f0dSdan    COMMIT;
328273f3f0dSdan    SELECT count(*) FROM z;
329273f3f0dSdan  } {258}
330273f3f0dSdan
331273f3f0dSdan  do_execsql_test pager1-3.$tn.4 {
332273f3f0dSdan    SAVEPOINT one;
333273f3f0dSdan      UPDATE z SET y = y||x;
334273f3f0dSdan    ROLLBACK TO one;
335273f3f0dSdan  } {}
336273f3f0dSdan  do_execsql_test pager1-3.$tn.5 {
337273f3f0dSdan    SELECT count(*) FROM z;
338273f3f0dSdan    RELEASE one;
339273f3f0dSdan    PRAGMA integrity_check;
340273f3f0dSdan  } {258 ok}
341273f3f0dSdan
342273f3f0dSdan  db close
343273f3f0dSdan  catch { tv delete }
344273f3f0dSdan}
345273f3f0dSdan
34653f04f3bSdan#-------------------------------------------------------------------------
34753f04f3bSdan# Hot journal rollback related test cases.
34853f04f3bSdan#
34953f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
35053f04f3bSdan#               journal files.
35153f04f3bSdan#
35253f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
35353f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
35453f04f3bSdan#               compute) the associated journal is rolled back (and no
35553f04f3bSdan#               xAccess() call to check for the presence of any master
35653f04f3bSdan#               journal file is made).
35753f04f3bSdan#
358de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
359de4996e2Sdan#               page-size or sector-size in the journal header appear to
360de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
361de4996e2Sdan#
362e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
363e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
364e08341c6Sdan#               modes.
365e08341c6Sdan#
366e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
367e08341c6Sdan#               journal-record for which the checksum fails.
368e08341c6Sdan#
369ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
370ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
371ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
372ec6ffc1aSdan#
373c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can
374c8ce3972Sdan#               open it for reading only, the database cannot be accessed and
375c8ce3972Sdan#               SQLITE_CANTOPEN is returned.
376c8ce3972Sdan#
37753f04f3bSdando_test pager1.4.1.1 {
37853f04f3bSdan  faultsim_delete_and_reopen
37953f04f3bSdan  execsql {
38053f04f3bSdan    CREATE TABLE x(y, z);
38153f04f3bSdan    INSERT INTO x VALUES(1, 2);
38253f04f3bSdan  }
38353f04f3bSdan  set fd [open test.db-journal w]
38453f04f3bSdan  puts -nonewline $fd "helloworld"
38553f04f3bSdan  close $fd
38653f04f3bSdan  file exists test.db-journal
38753f04f3bSdan} {1}
38853f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
38953f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
39053f04f3bSdan
39153f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
39253f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
39353f04f3bSdan#
39453f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
39553f04f3bSdan# up the file system to contain two databases, two hot-journal files and
39653f04f3bSdan# a master-journal.
39753f04f3bSdan#
39853f04f3bSdando_test pager1.4.2.1 {
39953f04f3bSdan  testvfs tstvfs -default 1
40053f04f3bSdan  tstvfs filter xDelete
40153f04f3bSdan  tstvfs script xDeleteCallback
40253f04f3bSdan  proc xDeleteCallback {method file args} {
40353f04f3bSdan    set file [file tail $file]
40453f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
40553f04f3bSdan  }
40653f04f3bSdan  faultsim_delete_and_reopen
40753f04f3bSdan  db func a_string a_string
40853f04f3bSdan  execsql {
40953f04f3bSdan    ATTACH 'test.db2' AS aux;
41053f04f3bSdan    PRAGMA journal_mode = DELETE;
41153f04f3bSdan    PRAGMA main.cache_size = 10;
41253f04f3bSdan    PRAGMA aux.cache_size = 10;
41353f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
41453f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
41553f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
41653f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
41753f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
41853f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
41953f04f3bSdan    BEGIN;
42053f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
42153f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
42253f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
42353f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
42453f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
42553f04f3bSdan    COMMIT;
42653f04f3bSdan  }
42753f04f3bSdan  db close
42853f04f3bSdan  tstvfs delete
42953f04f3bSdan} {}
43053f04f3bSdando_test pager1.4.2.2 {
43153f04f3bSdan  faultsim_restore_and_reopen
43253f04f3bSdan  execsql {
43353f04f3bSdan    SELECT count(*) FROM t1;
43453f04f3bSdan    PRAGMA integrity_check;
43553f04f3bSdan  }
43653f04f3bSdan} {4 ok}
43753f04f3bSdando_test pager1.4.2.3 {
43853f04f3bSdan  faultsim_restore_and_reopen
43953f04f3bSdan  foreach f [glob test.db-mj*] { file delete -force $f }
44053f04f3bSdan  execsql {
44153f04f3bSdan    SELECT count(*) FROM t1;
44253f04f3bSdan    PRAGMA integrity_check;
44353f04f3bSdan  }
44453f04f3bSdan} {64 ok}
44553f04f3bSdando_test pager1.4.2.4 {
44653f04f3bSdan  faultsim_restore_and_reopen
44753f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
44853f04f3bSdan  execsql {
44953f04f3bSdan    SELECT count(*) FROM t1;
45053f04f3bSdan    PRAGMA integrity_check;
45153f04f3bSdan  }
45253f04f3bSdan} {4 ok}
45353f04f3bSdando_test pager1.4.2.5 {
45453f04f3bSdan  faultsim_restore_and_reopen
45553f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
45653f04f3bSdan  foreach f [glob test.db-mj*] { file delete -force $f }
45753f04f3bSdan  execsql {
45853f04f3bSdan    SELECT count(*) FROM t1;
45953f04f3bSdan    PRAGMA integrity_check;
46053f04f3bSdan  }
46153f04f3bSdan} {4 ok}
46253f04f3bSdan
463de4996e2Sdando_test pager1.4.3.1 {
464de4996e2Sdan  testvfs tstvfs -default 1
465de4996e2Sdan  tstvfs filter xSync
466de4996e2Sdan  tstvfs script xSyncCallback
467de4996e2Sdan  proc xSyncCallback {method file args} {
468de4996e2Sdan    set file [file tail $file]
469de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
470de4996e2Sdan  }
471de4996e2Sdan  faultsim_delete_and_reopen
472de4996e2Sdan  execsql {
473de4996e2Sdan    PRAGMA journal_mode = DELETE;
474de4996e2Sdan    CREATE TABLE t1(a, b);
475de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
476de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
477de4996e2Sdan  }
478de4996e2Sdan  db close
479de4996e2Sdan  tstvfs delete
480de4996e2Sdan} {}
481de4996e2Sdan
482de4996e2Sdanforeach {tn ofst value result} {
483de4996e2Sdan          2   20    31       {1 2 3 4}
484de4996e2Sdan          3   20    32       {1 2 3 4}
485de4996e2Sdan          4   20    33       {1 2 3 4}
486de4996e2Sdan          5   20    65536    {1 2 3 4}
487de4996e2Sdan          6   20    131072   {1 2 3 4}
488de4996e2Sdan
489de4996e2Sdan          7   24    511      {1 2 3 4}
490de4996e2Sdan          8   24    513      {1 2 3 4}
491de4996e2Sdan          9   24    65536    {1 2 3 4}
492de4996e2Sdan
493de4996e2Sdan         10   32    65536    {1 2}
494de4996e2Sdan} {
495de4996e2Sdan  do_test pager1.4.3.$tn {
496de4996e2Sdan    faultsim_restore_and_reopen
497de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
498de4996e2Sdan    execsql { SELECT * FROM t1 }
499de4996e2Sdan  } $result
500de4996e2Sdan}
501de4996e2Sdandb close
502de4996e2Sdan
503e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
504e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
505e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
506e08341c6Sdan# master journal file from the file-system.
507e08341c6Sdan#
508e08341c6Sdantestvfs tv -default 1
509e08341c6Sdantv script copy_on_mj_delete
510e08341c6Sdanset ::mj_filename_length 0
511e08341c6Sdanproc copy_on_mj_delete {method filename args} {
512e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
513e08341c6Sdan    set ::mj_filename_length [string length $filename]
514e08341c6Sdan    faultsim_save
515e08341c6Sdan  }
516e08341c6Sdan  return SQLITE_OK
517e08341c6Sdan}
518e08341c6Sdan
519e08341c6Sdanset pwd [pwd]
520e08341c6Sdanforeach {tn1 tcl} {
521e08341c6Sdan  1 { set prefix "test.db" }
522e08341c6Sdan  2 {
523e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
524e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
525e08341c6Sdan    # contains a master-journal pointer so large that it could contain
526e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
527e08341c6Sdan    # make sure SQLite doesn't get confused by this.
528e08341c6Sdan    #
529e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
530e08341c6Sdan
531e08341c6Sdan    # We cannot just create a really long database file name to open, as
532e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
533e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
534e08341c6Sdan    # hierarchy to work in.
535e08341c6Sdan    #
536e08341c6Sdan    set dirname "d123456789012345678901234567890/"
537e08341c6Sdan    set nDir [expr $nPadding / 32]
538e08341c6Sdan    if { $nDir } {
539e08341c6Sdan      set p [string repeat $dirname $nDir]
540e08341c6Sdan      file mkdir $p
541e08341c6Sdan      cd $p
542e08341c6Sdan    }
543e08341c6Sdan
544e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
545e08341c6Sdan    set prefix "test.db${padding}"
546e08341c6Sdan  }
547e08341c6Sdan} {
548e08341c6Sdan  eval $tcl
549e08341c6Sdan  foreach {tn2 sql} {
550e08341c6Sdan    o {
551e08341c6Sdan      PRAGMA main.synchronous=OFF;
552e08341c6Sdan      PRAGMA aux.synchronous=OFF;
553e08341c6Sdan    }
554e08341c6Sdan    o512 {
555e08341c6Sdan      PRAGMA main.synchronous=OFF;
556e08341c6Sdan      PRAGMA aux.synchronous=OFF;
557e08341c6Sdan      PRAGMA main.page_size = 512;
558e08341c6Sdan      PRAGMA aux.page_size = 512;
559e08341c6Sdan    }
560e08341c6Sdan    n {
561e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
562e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
563e08341c6Sdan    }
564e08341c6Sdan    f {
565e08341c6Sdan      PRAGMA main.synchronous=FULL;
566e08341c6Sdan      PRAGMA aux.synchronous=FULL;
567e08341c6Sdan    }
568e08341c6Sdan  } {
569e08341c6Sdan
570e08341c6Sdan    set tn "${tn1}.${tn2}"
571e08341c6Sdan
572e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
573e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
574e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
575e08341c6Sdan    # file is deleted to commit the transaction.
576e08341c6Sdan    #
577e08341c6Sdan    tv filter xDelete
578e08341c6Sdan    do_test pager1-4.4.$tn.1 {
579e08341c6Sdan      faultsim_delete_and_reopen $prefix
580e08341c6Sdan      execsql "
581e08341c6Sdan        ATTACH '${prefix}2' AS aux;
582e08341c6Sdan        $sql
583e08341c6Sdan        CREATE TABLE a(x);
584e08341c6Sdan        CREATE TABLE aux.b(x);
585e08341c6Sdan        INSERT INTO a VALUES('double-you');
586e08341c6Sdan        INSERT INTO a VALUES('why');
587e08341c6Sdan        INSERT INTO a VALUES('zed');
588e08341c6Sdan        INSERT INTO b VALUES('won');
589e08341c6Sdan        INSERT INTO b VALUES('too');
590e08341c6Sdan        INSERT INTO b VALUES('free');
591e08341c6Sdan      "
592e08341c6Sdan      execsql {
593e08341c6Sdan        BEGIN;
594e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
595e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
596e08341c6Sdan        COMMIT;
597e08341c6Sdan      }
598e08341c6Sdan    } {}
599e08341c6Sdan    tv filter {}
600e08341c6Sdan
601e08341c6Sdan    # Check that the transaction was committed successfully.
602e08341c6Sdan    #
603e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
604e08341c6Sdan      SELECT * FROM a
605e08341c6Sdan    } {double-you why zed won too free}
606e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
607e08341c6Sdan      SELECT * FROM b
608e08341c6Sdan    } {won too free double-you why zed}
609e08341c6Sdan
610e08341c6Sdan    # Restore the file-system and reopen the databases. Check that it now
611e08341c6Sdan    # appears that the transaction was not committed (because the file-system
612e08341c6Sdan    # was restored to the state where it had not been).
613e08341c6Sdan    #
614e08341c6Sdan    do_test pager1-4.4.$tn.4 {
615e08341c6Sdan      faultsim_restore_and_reopen $prefix
616e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
617e08341c6Sdan    } {}
618e08341c6Sdan    do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
619e08341c6Sdan    do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
620e08341c6Sdan
621e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
622e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
623e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
624e08341c6Sdan    #
625e08341c6Sdan    do_test pager1-4.4.$tn.7 {
626e08341c6Sdan      faultsim_restore_and_reopen $prefix
627e08341c6Sdan      foreach f [glob ${prefix}-mj*] { file delete -force $f }
628e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
629e08341c6Sdan    } {}
630e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
631e08341c6Sdan      SELECT * FROM a
632e08341c6Sdan    } {double-you why zed won too free}
633e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
634e08341c6Sdan      SELECT * FROM b
635e08341c6Sdan    } {won too free double-you why zed}
636e08341c6Sdan  }
637e08341c6Sdan
638e08341c6Sdan  cd $pwd
639e08341c6Sdan}
640e08341c6Sdandb close
641e08341c6Sdantv delete
6420e986f51Sdanfile delete -force $dirname
6430e986f51Sdan
6440e986f51Sdan
6450e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
6460e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
6470e986f51Sdan# two database pages (and page 1 - the change counter).
6480e986f51Sdan#
6490e986f51Sdantestvfs tv -default 1
6500e986f51Sdantv sectorsize 512
6510e986f51Sdantv script copy_on_journal_delete
6520e986f51Sdantv filter xDelete
6530e986f51Sdanproc copy_on_journal_delete {method filename args} {
6540e986f51Sdan  if {[string match *journal $filename]} faultsim_save
6550e986f51Sdan  return SQLITE_OK
6560e986f51Sdan}
6570e986f51Sdanfaultsim_delete_and_reopen
6580e986f51Sdando_execsql_test pager1.4.5.1 {
6590e986f51Sdan  PRAGMA page_size = 1024;
6600e986f51Sdan  CREATE TABLE t1(a, b);
6610e986f51Sdan  CREATE TABLE t2(a, b);
6620e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
6630e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
6640e986f51Sdan  BEGIN;
6650e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
6660e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
6670e986f51Sdan  COMMIT;
6680e986f51Sdan} {}
6690e986f51Sdantv filter {}
6700e986f51Sdan
6710e986f51Sdan# Check the transaction was committed:
6720e986f51Sdan#
6730e986f51Sdando_execsql_test pager1.4.5.2 {
6740e986f51Sdan  SELECT * FROM t1;
6750e986f51Sdan  SELECT * FROM t2;
6760e986f51Sdan} {I II 1 2 III IV 3 4}
6770e986f51Sdan
678ec6ffc1aSdan# Now try four tests:
6790e986f51Sdan#
6800e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
6810e986f51Sdan#                is rolled back.
6820e986f51Sdan#
6830e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
6840e986f51Sdan#                journal. Check the transaction is not rolled back.
6850e986f51Sdan#
6860e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
6870e986f51Sdan#                journal. Check that the first record in the transaction is
6880e986f51Sdan#                played back, but not the second.
6890e986f51Sdan#
69010f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
69110f5a50eSdan#                readonly connection. This should fail, as a read-only
69210f5a50eSdan#                connection cannot roll back the database file.
69310f5a50eSdan#
6940e986f51Sdanfaultsim_restore_and_reopen
6950e986f51Sdando_execsql_test pager1.4.5.3 {
6960e986f51Sdan  SELECT * FROM t1;
6970e986f51Sdan  SELECT * FROM t2;
6980e986f51Sdan} {I II III IV}
6990e986f51Sdanfaultsim_restore_and_reopen
7000e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
7010e986f51Sdando_execsql_test pager1.4.5.4 {
7020e986f51Sdan  SELECT * FROM t1;
7030e986f51Sdan  SELECT * FROM t2;
7040e986f51Sdan} {I II 1 2 III IV 3 4}
7050e986f51Sdanfaultsim_restore_and_reopen
7060e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
7070e986f51Sdando_execsql_test pager1.4.5.5 {
7080e986f51Sdan  SELECT * FROM t1;
7090e986f51Sdan  SELECT * FROM t2;
7100e986f51Sdan} {I II III IV 3 4}
7110e986f51Sdan
71210f5a50eSdanfaultsim_restore_and_reopen
71310f5a50eSdandb close
71410f5a50eSdansqlite3 db test.db -readonly 1
71510f5a50eSdando_catchsql_test pager1.4.5.6 {
71610f5a50eSdan  SELECT * FROM t1;
71710f5a50eSdan  SELECT * FROM t2;
71810f5a50eSdan} {1 {disk I/O error}}
719ec6ffc1aSdandb close
720ec6ffc1aSdan
721ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
722ec6ffc1aSdan# of the master journal file in $::mj_filename.
723ec6ffc1aSdan#
724ec6ffc1aSdantv script copy_on_mj_delete
725ec6ffc1aSdantv filter xDelete
726ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
727ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
728ec6ffc1aSdan    set ::mj_filename $filename
729ec6ffc1aSdan    faultsim_save
730ec6ffc1aSdan  }
731ec6ffc1aSdan  return SQLITE_OK
732ec6ffc1aSdan}
733ec6ffc1aSdando_test pager1.4.6.1 {
734ec6ffc1aSdan  faultsim_delete_and_reopen
735ec6ffc1aSdan  execsql {
736ec6ffc1aSdan    ATTACH 'test.db2' AS two;
737ec6ffc1aSdan    CREATE TABLE t1(a, b);
738ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
739ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
740ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
741ec6ffc1aSdan    BEGIN;
742ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
743ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
744ec6ffc1aSdan    COMMIT;
745ec6ffc1aSdan  }
746ec6ffc1aSdan  tv filter {}
747ec6ffc1aSdan  db close
748ec6ffc1aSdan} {}
749ec6ffc1aSdan
750ec6ffc1aSdanfaultsim_restore_and_reopen
751ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
752ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
753ec6ffc1aSdando_execsql_test pager1.4.6.4 {
754ec6ffc1aSdan  ATTACH 'test.db2' AS two;
755ec6ffc1aSdan  SELECT * FROM t2;
756ec6ffc1aSdan} {1 t2.1}
757ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
758ec6ffc1aSdan
759ec6ffc1aSdanfaultsim_restore_and_reopen
760ec6ffc1aSdandb close
761ec6ffc1aSdando_test pager1.4.6.8 {
762ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
763ec6ffc1aSdan  tv filter xDelete
764ec6ffc1aSdan  sqlite3 db test.db2
765ec6ffc1aSdan  execsql {
766ec6ffc1aSdan    ATTACH 'test.db3' AS three;
767ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
768ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
769ec6ffc1aSdan    BEGIN;
770ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
771ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
772ec6ffc1aSdan    COMMIT;
773ec6ffc1aSdan  }
774ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
775ec6ffc1aSdan} {1}
776ec6ffc1aSdanfaultsim_restore_and_reopen
777ec6ffc1aSdantv filter {}
778ec6ffc1aSdan
779ec6ffc1aSdan# The file-system now contains:
780ec6ffc1aSdan#
781ec6ffc1aSdan#   * three databases
782ec6ffc1aSdan#   * three hot-journal files
783ec6ffc1aSdan#   * two master-journal files.
784ec6ffc1aSdan#
785ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
786ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
787ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
788ec6ffc1aSdan# test.db should delete $::mj_filename1.
789ec6ffc1aSdan#
790ec6ffc1aSdando_test pager1.4.6.9 {
791ec6ffc1aSdan  lsort [glob test.db*]
792ec6ffc1aSdan} [lsort [list                                           \
793ec6ffc1aSdan  test.db test.db2 test.db3                              \
794ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
795ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
796ec6ffc1aSdan]]
797ec6ffc1aSdan
798ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
799ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
800ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
801ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
802ec6ffc1aSdan#
803ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
804ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
805ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
806ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
807ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
808ec6ffc1aSdan
809ec6ffc1aSdando_execsql_test pager1.4.6.12 {
810ec6ffc1aSdan  ATTACH 'test.db2' AS two;
811ec6ffc1aSdan  SELECT * FROM t2;
812ec6ffc1aSdan} {1 t2.1}
813ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
814ec6ffc1aSdando_execsql_test pager1.4.6.14 {
815ec6ffc1aSdan  ATTACH 'test.db3' AS three;
816ec6ffc1aSdan  SELECT * FROM t3;
817ec6ffc1aSdan} {1 t3.1}
818ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
81910f5a50eSdan
8200e986f51Sdandb close
8210e986f51Sdantv delete
822e08341c6Sdan
823c8ce3972Sdantestvfs tv -default 1
824c8ce3972Sdantv sectorsize 512
825c8ce3972Sdantv script copy_on_journal_delete
826c8ce3972Sdantv filter xDelete
827c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
828c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
829c8ce3972Sdan  return SQLITE_OK
830c8ce3972Sdan}
831c8ce3972Sdanfaultsim_delete_and_reopen
832c8ce3972Sdando_execsql_test pager1.4.7.1 {
833c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
834c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
835c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
836c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
837c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
838c8ce3972Sdan  BEGIN;
839c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
840c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
841c8ce3972Sdan  COMMIT;
842c8ce3972Sdan} {}
843c8ce3972Sdantv filter {}
844c8ce3972Sdandb close
845c8ce3972Sdantv delete
846c8ce3972Sdando_test pager1.4.7.2 {
847c8ce3972Sdan  faultsim_restore_and_reopen
848c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
849c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
850c8ce3972Sdan  catchsql { SELECT * FROM t1 }
851c8ce3972Sdan} {1 {unable to open database file}}
852c8ce3972Sdando_test pager1.4.7.3 {
853c8ce3972Sdan  db close
854c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
855c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
856c8ce3972Sdan  file delete test.db-journal
857c8ce3972Sdan  file exists test.db-journal
858c8ce3972Sdan} {0}
859c8ce3972Sdan
860de4996e2Sdan#-------------------------------------------------------------------------
861146ed78bSdan# The following tests deal with multi-file commits.
862de4996e2Sdan#
863146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
864146ed78bSdan#               another connection is holding a SHARED lock on one of the
865146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
866146ed78bSdan#
867146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
868146ed78bSdan#
869146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
870146ed78bSdan#
871146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
872146ed78bSdan#               name is added to a journal file immediately after the last
873146ed78bSdan#               journal record. But with synchronous=full, extra unused space
874146ed78bSdan#               is allocated between the last journal record and the
875146ed78bSdan#               master-journal file name so that the master-journal file
876146ed78bSdan#               name does not lie on the same sector as the last journal file
877146ed78bSdan#               record.
878146ed78bSdan#
879e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
880e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
881e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
882e08341c6Sdan#
883146ed78bSdan#
884146ed78bSdando_test pager1-5.1.1 {
885146ed78bSdan  faultsim_delete_and_reopen
886146ed78bSdan  execsql {
887146ed78bSdan    ATTACH 'test.db2' AS aux;
888146ed78bSdan    CREATE TABLE t1(a, b);
889146ed78bSdan    CREATE TABLE aux.t2(a, b);
890146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
891146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
892146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
893146ed78bSdan  }
894146ed78bSdan} {}
895146ed78bSdando_test pager1-5.1.2 {
896146ed78bSdan  execsql {
897146ed78bSdan    BEGIN;
898146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
899146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
900146ed78bSdan  }
901146ed78bSdan  sqlite3 db2 test.db2
902146ed78bSdan  execsql {
903146ed78bSdan    BEGIN;
904146ed78bSdan      SELECT * FROM t2;
905146ed78bSdan  } db2
906146ed78bSdan} {}
907146ed78bSdando_test pager1-5.1.3 {
908146ed78bSdan  catchsql COMMIT
909146ed78bSdan} {1 {database is locked}}
910146ed78bSdando_test pager1-5.1.4 {
911146ed78bSdan  execsql COMMIT db2
912146ed78bSdan  execsql COMMIT
913146ed78bSdan  execsql { SELECT * FROM t2 } db2
914146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
915146ed78bSdando_test pager1-5.1.5 {
916146ed78bSdan  db2 close
917146ed78bSdan} {}
918146ed78bSdan
919146ed78bSdando_test pager1-5.2.1 {
920146ed78bSdan  execsql {
921146ed78bSdan    PRAGMA journal_mode = memory;
922146ed78bSdan    BEGIN;
923146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
924146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
925146ed78bSdan    COMMIT;
926146ed78bSdan  }
927146ed78bSdan} {memory}
928146ed78bSdando_test pager1-5.3.1 {
929146ed78bSdan  execsql {
930146ed78bSdan    PRAGMA journal_mode = off;
931146ed78bSdan    BEGIN;
932146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
933146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
934146ed78bSdan    COMMIT;
935146ed78bSdan  }
936146ed78bSdan} {off}
937146ed78bSdan
938146ed78bSdando_test pager1-5.4.1 {
939146ed78bSdan  db close
940146ed78bSdan  testvfs tv
941146ed78bSdan  sqlite3 db test.db -vfs tv
942146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
943146ed78bSdan
944146ed78bSdan  tv filter xDelete
945146ed78bSdan  tv script max_journal_size
946146ed78bSdan  tv sectorsize 512
947146ed78bSdan  set ::max_journal 0
948146ed78bSdan  proc max_journal_size {method args} {
949146ed78bSdan    set sz 0
950146ed78bSdan    catch { set sz [file size test.db-journal] }
951146ed78bSdan    if {$sz > $::max_journal} {
952146ed78bSdan      set ::max_journal $sz
953146ed78bSdan    }
954146ed78bSdan    return SQLITE_OK
955146ed78bSdan  }
956146ed78bSdan  execsql {
957146ed78bSdan    PRAGMA journal_mode = DELETE;
958146ed78bSdan    PRAGMA synchronous = NORMAL;
959146ed78bSdan    BEGIN;
960146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
961146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
962146ed78bSdan    COMMIT;
963146ed78bSdan  }
964146ed78bSdan  set ::max_journal
965146ed78bSdan} [expr 2615+[string length [pwd]]]
966146ed78bSdando_test pager1-5.4.2 {
967146ed78bSdan  set ::max_journal 0
968146ed78bSdan  execsql {
969146ed78bSdan    PRAGMA synchronous = full;
970146ed78bSdan    BEGIN;
971146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
972146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
973146ed78bSdan    COMMIT;
974146ed78bSdan  }
975146ed78bSdan  set ::max_journal
976146ed78bSdan} [expr 3111+[string length [pwd]]]
977146ed78bSdandb close
978146ed78bSdantv delete
979146ed78bSdan
980146ed78bSdando_test pager1-5.5.1 {
981146ed78bSdan  sqlite3 db test.db
982146ed78bSdan  execsql {
983146ed78bSdan    ATTACH 'test.db2' AS aux;
984146ed78bSdan    PRAGMA journal_mode = PERSIST;
985146ed78bSdan    CREATE TABLE t3(a, b);
986146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
987146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
988146ed78bSdan  }
989146ed78bSdan  expr [file size test.db-journal] > 15000
990146ed78bSdan} {1}
991146ed78bSdando_test pager1-5.5.2 {
992146ed78bSdan  execsql {
993146ed78bSdan    PRAGMA synchronous = full;
994146ed78bSdan    BEGIN;
995146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
996146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
997146ed78bSdan    COMMIT;
998146ed78bSdan  }
999146ed78bSdan  file size test.db-journal
1000146ed78bSdan} {0}
1001146ed78bSdan
1002146ed78bSdan
1003146ed78bSdan#-------------------------------------------------------------------------
1004146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1005146ed78bSdan#
1006146ed78bSdando_test pager1-6.1 {
1007146ed78bSdan  faultsim_delete_and_reopen
1008146ed78bSdan  execsql {
1009146ed78bSdan    PRAGMA max_page_count = 10;
1010146ed78bSdan    CREATE TABLE t2(a, b);
1011146ed78bSdan    CREATE TABLE t3(a, b);
1012146ed78bSdan    CREATE TABLE t4(a, b);
1013146ed78bSdan    CREATE TABLE t5(a, b);
1014146ed78bSdan    CREATE TABLE t6(a, b);
1015146ed78bSdan    CREATE TABLE t7(a, b);
1016146ed78bSdan    CREATE TABLE t8(a, b);
1017146ed78bSdan    CREATE TABLE t9(a, b);
1018146ed78bSdan    CREATE TABLE t10(a, b);
1019146ed78bSdan  }
1020146ed78bSdan} {10}
1021d353331aSdando_catchsql_test pager1-6.2 {
1022d353331aSdan  CREATE TABLE t11(a, b)
1023146ed78bSdan} {1 {database or disk is full}}
1024d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1025d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1026d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1027d353331aSdando_execsql_test pager1-6.7 {
1028d353331aSdan  BEGIN;
1029d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1030d353331aSdan    PRAGMA max_page_count = 13;
1031d353331aSdan} {13}
1032d353331aSdando_execsql_test pager1-6.8 {
1033d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1034d353331aSdan    PRAGMA max_page_count = 10;
1035d353331aSdan} {11}
1036d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1037de4996e2Sdan
1038153eda0aSdan
1039153eda0aSdan#-------------------------------------------------------------------------
1040153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1041153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1042153eda0aSdan#
1043153eda0aSdan# Each test is specified with 5 variables. As follows:
1044153eda0aSdan#
1045153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1046153eda0aSdan#   $sql: SQL to execute.
1047153eda0aSdan#   $res: Expected result of executing $sql.
1048153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1049153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1050153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1051153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1052153eda0aSdan#
105338e1a279Sdanifcapable wal {
1054153eda0aSdan  faultsim_delete_and_reopen
1055153eda0aSdan  foreach {tn sql res js ws} [subst {
1056153eda0aSdan
1057153eda0aSdan    1  {
1058153eda0aSdan      CREATE TABLE t1(a, b);
1059153eda0aSdan      PRAGMA auto_vacuum=OFF;
1060153eda0aSdan      PRAGMA synchronous=NORMAL;
1061153eda0aSdan      PRAGMA page_size=1024;
1062153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1063153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1064153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1065153eda0aSdan    } {exclusive truncate} 0 -1
1066153eda0aSdan
1067153eda0aSdan    2  {
1068153eda0aSdan      BEGIN IMMEDIATE;
1069153eda0aSdan        SELECT * FROM t1;
1070153eda0aSdan      COMMIT;
1071153eda0aSdan    } {1 2} 0 -1
1072153eda0aSdan
1073153eda0aSdan    3  {
1074153eda0aSdan      BEGIN;
1075153eda0aSdan        SELECT * FROM t1;
1076153eda0aSdan      COMMIT;
1077153eda0aSdan    } {1 2} 0 -1
1078153eda0aSdan
1079153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal    -1 -1
1080153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}     -1 [wal_file_size 1 1024]
1081153eda0aSdan    6  { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024]
1082153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}     -1 [wal_file_size 2 1024]
1083153eda0aSdan
1084153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1085153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1086153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1087153eda0aSdan
1088153eda0aSdan  }] {
1089153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1090153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1091153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1092153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1093153eda0aSdan  }
109438e1a279Sdan}
1095153eda0aSdan
109689ccf448Sdando_test pager1-7.2.1 {
109789ccf448Sdan  faultsim_delete_and_reopen
109889ccf448Sdan  execsql {
109989ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
110089ccf448Sdan    CREATE TABLE t1(a, b);
110189ccf448Sdan    BEGIN;
110289ccf448Sdan      PRAGMA journal_mode = delete;
110389ccf448Sdan      PRAGMA journal_mode = truncate;
110489ccf448Sdan  }
110589ccf448Sdan} {exclusive delete truncate}
110689ccf448Sdando_test pager1-7.2.2 {
110789ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
110889ccf448Sdan  execsql { PRAGMA journal_mode = persist }
110989ccf448Sdan} {truncate}
111089ccf448Sdando_test pager1-7.2.3 {
111189ccf448Sdan  execsql { COMMIT }
111289ccf448Sdan  execsql {
111389ccf448Sdan    PRAGMA journal_mode = persist;
111489ccf448Sdan    PRAGMA journal_size_limit;
111589ccf448Sdan  }
111689ccf448Sdan} {persist -1}
111789ccf448Sdan
1118d353331aSdan#-------------------------------------------------------------------------
1119d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1120d353331aSdan# ":memory:" and "" open temporary databases.
1121d353331aSdan#
11220e986f51Sdanforeach {tn filename} {
11230e986f51Sdan  1 :memory:
11240e986f51Sdan  2 ""
11250e986f51Sdan} {
11260e986f51Sdan  do_test pager1-8.$tn.1 {
1127153eda0aSdan    faultsim_delete_and_reopen
1128153eda0aSdan    db close
11290e986f51Sdan    sqlite3 db $filename
1130153eda0aSdan    execsql {
1131c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1132153eda0aSdan      CREATE TABLE x1(x);
1133153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1134153eda0aSdan      INSERT INTO x1 VALUES('James');
1135153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1136153eda0aSdan      SELECT * FROM x1;
1137153eda0aSdan    }
1138153eda0aSdan  } {Charles James Mary}
11390e986f51Sdan
11400e986f51Sdan  do_test pager1-8.$tn.2 {
11410e986f51Sdan    sqlite3 db2 $filename
11420e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1143153eda0aSdan  } {1 {no such table: x1}}
1144153eda0aSdan
11450e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
11460e986f51Sdan    BEGIN;
11470e986f51Sdan      INSERT INTO x1 VALUES('William');
11480e986f51Sdan      INSERT INTO x1 VALUES('Anne');
11490e986f51Sdan    ROLLBACK;
11500e986f51Sdan  } {}
11510e986f51Sdan}
11520e986f51Sdan
1153dca321aeSdan#-------------------------------------------------------------------------
1154dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1155dca321aeSdan# the pager and the backup API. Test cases:
1156dca321aeSdan#
1157dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1158dca321aeSdan#                 source db is written to during the backup op.
1159dca321aeSdan#
1160dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1161dca321aeSdan#                 source db is written to and then rolled back during a
1162dca321aeSdan#                 backup operation.
1163dca321aeSdan#
1164dca321aeSdando_test pager1-9.0.1 {
1165dca321aeSdan  faultsim_delete_and_reopen
1166dca321aeSdan  db func a_string a_string
1167dca321aeSdan  execsql {
1168dca321aeSdan    PRAGMA cache_size = 10;
1169dca321aeSdan    BEGIN;
1170dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1171dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1172dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1173dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1174dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1175dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1176dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1177dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1178dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1179dca321aeSdan    COMMIT;
1180dca321aeSdan  }
1181dca321aeSdan} {}
1182dca321aeSdando_test pager1-9.0.2 {
1183dca321aeSdan  sqlite3 db2 test.db2
1184dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1185dca321aeSdan  sqlite3_backup B db2 main db main
1186dca321aeSdan  list [B step 10000] [B finish]
1187dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1188dca321aeSdando_test pager1-9.0.3 {
1189dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1190dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1191dca321aeSdan
1192dca321aeSdando_test pager1-9.1.1 {
1193dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1194dca321aeSdan  sqlite3_backup B db2 main db main
1195dca321aeSdan  B step 30
1196dca321aeSdan} {SQLITE_OK}
1197dca321aeSdando_test pager1-9.1.2 {
1198dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1199dca321aeSdan  list [B step 10000] [B finish]
1200dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1201dca321aeSdando_test pager1-9.1.3 {
1202dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1203dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1204dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1205dca321aeSdan
1206dca321aeSdando_test pager1-9.2.1 {
1207dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1208dca321aeSdan  sqlite3_backup B db2 main db main
1209dca321aeSdan  B step 30
1210dca321aeSdan} {SQLITE_OK}
1211dca321aeSdando_test pager1-9.2.2 {
1212dca321aeSdan  execsql {
1213dca321aeSdan    BEGIN;
1214dca321aeSdan      UPDATE ab SET b = a_string(301);
1215dca321aeSdan    ROLLBACK;
1216dca321aeSdan  }
1217dca321aeSdan  list [B step 10000] [B finish]
1218dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1219dca321aeSdando_test pager1-9.2.3 {
1220dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1221dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1222dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1223ec6ffc1aSdandb close
1224ec6ffc1aSdandb2 close
1225ec6ffc1aSdan
1226*d0b0d4dcSdanproc recursive_select {id table {script {}}} {
1227*d0b0d4dcSdan  set cnt 0
1228*d0b0d4dcSdan  db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
1229*d0b0d4dcSdan    recursive_select $rowid $table $script
1230*d0b0d4dcSdan    incr cnt
1231*d0b0d4dcSdan  }
1232*d0b0d4dcSdan  if {$cnt==0} { eval $script }
1233*d0b0d4dcSdan}
1234*d0b0d4dcSdan
1235ec6ffc1aSdan#-------------------------------------------------------------------------
1236ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1237ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1238ec6ffc1aSdan#
1239ec6ffc1aSdantestvfs tv -default 1
1240ec6ffc1aSdanforeach sectorsize {
1241ec6ffc1aSdan    32   64   128   256   512   1024   2048
1242ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1243ec6ffc1aSdan} {
1244ec6ffc1aSdan  tv sectorsize $sectorsize
1245ec6ffc1aSdan  set eff $sectorsize
1246ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1247ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1248ec6ffc1aSdan
1249*d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1250ec6ffc1aSdan    faultsim_delete_and_reopen
1251*d0b0d4dcSdan    db func a_string a_string
1252ec6ffc1aSdan    execsql {
1253ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1254ec6ffc1aSdan      PRAGMA page_size = 1024;
1255*d0b0d4dcSdan      BEGIN;
1256ec6ffc1aSdan        CREATE TABLE t1(a, b);
1257*d0b0d4dcSdan        CREATE TABLE t2(a, b);
1258*d0b0d4dcSdan        CREATE TABLE t3(a, b);
1259*d0b0d4dcSdan      COMMIT;
1260ec6ffc1aSdan    }
1261ec6ffc1aSdan    file size test.db-journal
1262ec6ffc1aSdan  } [expr $sectorsize > 65536 ? 65536 : $sectorsize]
1263*d0b0d4dcSdan
1264*d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1265*d0b0d4dcSdan    execsql {
1266*d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1267*d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1268*d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1269*d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1270*d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1271*d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1272ec6ffc1aSdan    }
1273*d0b0d4dcSdan  } {}
1274*d0b0d4dcSdan
1275*d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1276*d0b0d4dcSdan    db close
1277*d0b0d4dcSdan    sqlite3 db test.db
1278*d0b0d4dcSdan    execsql {
1279*d0b0d4dcSdan      PRAGMA cache_size = 10;
1280*d0b0d4dcSdan      BEGIN;
1281*d0b0d4dcSdan    }
1282*d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1283*d0b0d4dcSdan    execsql {
1284*d0b0d4dcSdan      COMMIT;
1285*d0b0d4dcSdan      SELECT * FROM t2;
1286*d0b0d4dcSdan    }
1287*d0b0d4dcSdan  } {1 2}
1288*d0b0d4dcSdan
1289*d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1290*d0b0d4dcSdan    execsql {
1291*d0b0d4dcSdan      CREATE TABLE t6(a, b);
1292*d0b0d4dcSdan      CREATE TABLE t7(a, b);
1293*d0b0d4dcSdan      CREATE TABLE t5(a, b);
1294*d0b0d4dcSdan      DROP TABLE t6;
1295*d0b0d4dcSdan      DROP TABLE t7;
1296*d0b0d4dcSdan    }
1297*d0b0d4dcSdan    if {$eff==65536} breakpoint
1298*d0b0d4dcSdan    execsql {
1299*d0b0d4dcSdan      BEGIN;
1300*d0b0d4dcSdan        CREATE TABLE t6(a, b);
1301*d0b0d4dcSdan    }
1302*d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1303*d0b0d4dcSdan    execsql {
1304*d0b0d4dcSdan      COMMIT;
1305*d0b0d4dcSdan      SELECT * FROM t5;
1306*d0b0d4dcSdan    }
1307*d0b0d4dcSdan  } {1 2}
1308*d0b0d4dcSdan
1309*d0b0d4dcSdan}
1310*d0b0d4dcSdandb close
1311*d0b0d4dcSdan
1312*d0b0d4dcSdantv sectorsize 4096
1313*d0b0d4dcSdando_test pager1.10.x.1 {
1314*d0b0d4dcSdan  faultsim_delete_and_reopen
1315*d0b0d4dcSdan  execsql {
1316*d0b0d4dcSdan    PRAGMA page_size = 1024;
1317*d0b0d4dcSdan    CREATE TABLE t1(x);
1318*d0b0d4dcSdan  }
1319*d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1320*d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1321*d0b0d4dcSdan  }
1322*d0b0d4dcSdan  file size test.db
1323*d0b0d4dcSdan} {32768}
1324*d0b0d4dcSdando_test pager1.10.x.2 {
1325*d0b0d4dcSdan  execsql {
1326*d0b0d4dcSdan    CREATE TABLE t2(x);
1327*d0b0d4dcSdan    DROP TABLE t2;
1328*d0b0d4dcSdan  }
1329*d0b0d4dcSdan  file size test.db
1330*d0b0d4dcSdan} {33792}
1331*d0b0d4dcSdando_test pager1.10.x.3 {
1332*d0b0d4dcSdan  execsql {
1333*d0b0d4dcSdan    BEGIN;
1334*d0b0d4dcSdan    CREATE TABLE t2(x);
1335*d0b0d4dcSdan  }
1336*d0b0d4dcSdan  recursive_select 30 t1
1337*d0b0d4dcSdan  execsql {
1338*d0b0d4dcSdan    CREATE TABLE t3(x);
1339*d0b0d4dcSdan    COMMIT;
1340*d0b0d4dcSdan  }
1341*d0b0d4dcSdan} {}
1342*d0b0d4dcSdan
1343ec6ffc1aSdandb close
1344ec6ffc1aSdantv delete
1345ec6ffc1aSdan
1346ec6ffc1aSdantestvfs tv -default 1
1347ec6ffc1aSdanfaultsim_delete_and_reopen
1348ec6ffc1aSdandb func a_string a_string
1349ec6ffc1aSdando_execsql_test pager1-11.1 {
1350ec6ffc1aSdan  PRAGMA cache_size = 10;
1351ec6ffc1aSdan  BEGIN;
1352ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1353ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1354ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1355ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1356ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1357ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1358ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1359ec6ffc1aSdan  COMMIT;
1360ec6ffc1aSdan  BEGIN;
1361ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
1362ec6ffc1aSdan} {}
1363ec6ffc1aSdan
1364ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1365ec6ffc1aSdantv script lockout
1366ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1367ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1368ec6ffc1aSdan
1369ec6ffc1aSdantv script {}
1370ec6ffc1aSdando_test pager1-11.3 {
1371ec6ffc1aSdan  sqlite3 db2 test.db
1372ec6ffc1aSdan  execsql {
1373ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1374ec6ffc1aSdan    PRAGMA integrity_check;
1375ec6ffc1aSdan  } db2
1376ec6ffc1aSdan} {truncate ok}
1377ec6ffc1aSdando_test pager1-11.4 {
1378ec6ffc1aSdan  db2 close
1379ec6ffc1aSdan  file size test.db-journal
1380ec6ffc1aSdan} {0}
1381ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1382f9b4419dSdandb close
1383f9b4419dSdantv delete
1384ec6ffc1aSdan
1385f9b4419dSdan#-------------------------------------------------------------------------
1386f9b4419dSdan# Test "PRAGMA page_size"
1387f9b4419dSdan#
1388f9b4419dSdanforeach pagesize {
1389f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1390f9b4419dSdan} {
1391f9b4419dSdan  faultsim_delete_and_reopen
1392f9b4419dSdan
1393f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1394f9b4419dSdan    sqlite3 db2 test.db
1395f9b4419dSdan    execsql "
1396f9b4419dSdan      PRAGMA page_size = $pagesize;
1397f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1398f9b4419dSdan    " db2
1399f9b4419dSdan    file size test.db
1400f9b4419dSdan  } $pagesize
1401f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1402f9b4419dSdan    sqlite3 db2 test.db
1403f9b4419dSdan    execsql {
1404f9b4419dSdan      SELECT count(*) FROM v;
1405f9b4419dSdan      PRAGMA main.page_size;
1406f9b4419dSdan    } db2
1407f9b4419dSdan  } [list 1 $pagesize]
1408f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1409f9b4419dSdan    execsql {
1410f9b4419dSdan      SELECT count(*) FROM v;
1411f9b4419dSdan      PRAGMA main.page_size;
1412f9b4419dSdan    }
1413f9b4419dSdan  } [list 1 $pagesize]
1414f9b4419dSdan  db2 close
1415f9b4419dSdan}
1416dca321aeSdan
1417d353331aSdan#-------------------------------------------------------------------------
1418d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1419d353331aSdan#
1420d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1421d353331aSdan#                journal mode: If the journal associated with a transaction
1422d353331aSdan#                is smaller than the journal file (because a previous
1423d353331aSdan#                transaction left a very large non-hot journal file in the
1424d353331aSdan#                file-system), then SQLite has to be careful that there is
1425d353331aSdan#                not a journal-header left over from a previous transaction
1426d353331aSdan#                immediately following the journal content just written.
1427d353331aSdan#                If there is, and the process crashes so that the journal
1428d353331aSdan#                becomes a hot-journal and must be rolled back by another
1429d353331aSdan#                process, there is a danger that the other process may roll
1430d353331aSdan#                back the aborted transaction, then continue copying data
1431d353331aSdan#                from an older transaction from the remainder of the journal.
1432d353331aSdan#                See the syncJournal() function for details.
1433d353331aSdan#
1434d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1435d353331aSdan#                the mix to make the integrity-check more likely to catch
1436d353331aSdan#                errors.
1437d353331aSdan#
1438d353331aSdantestvfs tv -default 1
1439d353331aSdantv script xSyncCb
1440d353331aSdantv filter xSync
1441d353331aSdanproc xSyncCb {method filename args} {
1442d353331aSdan  set t [file tail $filename]
1443d353331aSdan  if {$t == "test.db"} faultsim_save
1444d353331aSdan  return SQLITE_OK
1445d353331aSdan}
1446d353331aSdanfaultsim_delete_and_reopen
1447d353331aSdandb func a_string a_string
1448e91a54e1Sdan
1449d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1450d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1451d353331aSdan# frequent journal headers.
1452d353331aSdan#
1453d353331aSdando_execsql_test pager1-13.1.1 {
1454d353331aSdan  PRAGMA page_size = 1024;
1455d353331aSdan  PRAGMA journal_mode = PERSIST;
1456d353331aSdan  PRAGMA cache_size = 10;
1457d353331aSdan  BEGIN;
1458d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1459d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1460d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1461d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1462d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1463d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1464d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1465d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1466d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1467d353331aSdan  COMMIT;
1468d353331aSdan  UPDATE t1 SET b = a_string(400);
1469d353331aSdan} {persist}
1470d353331aSdan
1471d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1472d353331aSdan# of these will write just enough content that one of the old headers created
1473d353331aSdan# by the transaction in the block above lies immediately after the content
1474d353331aSdan# journalled by the current transaction.
1475d353331aSdan#
1476d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1477d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1478d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1479d353331aSdan  } {}
1480d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1481d353331aSdan
1482d353331aSdan  # Try to access the snapshot of the file-system.
1483d353331aSdan  #
1484d353331aSdan  sqlite3 db2 sv_test.db
1485d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1486d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1487d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1488d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1489d353331aSdan    execsql { PRAGMA integrity_check } db2
1490d353331aSdan  } {ok}
1491d353331aSdan  db2 close
1492d353331aSdan}
1493d353331aSdan
1494d353331aSdan# Same test as above. But this time with an index on the table.
1495d353331aSdan#
1496d353331aSdando_execsql_test pager1-13.2.1 {
1497d353331aSdan  CREATE INDEX i1 ON t1(b);
1498d353331aSdan  UPDATE t1 SET b = a_string(400);
1499d353331aSdan} {}
1500d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1501d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1502d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1503d353331aSdan  } {}
1504d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1505d353331aSdan  sqlite3 db2 sv_test.db
1506d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1507d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1508d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1509d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1510d353331aSdan    execsql { PRAGMA integrity_check } db2
1511d353331aSdan  } {ok}
1512d353331aSdan  db2 close
1513d353331aSdan}
1514d353331aSdan
1515d353331aSdandb close
1516d353331aSdantv delete
1517d353331aSdan
1518d353331aSdan#-------------------------------------------------------------------------
1519d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1520d353331aSdan#
1521d353331aSdanfaultsim_delete_and_reopen
1522d353331aSdando_execsql_test pager1-14.1.1 {
1523d353331aSdan  PRAGMA journal_mode = OFF;
1524d353331aSdan  CREATE TABLE t1(a, b);
1525d353331aSdan  BEGIN;
1526d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1527d353331aSdan  COMMIT;
1528d353331aSdan  SELECT * FROM t1;
1529d353331aSdan} {off 1 2}
1530d353331aSdando_catchsql_test pager1-14.1.2 {
1531d353331aSdan  BEGIN;
1532d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1533d353331aSdan  ROLLBACK;
1534d353331aSdan} {0 {}}
1535d353331aSdando_execsql_test pager1-14.1.3 {
1536d353331aSdan  SELECT * FROM t1;
1537d353331aSdan} {1 2 3 4}
1538d353331aSdando_catchsql_test pager1-14.1.4 {
1539d353331aSdan  BEGIN;
1540d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1541d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1542d353331aSdan} {1 {PRIMARY KEY must be unique}}
1543d353331aSdando_execsql_test pager1-14.1.5 {
1544d353331aSdan  COMMIT;
1545d353331aSdan  SELECT * FROM t1;
1546d353331aSdan} {1 2 3 4 2 2 4 4}
1547d353331aSdan
1548c8ce3972Sdan#-------------------------------------------------------------------------
1549c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1550c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1551c8ce3972Sdan#
1552c8ce3972Sdanfaultsim_delete_and_reopen
1553c8ce3972Sdando_execsql_test pager1-15.0 {
1554c8ce3972Sdan  CREATE TABLE tx(y, z);
1555c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1556c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1557c8ce3972Sdan} {}
1558c8ce3972Sdandb close
1559c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1560c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1561c8ce3972Sdan  sqlite3 db test.db
1562c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1563c8ce3972Sdan    SELECT * FROM tx;
1564c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1565c8ce3972Sdan  db close
1566c8ce3972Sdan  tv delete
1567c8ce3972Sdan}
1568c8ce3972Sdan
1569c8ce3972Sdan#-------------------------------------------------------------------------
1570c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1571c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1572c8ce3972Sdan#
1573c8ce3972Sdantestvfs tv -default 1
1574c8ce3972Sdantv script xOpenCb
1575c8ce3972Sdantv filter xOpen
1576c8ce3972Sdanproc xOpenCb {method filename} {
1577c8ce3972Sdan  set ::file_len [string length $filename]
1578c8ce3972Sdan}
1579c8ce3972Sdansqlite3 db test.db
1580c8ce3972Sdandb close
1581c8ce3972Sdantv delete
1582c8ce3972Sdan
1583c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1584c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1585c8ce3972Sdan
1586c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1587c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1588c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1589c8ce3972Sdan  #
1590c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1591c8ce3972Sdan    set res {0 {}}
1592c8ce3972Sdan  } else {
1593c8ce3972Sdan    set res {1 {unable to open database file}}
1594c8ce3972Sdan  }
1595c8ce3972Sdan
1596c8ce3972Sdan  do_test pager1-16.1.$ii {
1597c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1598c8ce3972Sdan  } $res
1599c8ce3972Sdan
1600c8ce3972Sdan  catch {db close}
1601c8ce3972Sdan  tv delete
1602c8ce3972Sdan}
1603c8ce3972Sdan
1604c8ce3972Sdan#-------------------------------------------------------------------------
1605c8ce3972Sdan# Test "PRAGMA omit_readlock".
1606c8ce3972Sdan#
1607c8ce3972Sdan#   pager1-17.$tn.1.*: Test that if a second connection has an open
1608c8ce3972Sdan#                      read-transaction, it is not usually possible to write
1609c8ce3972Sdan#                      the database.
1610c8ce3972Sdan#
1611c8ce3972Sdan#   pager1-17.$tn.2.*: Test that if the second connection was opened with
1612c8ce3972Sdan#                      the SQLITE_OPEN_READONLY flag, and
1613c8ce3972Sdan#                      "PRAGMA omit_readlock = 1" is executed before attaching
1614c8ce3972Sdan#                      the database and opening a read-transaction on it, it is
1615c8ce3972Sdan#                      possible to write the db.
1616c8ce3972Sdan#
1617c8ce3972Sdan#   pager1-17.$tn.3.*: Test that if the second connection was *not* opened with
1618c8ce3972Sdan#                      the SQLITE_OPEN_READONLY flag, executing
1619c8ce3972Sdan#                      "PRAGMA omit_readlock = 1" has no effect.
1620c8ce3972Sdan#
1621c8ce3972Sdando_multiclient_test tn {
1622c8ce3972Sdan  do_test pager1-17.$tn.1.1 {
1623c8ce3972Sdan    sql1 {
1624c8ce3972Sdan      CREATE TABLE t1(a, b);
1625c8ce3972Sdan      INSERT INTO t1 VALUES(1, 2);
1626c8ce3972Sdan    }
1627c8ce3972Sdan    sql2 {
1628c8ce3972Sdan      BEGIN;
1629c8ce3972Sdan      SELECT * FROM t1;
1630c8ce3972Sdan    }
1631c8ce3972Sdan  } {1 2}
1632c8ce3972Sdan  do_test pager1-17.$tn.1.2 {
1633c8ce3972Sdan    csql1 { INSERT INTO t1 VALUES(3, 4) }
1634c8ce3972Sdan  } {1 {database is locked}}
1635c8ce3972Sdan  do_test pager1-17.$tn.1.3 {
1636c8ce3972Sdan    sql2 { COMMIT }
1637c8ce3972Sdan    sql1 { INSERT INTO t1 VALUES(3, 4) }
1638c8ce3972Sdan  } {}
1639c8ce3972Sdan
1640c8ce3972Sdan  do_test pager1-17.$tn.2.1 {
1641c8ce3972Sdan    code2 {
1642c8ce3972Sdan      db2 close
1643c8ce3972Sdan      sqlite3 db2 :memory: -readonly 1
1644c8ce3972Sdan    }
1645c8ce3972Sdan    sql2 {
1646c8ce3972Sdan      PRAGMA omit_readlock = 1;
1647c8ce3972Sdan      ATTACH 'test.db' AS two;
1648c8ce3972Sdan      BEGIN;
1649c8ce3972Sdan      SELECT * FROM t1;
1650c8ce3972Sdan    }
1651c8ce3972Sdan  } {1 2 3 4}
1652c8ce3972Sdan  do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {}
1653c8ce3972Sdan  do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" }            {1 2 3 4}
1654c8ce3972Sdan  do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" }   {1 2 3 4 5 6}
1655c8ce3972Sdan
1656c8ce3972Sdan  do_test pager1-17.$tn.3.1 {
1657c8ce3972Sdan    code2 {
1658c8ce3972Sdan      db2 close
1659c8ce3972Sdan      sqlite3 db2 :memory:
1660c8ce3972Sdan    }
1661c8ce3972Sdan    sql2 {
1662c8ce3972Sdan      PRAGMA omit_readlock = 1;
1663c8ce3972Sdan      ATTACH 'test.db' AS two;
1664c8ce3972Sdan      BEGIN;
1665c8ce3972Sdan      SELECT * FROM t1;
1666c8ce3972Sdan    }
1667c8ce3972Sdan  } {1 2 3 4 5 6}
1668c8ce3972Sdan  do_test pager1-17.$tn.3.2 {
1669c8ce3972Sdan    csql1 { INSERT INTO t1 VALUES(3, 4) }
1670c8ce3972Sdan  } {1 {database is locked}}
1671c8ce3972Sdan  do_test pager1-17.$tn.3.3 { sql2 COMMIT } {}
1672c8ce3972Sdan}
1673c8ce3972Sdan
1674c8ce3972Sdan#-------------------------------------------------------------------------
1675c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1676c8ce3972Sdan# numbers:
1677c8ce3972Sdan#
1678c8ce3972Sdan#   + The locking page,
1679c8ce3972Sdan#   + Page 0,
1680c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1681c8ce3972Sdan#
1682c8ce3972Sdando_test pager1-18.1 {
1683c8ce3972Sdan  faultsim_delete_and_reopen
1684c8ce3972Sdan  db func a_string a_string
1685c8ce3972Sdan  execsql {
1686c8ce3972Sdan    PRAGMA page_size = 1024;
1687c8ce3972Sdan    CREATE TABLE t1(a, b);
1688c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1689c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1690c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1691c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1692c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1693c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1694c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1695c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1696c8ce3972Sdan  }
1697c8ce3972Sdan} {}
1698c8ce3972Sdando_test pager1-18.2 {
1699c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1700c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1701c8ce3972Sdan  execsql {
1702c8ce3972Sdan    PRAGMA writable_schema = 1;
1703c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1704c8ce3972Sdan  }
1705c8ce3972Sdan  sqlite3 db2 test.db
1706c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1707c8ce3972Sdan} {1 {database disk image is malformed}}
1708c8ce3972Sdandb2 close
1709c8ce3972Sdando_test pager1-18.3 {
1710c8ce3972Sdan  execsql {
1711c8ce3972Sdan    CREATE TABLE t2(x);
1712c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1713c8ce3972Sdan  }
1714c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1715c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1716c8ce3972Sdan  sqlite3 db2 test.db
1717c8ce3972Sdan  catchsql { SELECT length(x) FROM t2 } db2
1718c8ce3972Sdan} {1 {database disk image is malformed}}
1719c8ce3972Sdandb2 close
1720c8ce3972Sdando_test pager1-18.4 {
1721c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1722c8ce3972Sdan  sqlite3 db2 test.db
1723c8ce3972Sdan  catchsql { SELECT length(x) FROM t2 } db2
1724c8ce3972Sdan} {1 {database disk image is malformed}}
1725c8ce3972Sdandb2 close
1726c8ce3972Sdando_test pager1-18.5 {
1727c8ce3972Sdan  sqlite3 db ""
1728c8ce3972Sdan  execsql {
1729c8ce3972Sdan    CREATE TABLE t1(a, b);
1730c8ce3972Sdan    CREATE TABLE t2(a, b);
1731c8ce3972Sdan    PRAGMA writable_schema = 1;
1732c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1733c8ce3972Sdan    PRAGMA writable_schema = 0;
1734c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1735c8ce3972Sdan  }
1736c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1737ba3cbf3dSdan} {1 {database disk image is malformed}}
1738c8ce3972Sdandb close
1739c8ce3972Sdan
1740ba3cbf3dSdando_test pager1-18.6 {
1741ba3cbf3dSdan  faultsim_delete_and_reopen
1742ba3cbf3dSdan  db func a_string a_string
1743ba3cbf3dSdan  execsql {
1744ba3cbf3dSdan    PRAGMA page_size = 1024;
1745ba3cbf3dSdan    CREATE TABLE t1(x);
1746ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1747ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1748ba3cbf3dSdan  }
1749ba3cbf3dSdan
1750ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1751ba3cbf3dSdan  db close
1752ba3cbf3dSdan
1753ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1754ba3cbf3dSdan  sqlite3 db test.db
1755ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1756ba3cbf3dSdan} {1 {database disk image is malformed}}
1757ba3cbf3dSdan
1758ba3cbf3dSdando_test pager1-19.1 {
1759ba3cbf3dSdan  sqlite3 db ""
1760ba3cbf3dSdan  db func a_string a_string
1761ba3cbf3dSdan  execsql {
1762ba3cbf3dSdan    PRAGMA page_size = 512;
1763ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1764ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1765ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1766ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1767ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1768ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1769ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1770ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1771ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1772ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1773ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1774ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1775ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1776ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1777ba3cbf3dSdan    );
1778ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1779ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1780ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1781ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1782ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1783ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1784ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1785ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1786ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1787ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1788ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1789ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1790ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1791ba3cbf3dSdan    );
1792ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
1793ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
1794ba3cbf3dSdan    VACUUM;
1795ba3cbf3dSdan  }
1796ba3cbf3dSdan} {}
1797ba3cbf3dSdan
17986b63ab47Sdan#-------------------------------------------------------------------------
17996b63ab47Sdan# Test a couple of special cases that come up while committing
18006b63ab47Sdan# transactions:
18016b63ab47Sdan#
18026b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
18036b63ab47Sdan#                  database has not been modified at all.
18046b63ab47Sdan#
18056b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
18066b63ab47Sdan#
18076b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
18086b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
18096b63ab47Sdan#                  disk before the commit.
18106b63ab47Sdan#
18116b63ab47Sdando_test pager1-20.1.1 {
18126b63ab47Sdan  catch {db close}
18136b63ab47Sdan  sqlite3 db :memory:
18146b63ab47Sdan  execsql {
18156b63ab47Sdan    CREATE TABLE one(two, three);
18166b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
18176b63ab47Sdan  }
18186b63ab47Sdan} {}
18196b63ab47Sdando_test pager1-20.1.2 {
18206b63ab47Sdan  execsql {
18216b63ab47Sdan    BEGIN EXCLUSIVE;
18226b63ab47Sdan    COMMIT;
18236b63ab47Sdan  }
18246b63ab47Sdan} {}
18256b63ab47Sdan
18266b63ab47Sdando_test pager1-20.2.1 {
18276b63ab47Sdan  faultsim_delete_and_reopen
18286b63ab47Sdan  execsql {
18296b63ab47Sdan    PRAGMA locking_mode = exclusive;
18306b63ab47Sdan    PRAGMA journal_mode = persist;
18316b63ab47Sdan    CREATE TABLE one(two, three);
18326b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
18336b63ab47Sdan  }
18346b63ab47Sdan} {exclusive persist}
18356b63ab47Sdando_test pager1-20.2.2 {
18366b63ab47Sdan  execsql {
18376b63ab47Sdan    BEGIN EXCLUSIVE;
18386b63ab47Sdan    COMMIT;
18396b63ab47Sdan  }
18406b63ab47Sdan} {}
18416b63ab47Sdan
18426b63ab47Sdando_test pager1-20.3.1 {
18436b63ab47Sdan  faultsim_delete_and_reopen
18446b63ab47Sdan  db func a_string a_string
18456b63ab47Sdan  execsql {
18466b63ab47Sdan    PRAGMA cache_size = 10;
18476b63ab47Sdan    PRAGMA journal_mode = wal;
18486b63ab47Sdan    BEGIN;
18496b63ab47Sdan      CREATE TABLE t1(x);
18506b63ab47Sdan      CREATE TABLE t2(y);
18516b63ab47Sdan      INSERT INTO t1 VALUES(a_string(800));
18526b63ab47Sdan      INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
18536b63ab47Sdan      INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
18546b63ab47Sdan      INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
18556b63ab47Sdan      INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
18566b63ab47Sdan      INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
18576b63ab47Sdan    COMMIT;
18586b63ab47Sdan  }
18596b63ab47Sdan} {wal}
18606b63ab47Sdando_test pager1-20.3.2 {
18616b63ab47Sdan  proc recursive_select {id} {
18626b63ab47Sdan    db eval {SELECT rowid, x FROM t1 WHERE rowid = ($id-1)} {
18636b63ab47Sdan      recursive_select $rowid
18646b63ab47Sdan    }
18656b63ab47Sdan  }
18666b63ab47Sdan  execsql {
18676b63ab47Sdan    BEGIN;
18686b63ab47Sdan    INSERT INTO t2 VALUES('xxxx');
18696b63ab47Sdan  }
18706b63ab47Sdan  recursive_select 32
18716b63ab47Sdan  execsql COMMIT
18726b63ab47Sdan} {}
18736b63ab47Sdan
187489ccf448Sdan#-------------------------------------------------------------------------
187589ccf448Sdan# Test that a WAL database may not be opened if:
187689ccf448Sdan#
187789ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
187889ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
187989ccf448Sdan#
188089ccf448Sdando_test pager1-21.0 {
188189ccf448Sdan  faultsim_delete_and_reopen
188289ccf448Sdan  execsql {
188389ccf448Sdan    PRAGMA journal_mode = WAL;
188489ccf448Sdan    CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
188589ccf448Sdan    INSERT INTO ko DEFAULT VALUES;
188689ccf448Sdan  }
188789ccf448Sdan} {wal}
188889ccf448Sdando_test pager1-21.1 {
188989ccf448Sdan  testvfs tv -noshm 1
189089ccf448Sdan  sqlite3 db2 test.db -vfs tv
189189ccf448Sdan  catchsql { SELECT * FROM ko } db2
189289ccf448Sdan} {1 {unable to open database file}}
189389ccf448Sdandb2 close
189489ccf448Sdantv delete
189589ccf448Sdando_test pager1-21.2 {
189689ccf448Sdan  testvfs tv -iversion 1
189789ccf448Sdan  sqlite3 db2 test.db -vfs tv
189889ccf448Sdan  catchsql { SELECT * FROM ko } db2
189989ccf448Sdan} {1 {unable to open database file}}
190089ccf448Sdandb2 close
190189ccf448Sdantv delete
190289ccf448Sdan
190389ccf448Sdan#-------------------------------------------------------------------------
190489ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
190589ccf448Sdan#
190689ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
190789ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
190889ccf448Sdan#
190989ccf448Sdando_test pager1-22.1.1 {
191089ccf448Sdan  faultsim_delete_and_reopen
191189ccf448Sdan  execsql {
191289ccf448Sdan    CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
191389ccf448Sdan    INSERT INTO ko DEFAULT VALUES;
191489ccf448Sdan  }
191589ccf448Sdan  execsql { PRAGMA wal_checkpoint }
191689ccf448Sdan} {}
191789ccf448Sdando_test pager1-22.2.1 {
191889ccf448Sdan  testvfs tv -default 1
191989ccf448Sdan  tv filter xSync
192089ccf448Sdan  tv script xSyncCb
192189ccf448Sdan  proc xSyncCb {args} {incr ::synccount}
192289ccf448Sdan  set ::synccount 0
192389ccf448Sdan  sqlite3 db test.db
192489ccf448Sdan  execsql {
192589ccf448Sdan    PRAGMA synchronous = off;
192689ccf448Sdan    PRAGMA journal_mode = WAL;
192789ccf448Sdan    INSERT INTO ko DEFAULT VALUES;
192889ccf448Sdan  }
192989ccf448Sdan  execsql { PRAGMA wal_checkpoint }
193089ccf448Sdan  set synccount
193189ccf448Sdan} {0}
193289ccf448Sdandb close
193389ccf448Sdantv delete
193489ccf448Sdan
193589ccf448Sdan#-------------------------------------------------------------------------
193689ccf448Sdan# Tests for changing journal mode.
193789ccf448Sdan#
193889ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
193989ccf448Sdan#                  the journal file is deleted.
194089ccf448Sdan#
194189ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
194289ccf448Sdan#                  on the database file.
194389ccf448Sdan#
194489ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
194589ccf448Sdan#                  on the database file.
194689ccf448Sdan#
194789ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
194889ccf448Sdan#
194989ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
195089ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
195189ccf448Sdan#
1952*d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
1953*d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
1954*d0b0d4dcSdan#                  locking_mode=exclusive).
1955*d0b0d4dcSdan#
195689ccf448Sdando_test pager1-23.1.1 {
195789ccf448Sdan  faultsim_delete_and_reopen
195889ccf448Sdan  execsql {
195989ccf448Sdan    PRAGMA journal_mode = PERSIST;
196089ccf448Sdan    CREATE TABLE t1(a, b);
196189ccf448Sdan  }
196289ccf448Sdan  file exists test.db-journal
196389ccf448Sdan} {1}
196489ccf448Sdando_test pager1-23.1.2 {
196589ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
196689ccf448Sdan  file exists test.db-journal
196789ccf448Sdan} {0}
196889ccf448Sdan
196989ccf448Sdando_test pager1-23.2.1 {
197089ccf448Sdan  execsql {
197189ccf448Sdan    PRAGMA journal_mode = PERSIST;
197289ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
197389ccf448Sdan  }
197489ccf448Sdan  db eval { SELECT * FROM t1 } {
197589ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
197689ccf448Sdan  }
197789ccf448Sdan  execsql { PRAGMA journal_mode }
197889ccf448Sdan} {delete}
197989ccf448Sdando_test pager1-23.2.2 {
198089ccf448Sdan  file exists test.db-journal
198189ccf448Sdan} {0}
198289ccf448Sdan
198389ccf448Sdando_test pager1-23.3.1 {
198489ccf448Sdan  execsql {
198589ccf448Sdan    PRAGMA journal_mode = PERSIST;
198689ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
198789ccf448Sdan    BEGIN IMMEDIATE;
198889ccf448Sdan  }
198989ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
199089ccf448Sdan  execsql { PRAGMA journal_mode }
199189ccf448Sdan} {delete}
199289ccf448Sdando_test pager1-23.3.2 {
199389ccf448Sdan  file exists test.db-journal
199489ccf448Sdan} {0}
199589ccf448Sdando_test pager1-23.3.3 {
199689ccf448Sdan  execsql COMMIT
199789ccf448Sdan} {}
199889ccf448Sdan
199989ccf448Sdando_test pager1-23.4.1 {
200089ccf448Sdan  execsql {
200189ccf448Sdan    PRAGMA journal_mode = PERSIST;
200289ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
200389ccf448Sdan    BEGIN EXCLUSIVE;
200489ccf448Sdan  }
200589ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
200689ccf448Sdan  execsql { PRAGMA journal_mode }
200789ccf448Sdan} {delete}
200889ccf448Sdando_test pager1-23.4.2 {
200989ccf448Sdan  file exists test.db-journal
201089ccf448Sdan} {0}
201189ccf448Sdando_test pager1-23.4.3 {
201289ccf448Sdan  execsql COMMIT
201389ccf448Sdan} {}
201489ccf448Sdan
201589ccf448Sdando_test pager1-23.5.1 {
201689ccf448Sdan  faultsim_delete_and_reopen
201789ccf448Sdan  sqlite3 db :memory:
201889ccf448Sdan} {}
201989ccf448Sdanforeach {tn mode possible} {
202089ccf448Sdan  2  off      1
202189ccf448Sdan  3  memory   1
202289ccf448Sdan  4  persist  0
202389ccf448Sdan  5  delete   0
202489ccf448Sdan  6  wal      0
202589ccf448Sdan  7  truncate 0
202689ccf448Sdan} {
202789ccf448Sdan  do_test pager1-23.5.$tn.1 {
202889ccf448Sdan    execsql "PRAGMA journal_mode = off"
202989ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
203089ccf448Sdan  } [if $possible {list $mode} {list off}]
203189ccf448Sdan  do_test pager1-23.5.$tn.2 {
203289ccf448Sdan    execsql "PRAGMA journal_mode = memory"
203389ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
203489ccf448Sdan  } [if $possible {list $mode} {list memory}]
203589ccf448Sdan}
2036*d0b0d4dcSdando_test pager1-23.6.1 {
203789ccf448Sdan  execsql {PRAGMA locking_mode = normal}
203889ccf448Sdan} {exclusive}
2039*d0b0d4dcSdando_test pager1-23.6.2 {
204089ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
204189ccf448Sdan} {exclusive}
2042*d0b0d4dcSdando_test pager1-23.6.3 {
204389ccf448Sdan  execsql {PRAGMA locking_mode}
204489ccf448Sdan} {exclusive}
2045*d0b0d4dcSdando_test pager1-23.6.4 {
204689ccf448Sdan  execsql {PRAGMA main.locking_mode}
204789ccf448Sdan} {exclusive}
20486b63ab47Sdan
2049*d0b0d4dcSdan#-------------------------------------------------------------------------
2050*d0b0d4dcSdan#
2051*d0b0d4dcSdando_test pager1-24.1.1 {
2052*d0b0d4dcSdan  faultsim_delete_and_reopen
2053*d0b0d4dcSdan  db func a_string a_string
2054*d0b0d4dcSdan  execsql {
2055*d0b0d4dcSdan    PRAGMA cache_size = 10;
2056*d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2057*d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2058*d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2059*d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2060*d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2061*d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2062*d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2063*d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2064*d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2065*d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2066*d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2067*d0b0d4dcSdan  }
2068*d0b0d4dcSdan} {}
2069*d0b0d4dcSdanproc recursive_select {id {script {}}} {
2070*d0b0d4dcSdan  set cnt 0
2071*d0b0d4dcSdan  db eval {SELECT rowid, x,y,z FROM x2 WHERE rowid = ($id-1)} {
2072*d0b0d4dcSdan    recursive_select $rowid $script
2073*d0b0d4dcSdan    incr cnt
2074*d0b0d4dcSdan  }
2075*d0b0d4dcSdan  if {$cnt==0} { eval $script }
2076*d0b0d4dcSdan}
2077*d0b0d4dcSdando_test pager1-24.1.2 {
2078*d0b0d4dcSdan  execsql {
2079*d0b0d4dcSdan    BEGIN;
2080*d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2081*d0b0d4dcSdan  }
2082*d0b0d4dcSdan  recursive_select 64
2083*d0b0d4dcSdan} {}
2084*d0b0d4dcSdando_test pager1-24.1.3 {
2085*d0b0d4dcSdan  execsql {
2086*d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2087*d0b0d4dcSdan    COMMIT;
2088*d0b0d4dcSdan    PRAGMA integrity_check;
2089*d0b0d4dcSdan    SELECT count(*) FROM x1;
2090*d0b0d4dcSdan  }
2091*d0b0d4dcSdan} {ok 33}
2092*d0b0d4dcSdan
2093*d0b0d4dcSdando_test pager1-24.1.4 {
2094*d0b0d4dcSdan  execsql {
2095*d0b0d4dcSdan    DELETE FROM x1;
2096*d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2097*d0b0d4dcSdan    BEGIN;
2098*d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2099*d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2100*d0b0d4dcSdan  }
2101*d0b0d4dcSdan  recursive_select 64 {db eval COMMIT}
2102*d0b0d4dcSdan  execsql {
2103*d0b0d4dcSdan    PRAGMA integrity_check;
2104*d0b0d4dcSdan    SELECT count(*) FROM x1;
2105*d0b0d4dcSdan  }
2106*d0b0d4dcSdan} {ok 33}
2107*d0b0d4dcSdan
2108*d0b0d4dcSdando_test pager1-24.1.5 {
2109*d0b0d4dcSdan  execsql {
2110*d0b0d4dcSdan    DELETE FROM x1;
2111*d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2112*d0b0d4dcSdan  }
2113*d0b0d4dcSdan  recursive_select 64 { db eval {CREATE TABLE x3(x, y, z)} }
2114*d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2115*d0b0d4dcSdan} {}
2116*d0b0d4dcSdan
2117*d0b0d4dcSdan#-------------------------------------------------------------------------
2118*d0b0d4dcSdan#
2119*d0b0d4dcSdando_test pager1-25-1 {
2120*d0b0d4dcSdan  faultsim_delete_and_reopen
2121*d0b0d4dcSdan  execsql {
2122*d0b0d4dcSdan    BEGIN;
2123*d0b0d4dcSdan      SAVEPOINT abc;
2124*d0b0d4dcSdan        CREATE TABLE t1(a, b);
2125*d0b0d4dcSdan      ROLLBACK TO abc;
2126*d0b0d4dcSdan    COMMIT;
2127*d0b0d4dcSdan  }
2128*d0b0d4dcSdan  db close
2129*d0b0d4dcSdan} {}
2130*d0b0d4dcSdanbreakpoint
2131*d0b0d4dcSdando_test pager1-25-2 {
2132*d0b0d4dcSdan  faultsim_delete_and_reopen
2133*d0b0d4dcSdan  execsql {
2134*d0b0d4dcSdan    SAVEPOINT abc;
2135*d0b0d4dcSdan      CREATE TABLE t1(a, b);
2136*d0b0d4dcSdan    ROLLBACK TO abc;
2137*d0b0d4dcSdan    COMMIT;
2138*d0b0d4dcSdan  }
2139*d0b0d4dcSdan  db close
2140*d0b0d4dcSdan} {}
21416b63ab47Sdan
2142d353331aSdanfinish_test
2143