xref: /sqlite-3.40.0/test/pager1.test (revision 6ab91a7a)
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
18d7a558a9Sdanset testprefix pager1
1968928b6cSdan
2069aedc8dSdanif {[atomic_batch_write test.db]} {
2169aedc8dSdan  finish_test
2269aedc8dSdan  return
2369aedc8dSdan}
2469aedc8dSdan
2568928b6cSdan# Do not use a codec for tests in this file, as the database file is
2668928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command).
2768928b6cSdan#
2868928b6cSdando_not_use_codec
29e91a54e1Sdan
30b0ac3e3aSdan#
31b0ac3e3aSdan# pager1-1.*: Test inter-process locking (clients in multiple processes).
32b0ac3e3aSdan#
33b0ac3e3aSdan# pager1-2.*: Test intra-process locking (multiple clients in this process).
34b0ac3e3aSdan#
35b0ac3e3aSdan# pager1-3.*: Savepoint related tests.
36b0ac3e3aSdan#
371f4cb65aSdan# pager1-4.*: Hot-journal related tests.
381f4cb65aSdan#
39de4996e2Sdan# pager1-5.*: Cases related to multi-file commits.
40de4996e2Sdan#
41146ed78bSdan# pager1-6.*: Cases related to "PRAGMA max_page_count"
42146ed78bSdan#
43153eda0aSdan# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
44153eda0aSdan#
450e986f51Sdan# pager1-8.*: Cases using temporary and in-memory databases.
460e986f51Sdan#
47dca321aeSdan# pager1-9.*: Tests related to the backup API.
48dca321aeSdan#
49ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to
50ec6ffc1aSdan#              64KB.
51ec6ffc1aSdan#
52d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size"
53d353331aSdan#
54d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST"
55d353331aSdan#
56d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF"
57ec6ffc1aSdan#
58c8ce3972Sdan# pager1-15.*: Varying sqlite3_vfs.szOsFile
59c8ce3972Sdan#
60c8ce3972Sdan# pager1-16.*: Varying sqlite3_vfs.mxPathname
61c8ce3972Sdan#
62c8ce3972Sdan# pager1-17.*: Tests related to "PRAGMA omit_readlock"
6333f111dcSdrh#              (The omit_readlock pragma has been removed and so have
6433f111dcSdrh#              these tests.)
65c8ce3972Sdan#
66c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree
67c8ce3972Sdan#              requests an invalid page number (due to db corruption).
68c8ce3972Sdan#
69b0ac3e3aSdan
70c396d4afSdanproc recursive_select {id table {script {}}} {
71c396d4afSdan  set cnt 0
72c396d4afSdan  db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
73c396d4afSdan    recursive_select $rowid $table $script
74c396d4afSdan    incr cnt
75c396d4afSdan  }
76c396d4afSdan  if {$cnt==0} { eval $script }
77c396d4afSdan}
78c396d4afSdan
7953f04f3bSdanset a_string_counter 1
8053f04f3bSdanproc a_string {n} {
8153f04f3bSdan  global a_string_counter
8253f04f3bSdan  incr a_string_counter
8353f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
8453f04f3bSdan}
8553f04f3bSdandb func a_string a_string
8653f04f3bSdan
87a4a9095eSdando_multiclient_test tn {
88e91a54e1Sdan
89e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
90e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
91e91a54e1Sdan  #
92e91a54e1Sdan  do_test pager1-$tn.1 {
93e91a54e1Sdan    sql1 {
94e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
95e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
96d353331aSdan      INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
97e91a54e1Sdan    }
98e91a54e1Sdan  } {}
99e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
100e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
101e91a54e1Sdan
102e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
103e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
104e91a54e1Sdan  # read the database content as it was before the transaction was
105e91a54e1Sdan  # opened. [db] should see the inserted row.
106e91a54e1Sdan  #
107e91a54e1Sdan  do_test pager1-$tn.4 {
108e91a54e1Sdan    sql1 {
109e91a54e1Sdan      BEGIN;
110e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
111e91a54e1Sdan    }
112e91a54e1Sdan  } {}
113e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
114e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
115e91a54e1Sdan
116e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
117e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
118e91a54e1Sdan  #
119e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
120e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
121e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
122e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
123e91a54e1Sdan  #
124e91a54e1Sdan  do_test pager1-$tn.8 {
125e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
126e91a54e1Sdan  } {1 {database is locked}}
127e91a54e1Sdan  do_test pager1-$tn.9 {
128e91a54e1Sdan    csql2 {
129e91a54e1Sdan      BEGIN;
130e91a54e1Sdan      UPDATE t1 SET a = a + 10;
131e91a54e1Sdan    }
132e91a54e1Sdan  } {1 {database is locked}}
133e91a54e1Sdan
134e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
135e91a54e1Sdan  # now see the new database content.
136e91a54e1Sdan  #
137e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
138e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
139e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
140e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
141e91a54e1Sdan
142e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
143e91a54e1Sdan  # after the attempt to write the database failed.
144e91a54e1Sdan  #
145e91a54e1Sdan  do_test pager1-$tn.14 {
146e91a54e1Sdan    csql2 { BEGIN }
147e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
148e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
149e91a54e1Sdan
150e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
151e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
152e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
153e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
154e91a54e1Sdan  #
155e91a54e1Sdan  do_test pager1-$tn.15 {
156e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
157e91a54e1Sdan  } {1 one 2 two 3 three}
158e91a54e1Sdan  do_test pager1-$tn.16 {
159e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
160e91a54e1Sdan  } {1 {database is locked}}
161e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
162e91a54e1Sdan
163e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
164e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
165e91a54e1Sdan  # the SHARED lock [db2] is holding.
166e91a54e1Sdan  #
167e91a54e1Sdan  do_test pager1-$tn.18 {
168e91a54e1Sdan    sql1 {
169e91a54e1Sdan      BEGIN;
170e91a54e1Sdan      UPDATE t1 SET a = a + 10;
171e91a54e1Sdan    }
172e91a54e1Sdan  } {}
173e91a54e1Sdan  do_test pager1-$tn-19 {
174e91a54e1Sdan    sql1 { PRAGMA lock_status }
175e91a54e1Sdan  } {main reserved temp closed}
176e91a54e1Sdan  do_test pager1-$tn-20 {
177e91a54e1Sdan    sql2 { PRAGMA lock_status }
178e91a54e1Sdan  } {main shared temp closed}
179e91a54e1Sdan
180e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
181e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
182e91a54e1Sdan  #
183e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
184e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
185e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
186e91a54e1Sdan
187e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
188e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
189e91a54e1Sdan  # upgrades to a PENDING lock.
190e91a54e1Sdan  #
191e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
192e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
193e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
194e91a54e1Sdan  # the database.
195e91a54e1Sdan  #
196e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
197e91a54e1Sdan  do_test pager1-$tn-25 {
198e91a54e1Sdan    sql1 { PRAGMA lock_status }
199e91a54e1Sdan  } {main pending temp closed}
200e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
201e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
202e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
203e91a54e1Sdan
204e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
205e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
206e91a54e1Sdan  # is still holding a PENDING).
207e91a54e1Sdan  #
208e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
209e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
210e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
211e91a54e1Sdan
212e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
213e91a54e1Sdan  # committed, all three connections can read the new content.
214e91a54e1Sdan  #
215e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
216e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
217e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
218e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
219e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
220d353331aSdan
221d353331aSdan  # Install a busy-handler for connection [db].
222d353331aSdan  #
223d353331aSdan  set ::nbusy [list]
224d353331aSdan  proc busy {n} {
225d353331aSdan    lappend ::nbusy $n
226d353331aSdan    if {$n>5} { sql2 COMMIT }
227d353331aSdan    return 0
228d353331aSdan  }
229d353331aSdan  db busy busy
230d353331aSdan
231d353331aSdan  do_test pager1-$tn.29 {
232d353331aSdan    sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
233d353331aSdan  } {}
234d353331aSdan  do_test pager1-$tn.30 {
235d353331aSdan    sql2 { BEGIN ; SELECT * FROM t1 }
236d353331aSdan  } {21 one 22 two 23 three}
237d353331aSdan  do_test pager1-$tn.31 { sql1 COMMIT } {}
238d353331aSdan  do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
239e91a54e1Sdan}
240e91a54e1Sdan
24153f04f3bSdan#-------------------------------------------------------------------------
24253f04f3bSdan# Savepoint related test cases.
24353f04f3bSdan#
244dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
245dca321aeSdan#                 to grow.
246dca321aeSdan#
247273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
248273f3f0dSdan#                 of a savepoint rollback.
249273f3f0dSdan#
2500e986f51Sdando_test pager1-3.1.1 {
251b0ac3e3aSdan  faultsim_delete_and_reopen
252b0ac3e3aSdan  execsql {
253b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
254b0ac3e3aSdan    CREATE TABLE counter(
255b0ac3e3aSdan      i CHECK (i<5),
256b0ac3e3aSdan      u CHECK (u<10)
257b0ac3e3aSdan    );
258b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
259b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
260b0ac3e3aSdan      UPDATE counter SET i = i+1;
261b0ac3e3aSdan    END;
262b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
263b0ac3e3aSdan      UPDATE counter SET u = u+1;
264b0ac3e3aSdan    END;
265b0ac3e3aSdan  }
266b0ac3e3aSdan  execsql { SELECT * FROM counter }
267b0ac3e3aSdan} {0 0}
268b0ac3e3aSdan
2690e986f51Sdando_execsql_test pager1-3.1.2 {
270d353331aSdan  PRAGMA cache_size = 10;
271b0ac3e3aSdan  BEGIN;
272b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
273b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
274b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
275b0ac3e3aSdan    SELECT * FROM counter;
276b0ac3e3aSdan} {3 0}
2770e986f51Sdando_catchsql_test pager1-3.1.3 {
278b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
279f9c8ce3cSdrh} {1 {CHECK constraint failed: counter}}
280b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
281b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
282b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
283b0ac3e3aSdan
284273f3f0dSdanforeach {tn sql tcl} {
285d353331aSdan  7  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
286273f3f0dSdan    testvfs tv -default 1
287273f3f0dSdan    tv devchar safe_append
288273f3f0dSdan  }
289d353331aSdan  8  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
290d353331aSdan    testvfs tv -default 1
291d353331aSdan    tv devchar sequential
292d353331aSdan  }
293d353331aSdan  9  { PRAGMA synchronous = FULL } { }
294d353331aSdan  10 { PRAGMA synchronous = NORMAL } { }
295d353331aSdan  11 { PRAGMA synchronous = OFF } { }
296d353331aSdan  12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
297d353331aSdan  13 { PRAGMA synchronous = FULL } {
298d353331aSdan    testvfs tv -default 1
299d353331aSdan    tv devchar sequential
300d353331aSdan  }
3016b63ab47Sdan  14 { PRAGMA locking_mode = EXCLUSIVE } {
3026b63ab47Sdan  }
303273f3f0dSdan} {
304273f3f0dSdan  do_test pager1-3.$tn.1 {
305273f3f0dSdan    eval $tcl
306dca321aeSdan    faultsim_delete_and_reopen
307dca321aeSdan    db func a_string a_string
308273f3f0dSdan    execsql $sql
309dca321aeSdan    execsql {
310dca321aeSdan      PRAGMA auto_vacuum = 2;
311dca321aeSdan      PRAGMA cache_size = 10;
312dca321aeSdan      CREATE TABLE z(x INTEGER PRIMARY KEY, y);
313dca321aeSdan      BEGIN;
314dca321aeSdan        INSERT INTO z VALUES(NULL, a_string(800));
315dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
316dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
317dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
318dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
319dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
320dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
321dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
322dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
323dca321aeSdan      COMMIT;
324dca321aeSdan    }
325dca321aeSdan    execsql { PRAGMA auto_vacuum }
326dca321aeSdan  } {2}
327273f3f0dSdan  do_execsql_test pager1-3.$tn.2 {
328dca321aeSdan    BEGIN;
329dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
330dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
331dca321aeSdan      SAVEPOINT one;
332273f3f0dSdan        UPDATE z SET y = NULL WHERE x>256;
333dca321aeSdan        PRAGMA incremental_vacuum;
334dca321aeSdan        SELECT count(*) FROM z WHERE x < 100;
335dca321aeSdan      ROLLBACK TO one;
336dca321aeSdan    COMMIT;
337dca321aeSdan  } {99}
338dca321aeSdan
339273f3f0dSdan  do_execsql_test pager1-3.$tn.3 {
340273f3f0dSdan    BEGIN;
341273f3f0dSdan      SAVEPOINT one;
342273f3f0dSdan        UPDATE z SET y = y||x;
343273f3f0dSdan      ROLLBACK TO one;
344273f3f0dSdan    COMMIT;
345273f3f0dSdan    SELECT count(*) FROM z;
346273f3f0dSdan  } {258}
347273f3f0dSdan
348273f3f0dSdan  do_execsql_test pager1-3.$tn.4 {
349273f3f0dSdan    SAVEPOINT one;
350273f3f0dSdan      UPDATE z SET y = y||x;
351273f3f0dSdan    ROLLBACK TO one;
352273f3f0dSdan  } {}
353273f3f0dSdan  do_execsql_test pager1-3.$tn.5 {
354273f3f0dSdan    SELECT count(*) FROM z;
355273f3f0dSdan    RELEASE one;
356273f3f0dSdan    PRAGMA integrity_check;
357273f3f0dSdan  } {258 ok}
358273f3f0dSdan
35978f1e538Sdan  do_execsql_test pager1-3.$tn.6 {
36078f1e538Sdan    SAVEPOINT one;
36178f1e538Sdan    RELEASE one;
36278f1e538Sdan  } {}
36378f1e538Sdan
364273f3f0dSdan  db close
365273f3f0dSdan  catch { tv delete }
366273f3f0dSdan}
367273f3f0dSdan
36853f04f3bSdan#-------------------------------------------------------------------------
36953f04f3bSdan# Hot journal rollback related test cases.
37053f04f3bSdan#
37153f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
37253f04f3bSdan#               journal files.
37353f04f3bSdan#
37453f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
37553f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
37653f04f3bSdan#               compute) the associated journal is rolled back (and no
37753f04f3bSdan#               xAccess() call to check for the presence of any master
37853f04f3bSdan#               journal file is made).
37953f04f3bSdan#
380de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
381de4996e2Sdan#               page-size or sector-size in the journal header appear to
382de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
383de4996e2Sdan#
384e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
385e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
386e08341c6Sdan#               modes.
387e08341c6Sdan#
388e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
389e08341c6Sdan#               journal-record for which the checksum fails.
390e08341c6Sdan#
391ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
392ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
393ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
394ec6ffc1aSdan#
395c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can
396c8ce3972Sdan#               open it for reading only, the database cannot be accessed and
397c8ce3972Sdan#               SQLITE_CANTOPEN is returned.
398c8ce3972Sdan#
39953f04f3bSdando_test pager1.4.1.1 {
40053f04f3bSdan  faultsim_delete_and_reopen
40153f04f3bSdan  execsql {
40253f04f3bSdan    CREATE TABLE x(y, z);
40353f04f3bSdan    INSERT INTO x VALUES(1, 2);
40453f04f3bSdan  }
40553f04f3bSdan  set fd [open test.db-journal w]
40653f04f3bSdan  puts -nonewline $fd "helloworld"
40753f04f3bSdan  close $fd
40853f04f3bSdan  file exists test.db-journal
40953f04f3bSdan} {1}
41053f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
41153f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
41253f04f3bSdan
41353f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
41453f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
41553f04f3bSdan#
41653f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
41753f04f3bSdan# up the file system to contain two databases, two hot-journal files and
41853f04f3bSdan# a master-journal.
41953f04f3bSdan#
42053f04f3bSdando_test pager1.4.2.1 {
42153f04f3bSdan  testvfs tstvfs -default 1
42253f04f3bSdan  tstvfs filter xDelete
42353f04f3bSdan  tstvfs script xDeleteCallback
42453f04f3bSdan  proc xDeleteCallback {method file args} {
42553f04f3bSdan    set file [file tail $file]
42653f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
42753f04f3bSdan  }
42853f04f3bSdan  faultsim_delete_and_reopen
42953f04f3bSdan  db func a_string a_string
43053f04f3bSdan  execsql {
43153f04f3bSdan    ATTACH 'test.db2' AS aux;
43253f04f3bSdan    PRAGMA journal_mode = DELETE;
43353f04f3bSdan    PRAGMA main.cache_size = 10;
43453f04f3bSdan    PRAGMA aux.cache_size = 10;
43553f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
43653f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
43753f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
43853f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43953f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
44053f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
44153f04f3bSdan    BEGIN;
44253f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
44353f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
44453f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
44553f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
44653f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
44753f04f3bSdan    COMMIT;
44853f04f3bSdan  }
44953f04f3bSdan  db close
45053f04f3bSdan  tstvfs delete
45153f04f3bSdan} {}
452b2f20bfcSshaneh
453b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
45453f04f3bSdando_test pager1.4.2.2 {
45553f04f3bSdan  faultsim_restore_and_reopen
45653f04f3bSdan  execsql {
45753f04f3bSdan    SELECT count(*) FROM t1;
45853f04f3bSdan    PRAGMA integrity_check;
45953f04f3bSdan  }
46053f04f3bSdan} {4 ok}
46153f04f3bSdando_test pager1.4.2.3 {
46253f04f3bSdan  faultsim_restore_and_reopen
463fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
46453f04f3bSdan  execsql {
46553f04f3bSdan    SELECT count(*) FROM t1;
46653f04f3bSdan    PRAGMA integrity_check;
46753f04f3bSdan  }
46853f04f3bSdan} {64 ok}
46953f04f3bSdando_test pager1.4.2.4 {
47053f04f3bSdan  faultsim_restore_and_reopen
4710971140bSdrh  hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
47253f04f3bSdan  execsql {
47353f04f3bSdan    SELECT count(*) FROM t1;
47453f04f3bSdan    PRAGMA integrity_check;
47553f04f3bSdan  }
47653f04f3bSdan} {4 ok}
47753f04f3bSdando_test pager1.4.2.5 {
47853f04f3bSdan  faultsim_restore_and_reopen
4790971140bSdrh  hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
480fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
48153f04f3bSdan  execsql {
48253f04f3bSdan    SELECT count(*) FROM t1;
48353f04f3bSdan    PRAGMA integrity_check;
48453f04f3bSdan  }
48553f04f3bSdan} {4 ok}
486b2f20bfcSshaneh}
48753f04f3bSdan
488de4996e2Sdando_test pager1.4.3.1 {
489de4996e2Sdan  testvfs tstvfs -default 1
490de4996e2Sdan  tstvfs filter xSync
491de4996e2Sdan  tstvfs script xSyncCallback
492de4996e2Sdan  proc xSyncCallback {method file args} {
493de4996e2Sdan    set file [file tail $file]
494de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
495de4996e2Sdan  }
496de4996e2Sdan  faultsim_delete_and_reopen
497de4996e2Sdan  execsql {
498de4996e2Sdan    PRAGMA journal_mode = DELETE;
499de4996e2Sdan    CREATE TABLE t1(a, b);
500de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
501de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
502de4996e2Sdan  }
503de4996e2Sdan  db close
504de4996e2Sdan  tstvfs delete
505de4996e2Sdan} {}
506de4996e2Sdan
507de4996e2Sdanforeach {tn ofst value result} {
508de4996e2Sdan          2   20    31       {1 2 3 4}
509de4996e2Sdan          3   20    32       {1 2 3 4}
510de4996e2Sdan          4   20    33       {1 2 3 4}
511de4996e2Sdan          5   20    65536    {1 2 3 4}
512de4996e2Sdan          6   20    131072   {1 2 3 4}
513de4996e2Sdan
514de4996e2Sdan          7   24    511      {1 2 3 4}
515de4996e2Sdan          8   24    513      {1 2 3 4}
516b2eced5dSdrh          9   24    131072   {1 2 3 4}
517de4996e2Sdan
518de4996e2Sdan         10   32    65536    {1 2}
519de4996e2Sdan} {
520de4996e2Sdan  do_test pager1.4.3.$tn {
521de4996e2Sdan    faultsim_restore_and_reopen
522de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
523de4996e2Sdan    execsql { SELECT * FROM t1 }
524de4996e2Sdan  } $result
525de4996e2Sdan}
526de4996e2Sdandb close
527de4996e2Sdan
528e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
529e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
530e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
531e08341c6Sdan# master journal file from the file-system.
532e08341c6Sdan#
5336aa18c95Smistachkinset pwd [get_pwd]
534e08341c6Sdantestvfs tv -default 1
535e08341c6Sdantv script copy_on_mj_delete
536e08341c6Sdanset ::mj_filename_length 0
5378e6cf0a7Sdrhset ::mj_delete_cnt 0
538e08341c6Sdanproc copy_on_mj_delete {method filename args} {
539e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
540c5484654Smistachkin    #
541c5484654Smistachkin    # NOTE: Is the file name relative?  If so, add the length of the current
542c5484654Smistachkin    #       directory.
543c5484654Smistachkin    #
544c5484654Smistachkin    if {[is_relative_file $filename]} {
545c5484654Smistachkin      set ::mj_filename_length \
546c5484654Smistachkin        [expr {[string length $filename] + [string length $::pwd]}]
547c5484654Smistachkin    } else {
548e08341c6Sdan      set ::mj_filename_length [string length $filename]
549c5484654Smistachkin    }
550e08341c6Sdan    faultsim_save
5518e6cf0a7Sdrh    incr ::mj_delete_cnt
552e08341c6Sdan  }
553e08341c6Sdan  return SQLITE_OK
554e08341c6Sdan}
555e08341c6Sdan
556e08341c6Sdanforeach {tn1 tcl} {
557e08341c6Sdan  1 { set prefix "test.db" }
558e08341c6Sdan  2 {
559e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
560e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
561e08341c6Sdan    # contains a master-journal pointer so large that it could contain
562e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
563e08341c6Sdan    # make sure SQLite doesn't get confused by this.
564e08341c6Sdan    #
565e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
56633d85c9cSshaneh    if {$tcl_platform(platform)=="windows"} {
56733d85c9cSshaneh      # TBD need to figure out how to do this correctly for Windows!!!
56833d85c9cSshaneh      set nPadding [expr 255 - $::mj_filename_length]
56933d85c9cSshaneh    }
570e08341c6Sdan
571e08341c6Sdan    # We cannot just create a really long database file name to open, as
572e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
573e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
574e08341c6Sdan    # hierarchy to work in.
575e08341c6Sdan    #
576e08341c6Sdan    set dirname "d123456789012345678901234567890/"
577e08341c6Sdan    set nDir [expr $nPadding / 32]
578e08341c6Sdan    if { $nDir } {
579e08341c6Sdan      set p [string repeat $dirname $nDir]
580e08341c6Sdan      file mkdir $p
581e08341c6Sdan      cd $p
582e08341c6Sdan    }
583e08341c6Sdan
584e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
585e08341c6Sdan    set prefix "test.db${padding}"
586e08341c6Sdan  }
587e08341c6Sdan} {
588e08341c6Sdan  eval $tcl
5898e6cf0a7Sdrh  foreach {tn2 sql usesMJ} {
590e08341c6Sdan    o {
591e08341c6Sdan      PRAGMA main.synchronous=OFF;
592e08341c6Sdan      PRAGMA aux.synchronous=OFF;
5933f94b609Sdan      PRAGMA journal_mode = DELETE;
5948e6cf0a7Sdrh    } 0
595e08341c6Sdan    o512 {
596e08341c6Sdan      PRAGMA main.synchronous=OFF;
597e08341c6Sdan      PRAGMA aux.synchronous=OFF;
598e08341c6Sdan      PRAGMA main.page_size = 512;
599e08341c6Sdan      PRAGMA aux.page_size = 512;
6003f94b609Sdan      PRAGMA journal_mode = DELETE;
6018e6cf0a7Sdrh    } 0
602e08341c6Sdan    n {
603e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
604e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
6053f94b609Sdan      PRAGMA journal_mode = DELETE;
6068e6cf0a7Sdrh    } 1
607e08341c6Sdan    f {
608e08341c6Sdan      PRAGMA main.synchronous=FULL;
609e08341c6Sdan      PRAGMA aux.synchronous=FULL;
6103f94b609Sdan      PRAGMA journal_mode = DELETE;
6118e6cf0a7Sdrh    } 1
6128e6cf0a7Sdrh    w1 {
6138e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
6148e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
6158e6cf0a7Sdrh      PRAGMA journal_mode = WAL;
6168e6cf0a7Sdrh    } 0
6178e6cf0a7Sdrh    w2 {
6188e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
6198e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
6208e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
6218e6cf0a7Sdrh      PRAGMA aux.journal_mode=WAL;
6228e6cf0a7Sdrh    } 0
6238e6cf0a7Sdrh    o1a {
6248e6cf0a7Sdrh      PRAGMA main.synchronous=FULL;
6258e6cf0a7Sdrh      PRAGMA aux.synchronous=OFF;
6268e6cf0a7Sdrh      PRAGMA journal_mode=DELETE;
6278e6cf0a7Sdrh    } 0
6288e6cf0a7Sdrh    o1b {
6298e6cf0a7Sdrh      PRAGMA main.synchronous=OFF;
6308e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
6318e6cf0a7Sdrh      PRAGMA journal_mode=DELETE;
6328e6cf0a7Sdrh    } 0
6338e6cf0a7Sdrh    m1 {
6348e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
6358e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
6368e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
6378e6cf0a7Sdrh      PRAGMA aux.journal_mode = MEMORY;
6388e6cf0a7Sdrh    } 0
6398e6cf0a7Sdrh    t1 {
6408e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
6418e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
6428e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
6438e6cf0a7Sdrh      PRAGMA aux.journal_mode = TRUNCATE;
6448e6cf0a7Sdrh    } 1
6458e6cf0a7Sdrh    p1 {
6468e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
6478e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
6488e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
6498e6cf0a7Sdrh      PRAGMA aux.journal_mode = PERSIST;
6508e6cf0a7Sdrh    } 1
651e08341c6Sdan  } {
652e08341c6Sdan
653e08341c6Sdan    set tn "${tn1}.${tn2}"
654e08341c6Sdan
655e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
656e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
657e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
658e08341c6Sdan    # file is deleted to commit the transaction.
659e08341c6Sdan    #
660e08341c6Sdan    tv filter xDelete
661e08341c6Sdan    do_test pager1-4.4.$tn.1 {
6628e6cf0a7Sdrh      set ::mj_delete_cnt 0
663e08341c6Sdan      faultsim_delete_and_reopen $prefix
664e08341c6Sdan      execsql "
665e08341c6Sdan        ATTACH '${prefix}2' AS aux;
666e08341c6Sdan        $sql
667e08341c6Sdan        CREATE TABLE a(x);
668e08341c6Sdan        CREATE TABLE aux.b(x);
669e08341c6Sdan        INSERT INTO a VALUES('double-you');
670e08341c6Sdan        INSERT INTO a VALUES('why');
671e08341c6Sdan        INSERT INTO a VALUES('zed');
672e08341c6Sdan        INSERT INTO b VALUES('won');
673e08341c6Sdan        INSERT INTO b VALUES('too');
674e08341c6Sdan        INSERT INTO b VALUES('free');
675e08341c6Sdan      "
676e08341c6Sdan      execsql {
677e08341c6Sdan        BEGIN;
678e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
679e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
680e08341c6Sdan        COMMIT;
681e08341c6Sdan      }
682e08341c6Sdan    } {}
683e08341c6Sdan    tv filter {}
684e08341c6Sdan
6858e6cf0a7Sdrh    # Verify that a master journal was deleted only for those cases where
6868e6cf0a7Sdrh    # master journals really ought to be used
6878e6cf0a7Sdrh    #
6888e6cf0a7Sdrh    do_test pager1-4.4.$tn.1b {
6898e6cf0a7Sdrh      set ::mj_delete_cnt
6908e6cf0a7Sdrh    } $usesMJ
6918e6cf0a7Sdrh
692e08341c6Sdan    # Check that the transaction was committed successfully.
693e08341c6Sdan    #
694e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
695e08341c6Sdan      SELECT * FROM a
696e08341c6Sdan    } {double-you why zed won too free}
697e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
698e08341c6Sdan      SELECT * FROM b
699e08341c6Sdan    } {won too free double-you why zed}
700e08341c6Sdan
7018e6cf0a7Sdrh    if {$usesMJ} {
702e08341c6Sdan      # Restore the file-system and reopen the databases. Check that it now
703e08341c6Sdan      # appears that the transaction was not committed (because the file-system
704e08341c6Sdan      # was restored to the state where it had not been).
705e08341c6Sdan      #
706e08341c6Sdan      do_test pager1-4.4.$tn.4 {
707e08341c6Sdan        faultsim_restore_and_reopen $prefix
708e08341c6Sdan        execsql "ATTACH '${prefix}2' AS aux"
709e08341c6Sdan      } {}
710e08341c6Sdan      do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
711e08341c6Sdan      do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
7128e6cf0a7Sdrh    }
713e08341c6Sdan
714e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
715e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
716e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
717e08341c6Sdan    #
718e08341c6Sdan    do_test pager1-4.4.$tn.7 {
7198e6cf0a7Sdrh      if {$::mj_delete_cnt>0} {
720e08341c6Sdan        faultsim_restore_and_reopen $prefix
721fda06befSmistachkin        foreach f [glob ${prefix}-mj*] { forcedelete $f }
7228e6cf0a7Sdrh      } else {
7238e6cf0a7Sdrh        db close
7248e6cf0a7Sdrh        sqlite3 db $prefix
7258e6cf0a7Sdrh      }
726e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
7278e6cf0a7Sdrh      glob -nocomplain ${prefix}-mj*
728e08341c6Sdan    } {}
729e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
730e08341c6Sdan      SELECT * FROM a
731e08341c6Sdan    } {double-you why zed won too free}
732e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
733e08341c6Sdan      SELECT * FROM b
734e08341c6Sdan    } {won too free double-you why zed}
735e08341c6Sdan  }
736e08341c6Sdan
737e08341c6Sdan  cd $pwd
738e08341c6Sdan}
739e08341c6Sdandb close
740e08341c6Sdantv delete
741fda06befSmistachkinforcedelete $dirname
7420e986f51Sdan
7430e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
7440e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
7450e986f51Sdan# two database pages (and page 1 - the change counter).
7460e986f51Sdan#
7470e986f51Sdantestvfs tv -default 1
7480e986f51Sdantv sectorsize 512
7490e986f51Sdantv script copy_on_journal_delete
7500e986f51Sdantv filter xDelete
7510e986f51Sdanproc copy_on_journal_delete {method filename args} {
7520e986f51Sdan  if {[string match *journal $filename]} faultsim_save
7530e986f51Sdan  return SQLITE_OK
7540e986f51Sdan}
7550e986f51Sdanfaultsim_delete_and_reopen
7560e986f51Sdando_execsql_test pager1.4.5.1 {
7573f94b609Sdan  PRAGMA journal_mode = DELETE;
7580e986f51Sdan  PRAGMA page_size = 1024;
7590e986f51Sdan  CREATE TABLE t1(a, b);
7600e986f51Sdan  CREATE TABLE t2(a, b);
7610e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
7620e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
7630e986f51Sdan  BEGIN;
7640e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
7650e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
7660e986f51Sdan  COMMIT;
7673f94b609Sdan} {delete}
7680e986f51Sdantv filter {}
7690e986f51Sdan
7700e986f51Sdan# Check the transaction was committed:
7710e986f51Sdan#
7720e986f51Sdando_execsql_test pager1.4.5.2 {
7730e986f51Sdan  SELECT * FROM t1;
7740e986f51Sdan  SELECT * FROM t2;
7750e986f51Sdan} {I II 1 2 III IV 3 4}
7760e986f51Sdan
777ec6ffc1aSdan# Now try four tests:
7780e986f51Sdan#
7790e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
7800e986f51Sdan#                is rolled back.
7810e986f51Sdan#
7820e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
7830e986f51Sdan#                journal. Check the transaction is not rolled back.
7840e986f51Sdan#
7850e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
7860e986f51Sdan#                journal. Check that the first record in the transaction is
7870e986f51Sdan#                played back, but not the second.
7880e986f51Sdan#
78910f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
79010f5a50eSdan#                readonly connection. This should fail, as a read-only
79110f5a50eSdan#                connection cannot roll back the database file.
79210f5a50eSdan#
7930e986f51Sdanfaultsim_restore_and_reopen
7940e986f51Sdando_execsql_test pager1.4.5.3 {
7950e986f51Sdan  SELECT * FROM t1;
7960e986f51Sdan  SELECT * FROM t2;
7970e986f51Sdan} {I II III IV}
7980e986f51Sdanfaultsim_restore_and_reopen
7990e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
8000e986f51Sdando_execsql_test pager1.4.5.4 {
8010e986f51Sdan  SELECT * FROM t1;
8020e986f51Sdan  SELECT * FROM t2;
8030e986f51Sdan} {I II 1 2 III IV 3 4}
8040e986f51Sdanfaultsim_restore_and_reopen
8050e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
8060e986f51Sdando_execsql_test pager1.4.5.5 {
8070e986f51Sdan  SELECT * FROM t1;
8080e986f51Sdan  SELECT * FROM t2;
8090e986f51Sdan} {I II III IV 3 4}
8100e986f51Sdan
81110f5a50eSdanfaultsim_restore_and_reopen
81210f5a50eSdandb close
81310f5a50eSdansqlite3 db test.db -readonly 1
81410f5a50eSdando_catchsql_test pager1.4.5.6 {
81510f5a50eSdan  SELECT * FROM t1;
81610f5a50eSdan  SELECT * FROM t2;
817b83c21e6Sdan} {1 {attempt to write a readonly database}}
818ec6ffc1aSdandb close
819ec6ffc1aSdan
820ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
821ec6ffc1aSdan# of the master journal file in $::mj_filename.
822ec6ffc1aSdan#
823ec6ffc1aSdantv script copy_on_mj_delete
824ec6ffc1aSdantv filter xDelete
825ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
826ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
827ec6ffc1aSdan    set ::mj_filename $filename
828ec6ffc1aSdan    faultsim_save
829ec6ffc1aSdan  }
830ec6ffc1aSdan  return SQLITE_OK
831ec6ffc1aSdan}
832ec6ffc1aSdando_test pager1.4.6.1 {
833ec6ffc1aSdan  faultsim_delete_and_reopen
834ec6ffc1aSdan  execsql {
8353f94b609Sdan    PRAGMA journal_mode = DELETE;
836ec6ffc1aSdan    ATTACH 'test.db2' AS two;
837ec6ffc1aSdan    CREATE TABLE t1(a, b);
838ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
839ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
840ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
841ec6ffc1aSdan    BEGIN;
842ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
843ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
844ec6ffc1aSdan    COMMIT;
845ec6ffc1aSdan  }
846ec6ffc1aSdan  tv filter {}
847ec6ffc1aSdan  db close
848ec6ffc1aSdan} {}
849ec6ffc1aSdan
850ec6ffc1aSdanfaultsim_restore_and_reopen
851ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
852ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
853ec6ffc1aSdando_execsql_test pager1.4.6.4 {
854ec6ffc1aSdan  ATTACH 'test.db2' AS two;
855ec6ffc1aSdan  SELECT * FROM t2;
856ec6ffc1aSdan} {1 t2.1}
857ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
858ec6ffc1aSdan
859ec6ffc1aSdanfaultsim_restore_and_reopen
860ec6ffc1aSdandb close
861ec6ffc1aSdando_test pager1.4.6.8 {
862ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
863ec6ffc1aSdan  tv filter xDelete
864ec6ffc1aSdan  sqlite3 db test.db2
865ec6ffc1aSdan  execsql {
8663f94b609Sdan    PRAGMA journal_mode = DELETE;
867ec6ffc1aSdan    ATTACH 'test.db3' AS three;
868ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
869ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
870ec6ffc1aSdan    BEGIN;
871ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
872ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
873ec6ffc1aSdan    COMMIT;
874ec6ffc1aSdan  }
875ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
876ec6ffc1aSdan} {1}
877ec6ffc1aSdanfaultsim_restore_and_reopen
878ec6ffc1aSdantv filter {}
879ec6ffc1aSdan
880ec6ffc1aSdan# The file-system now contains:
881ec6ffc1aSdan#
882ec6ffc1aSdan#   * three databases
883ec6ffc1aSdan#   * three hot-journal files
884ec6ffc1aSdan#   * two master-journal files.
885ec6ffc1aSdan#
886ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
887ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
888ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
889ec6ffc1aSdan# test.db should delete $::mj_filename1.
890ec6ffc1aSdan#
891ec6ffc1aSdando_test pager1.4.6.9 {
892ec6ffc1aSdan  lsort [glob test.db*]
893ec6ffc1aSdan} [lsort [list                                           \
894ec6ffc1aSdan  test.db test.db2 test.db3                              \
895ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
896ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
897ec6ffc1aSdan]]
898ec6ffc1aSdan
899ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
900ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
901ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
902ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
903ec6ffc1aSdan#
904ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
905ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
906ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
907ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
908ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
909ec6ffc1aSdan
910ec6ffc1aSdando_execsql_test pager1.4.6.12 {
911ec6ffc1aSdan  ATTACH 'test.db2' AS two;
912ec6ffc1aSdan  SELECT * FROM t2;
913ec6ffc1aSdan} {1 t2.1}
914ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
915ec6ffc1aSdando_execsql_test pager1.4.6.14 {
916ec6ffc1aSdan  ATTACH 'test.db3' AS three;
917ec6ffc1aSdan  SELECT * FROM t3;
918ec6ffc1aSdan} {1 t3.1}
919ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
92010f5a50eSdan
9210e986f51Sdandb close
9220e986f51Sdantv delete
923e08341c6Sdan
924c8ce3972Sdantestvfs tv -default 1
925c8ce3972Sdantv sectorsize 512
926c8ce3972Sdantv script copy_on_journal_delete
927c8ce3972Sdantv filter xDelete
928c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
929c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
930c8ce3972Sdan  return SQLITE_OK
931c8ce3972Sdan}
932c8ce3972Sdanfaultsim_delete_and_reopen
933c8ce3972Sdando_execsql_test pager1.4.7.1 {
9343f94b609Sdan  PRAGMA journal_mode = DELETE;
935c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
936c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
937c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
938c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
939c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
940c8ce3972Sdan  BEGIN;
941c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
942c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
943c8ce3972Sdan  COMMIT;
9443f94b609Sdan} {delete}
945c8ce3972Sdantv filter {}
946c8ce3972Sdandb close
947c8ce3972Sdantv delete
948e1186ab2Sdrhcatch {
949e1186ab2Sdrh  test_syscall install fchmod
950e1186ab2Sdrh  test_syscall fault 1 1
951e1186ab2Sdrh}
952c8ce3972Sdando_test pager1.4.7.2 {
953c8ce3972Sdan  faultsim_restore_and_reopen
954c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
955c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
956c8ce3972Sdan  catchsql { SELECT * FROM t1 }
957c8ce3972Sdan} {1 {unable to open database file}}
958e1186ab2Sdrhcatch {
959e1186ab2Sdrh  test_syscall reset
960e1186ab2Sdrh  test_syscall fault 0 0
961e1186ab2Sdrh}
962c8ce3972Sdando_test pager1.4.7.3 {
963c8ce3972Sdan  db close
964c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
965c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
966fda06befSmistachkin  delete_file test.db-journal
967c8ce3972Sdan  file exists test.db-journal
968c8ce3972Sdan} {0}
969421377e6Sdrhdo_test pager1.4.8.1 {
970421377e6Sdrh  catch {file attributes test.db -permissions r--------}
971421377e6Sdrh  catch {file attributes test.db -readonly 1}
972421377e6Sdrh  sqlite3 db test.db
973421377e6Sdrh  db eval { SELECT * FROM t1 }
974421377e6Sdrh  sqlite3_db_readonly db main
975421377e6Sdrh} {1}
976421377e6Sdrhdo_test pager1.4.8.2 {
977421377e6Sdrh  sqlite3_db_readonly db xyz
978421377e6Sdrh} {-1}
979421377e6Sdrhdo_test pager1.4.8.3 {
980421377e6Sdrh  db close
981421377e6Sdrh  catch {file attributes test.db -readonly 0}
982db0ad5f2Sdan  catch {file attributes test.db -permissions rw-rw-rw-} msg
983421377e6Sdrh  sqlite3 db test.db
984421377e6Sdrh  db eval { SELECT * FROM t1 }
985421377e6Sdrh  sqlite3_db_readonly db main
986421377e6Sdrh} {0}
987c8ce3972Sdan
988de4996e2Sdan#-------------------------------------------------------------------------
989146ed78bSdan# The following tests deal with multi-file commits.
990de4996e2Sdan#
991146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
992146ed78bSdan#               another connection is holding a SHARED lock on one of the
993146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
994146ed78bSdan#
995146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
996146ed78bSdan#
997146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
998146ed78bSdan#
999146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
1000146ed78bSdan#               name is added to a journal file immediately after the last
1001146ed78bSdan#               journal record. But with synchronous=full, extra unused space
1002146ed78bSdan#               is allocated between the last journal record and the
1003146ed78bSdan#               master-journal file name so that the master-journal file
1004146ed78bSdan#               name does not lie on the same sector as the last journal file
1005146ed78bSdan#               record.
1006146ed78bSdan#
1007e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
1008e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
1009e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
1010e08341c6Sdan#
1011146ed78bSdan#
1012146ed78bSdando_test pager1-5.1.1 {
1013146ed78bSdan  faultsim_delete_and_reopen
1014146ed78bSdan  execsql {
1015146ed78bSdan    ATTACH 'test.db2' AS aux;
1016146ed78bSdan    CREATE TABLE t1(a, b);
1017146ed78bSdan    CREATE TABLE aux.t2(a, b);
1018146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
1019146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
1020146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
1021146ed78bSdan  }
1022146ed78bSdan} {}
1023146ed78bSdando_test pager1-5.1.2 {
1024146ed78bSdan  execsql {
1025146ed78bSdan    BEGIN;
1026146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
1027146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
1028146ed78bSdan  }
1029146ed78bSdan  sqlite3 db2 test.db2
1030146ed78bSdan  execsql {
1031146ed78bSdan    BEGIN;
1032146ed78bSdan      SELECT * FROM t2;
1033146ed78bSdan  } db2
1034146ed78bSdan} {}
1035146ed78bSdando_test pager1-5.1.3 {
1036146ed78bSdan  catchsql COMMIT
1037146ed78bSdan} {1 {database is locked}}
1038146ed78bSdando_test pager1-5.1.4 {
1039146ed78bSdan  execsql COMMIT db2
1040146ed78bSdan  execsql COMMIT
1041146ed78bSdan  execsql { SELECT * FROM t2 } db2
1042146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
1043146ed78bSdando_test pager1-5.1.5 {
1044146ed78bSdan  db2 close
1045146ed78bSdan} {}
1046146ed78bSdan
1047146ed78bSdando_test pager1-5.2.1 {
1048146ed78bSdan  execsql {
1049146ed78bSdan    PRAGMA journal_mode = memory;
1050146ed78bSdan    BEGIN;
1051146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
1052146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
1053146ed78bSdan    COMMIT;
1054146ed78bSdan  }
1055146ed78bSdan} {memory}
1056146ed78bSdando_test pager1-5.3.1 {
1057146ed78bSdan  execsql {
1058146ed78bSdan    PRAGMA journal_mode = off;
1059146ed78bSdan    BEGIN;
1060146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1061146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1062146ed78bSdan    COMMIT;
1063146ed78bSdan  }
1064146ed78bSdan} {off}
1065146ed78bSdan
1066146ed78bSdando_test pager1-5.4.1 {
1067146ed78bSdan  db close
1068146ed78bSdan  testvfs tv
1069146ed78bSdan  sqlite3 db test.db -vfs tv
1070146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
1071146ed78bSdan
1072146ed78bSdan  tv filter xDelete
1073146ed78bSdan  tv script max_journal_size
1074146ed78bSdan  tv sectorsize 512
1075146ed78bSdan  set ::max_journal 0
1076146ed78bSdan  proc max_journal_size {method args} {
1077146ed78bSdan    set sz 0
1078146ed78bSdan    catch { set sz [file size test.db-journal] }
1079146ed78bSdan    if {$sz > $::max_journal} {
1080146ed78bSdan      set ::max_journal $sz
1081146ed78bSdan    }
1082146ed78bSdan    return SQLITE_OK
1083146ed78bSdan  }
1084146ed78bSdan  execsql {
1085146ed78bSdan    PRAGMA journal_mode = DELETE;
1086146ed78bSdan    PRAGMA synchronous = NORMAL;
1087146ed78bSdan    BEGIN;
1088146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1089146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1090146ed78bSdan    COMMIT;
1091146ed78bSdan  }
10927f9026ddSdan
10937f9026ddSdan  # The size of the journal file is now:
10947f9026ddSdan  #
10957f9026ddSdan  #   1) 512 byte header +
10967f9026ddSdan  #   2) 2 * (1024+8) byte records +
10977f9026ddSdan  #   3) 20+N bytes of master-journal pointer, where N is the size of
10987f9026ddSdan  #      the master-journal name encoded as utf-8 with no nul term.
10997f9026ddSdan  #
11007f9026ddSdan  set mj_pointer [expr {
1101c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
11027f9026ddSdan  }]
1103c5484654Smistachkin  #
1104c5484654Smistachkin  #   NOTE: For item 3 above, if the current SQLite VFS lacks the concept of a
1105c5484654Smistachkin  #         current directory, the length of the current directory name plus 1
1106c5484654Smistachkin  #         character for the directory separator character are NOT counted as
1107c5484654Smistachkin  #         part of the total size; otherwise, they are.
1108c5484654Smistachkin  #
1109c5484654Smistachkin  ifcapable curdir {
11106aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1111c5484654Smistachkin  }
11127f9026ddSdan  expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
11137f9026ddSdan} 1
1114146ed78bSdando_test pager1-5.4.2 {
1115146ed78bSdan  set ::max_journal 0
1116146ed78bSdan  execsql {
1117146ed78bSdan    PRAGMA synchronous = full;
1118146ed78bSdan    BEGIN;
1119146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
1120146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
1121146ed78bSdan    COMMIT;
1122146ed78bSdan  }
11237f9026ddSdan
11247f9026ddSdan  # In synchronous=full mode, the master-journal pointer is not written
11257f9026ddSdan  # directly after the last record in the journal file. Instead, it is
11267f9026ddSdan  # written starting at the next (in this case 512 byte) sector boundary.
11277f9026ddSdan  #
11287f9026ddSdan  set mj_pointer [expr {
1129c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
11307f9026ddSdan  }]
1131c5484654Smistachkin  #
1132c5484654Smistachkin  #   NOTE: If the current SQLite VFS lacks the concept of a current directory,
1133c5484654Smistachkin  #         the length of the current directory name plus 1 character for the
1134c5484654Smistachkin  #         directory separator character are NOT counted as part of the total
1135c5484654Smistachkin  #         size; otherwise, they are.
1136c5484654Smistachkin  #
1137c5484654Smistachkin  ifcapable curdir {
11386aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1139c5484654Smistachkin  }
11407f9026ddSdan  expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
11417f9026ddSdan} 1
1142146ed78bSdandb close
1143146ed78bSdantv delete
1144146ed78bSdan
1145146ed78bSdando_test pager1-5.5.1 {
1146146ed78bSdan  sqlite3 db test.db
1147146ed78bSdan  execsql {
1148146ed78bSdan    ATTACH 'test.db2' AS aux;
1149146ed78bSdan    PRAGMA journal_mode = PERSIST;
1150146ed78bSdan    CREATE TABLE t3(a, b);
1151146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
1152d5aa9262Sdrh    UPDATE t3 SET b = randomblob(1501);
1153146ed78bSdan  }
1154146ed78bSdan  expr [file size test.db-journal] > 15000
1155146ed78bSdan} {1}
1156146ed78bSdando_test pager1-5.5.2 {
1157146ed78bSdan  execsql {
1158146ed78bSdan    PRAGMA synchronous = full;
1159146ed78bSdan    BEGIN;
1160146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
1161146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
1162146ed78bSdan    COMMIT;
1163146ed78bSdan  }
1164146ed78bSdan  file size test.db-journal
1165146ed78bSdan} {0}
1166146ed78bSdan
1167146ed78bSdan
1168146ed78bSdan#-------------------------------------------------------------------------
1169146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1170146ed78bSdan#
1171146ed78bSdando_test pager1-6.1 {
1172146ed78bSdan  faultsim_delete_and_reopen
1173146ed78bSdan  execsql {
1174f43d7fceSdan    PRAGMA auto_vacuum = none;
1175146ed78bSdan    PRAGMA max_page_count = 10;
1176146ed78bSdan    CREATE TABLE t2(a, b);
1177146ed78bSdan    CREATE TABLE t3(a, b);
1178146ed78bSdan    CREATE TABLE t4(a, b);
1179146ed78bSdan    CREATE TABLE t5(a, b);
1180146ed78bSdan    CREATE TABLE t6(a, b);
1181146ed78bSdan    CREATE TABLE t7(a, b);
1182146ed78bSdan    CREATE TABLE t8(a, b);
1183146ed78bSdan    CREATE TABLE t9(a, b);
1184146ed78bSdan    CREATE TABLE t10(a, b);
1185146ed78bSdan  }
1186146ed78bSdan} {10}
1187d353331aSdando_catchsql_test pager1-6.2 {
1188d353331aSdan  CREATE TABLE t11(a, b)
1189146ed78bSdan} {1 {database or disk is full}}
1190d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1191d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1192d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1193d353331aSdando_execsql_test pager1-6.7 {
1194d353331aSdan  BEGIN;
1195d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1196d353331aSdan    PRAGMA max_page_count = 13;
1197d353331aSdan} {13}
1198d353331aSdando_execsql_test pager1-6.8 {
1199d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1200d353331aSdan    PRAGMA max_page_count = 10;
1201d353331aSdan} {11}
1202d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1203de4996e2Sdan
120460ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
120522b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
120622b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
120722b328b2Sdan
1208153eda0aSdan
1209153eda0aSdan#-------------------------------------------------------------------------
1210153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1211153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1212153eda0aSdan#
1213153eda0aSdan# Each test is specified with 5 variables. As follows:
1214153eda0aSdan#
1215153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1216153eda0aSdan#   $sql: SQL to execute.
1217153eda0aSdan#   $res: Expected result of executing $sql.
1218153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1219153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1220153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1221153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1222153eda0aSdan#
122338e1a279Sdanifcapable wal {
1224153eda0aSdan  faultsim_delete_and_reopen
1225153eda0aSdan  foreach {tn sql res js ws} [subst {
1226153eda0aSdan
1227153eda0aSdan    1  {
1228153eda0aSdan      CREATE TABLE t1(a, b);
1229153eda0aSdan      PRAGMA auto_vacuum=OFF;
1230153eda0aSdan      PRAGMA synchronous=NORMAL;
1231153eda0aSdan      PRAGMA page_size=1024;
1232153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1233153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1234153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1235153eda0aSdan    } {exclusive truncate} 0 -1
1236153eda0aSdan
1237153eda0aSdan    2  {
1238153eda0aSdan      BEGIN IMMEDIATE;
1239153eda0aSdan        SELECT * FROM t1;
1240153eda0aSdan      COMMIT;
1241153eda0aSdan    } {1 2} 0 -1
1242153eda0aSdan
1243153eda0aSdan    3  {
1244153eda0aSdan      BEGIN;
1245153eda0aSdan        SELECT * FROM t1;
1246153eda0aSdan      COMMIT;
1247153eda0aSdan    } {1 2} 0 -1
1248153eda0aSdan
1249153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal       -1 -1
1250153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}        -1 [wal_file_size 1 1024]
12518c408004Sdan    6  { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
1252153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
1253153eda0aSdan
1254153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1255153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1256153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1257153eda0aSdan
1258153eda0aSdan  }] {
1259153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1260153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1261153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1262153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1263153eda0aSdan  }
126438e1a279Sdan}
1265153eda0aSdan
126689ccf448Sdando_test pager1-7.2.1 {
126789ccf448Sdan  faultsim_delete_and_reopen
126889ccf448Sdan  execsql {
126989ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
127089ccf448Sdan    CREATE TABLE t1(a, b);
127189ccf448Sdan    BEGIN;
127289ccf448Sdan      PRAGMA journal_mode = delete;
127389ccf448Sdan      PRAGMA journal_mode = truncate;
127489ccf448Sdan  }
127589ccf448Sdan} {exclusive delete truncate}
127689ccf448Sdando_test pager1-7.2.2 {
127789ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
127889ccf448Sdan  execsql { PRAGMA journal_mode = persist }
127989ccf448Sdan} {truncate}
128089ccf448Sdando_test pager1-7.2.3 {
128189ccf448Sdan  execsql { COMMIT }
128289ccf448Sdan  execsql {
128389ccf448Sdan    PRAGMA journal_mode = persist;
128489ccf448Sdan    PRAGMA journal_size_limit;
128589ccf448Sdan  }
128689ccf448Sdan} {persist -1}
128789ccf448Sdan
1288d353331aSdan#-------------------------------------------------------------------------
1289d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1290d353331aSdan# ":memory:" and "" open temporary databases.
1291d353331aSdan#
12920e986f51Sdanforeach {tn filename} {
12930e986f51Sdan  1 :memory:
12940e986f51Sdan  2 ""
12950e986f51Sdan} {
12960e986f51Sdan  do_test pager1-8.$tn.1 {
1297153eda0aSdan    faultsim_delete_and_reopen
1298153eda0aSdan    db close
12990e986f51Sdan    sqlite3 db $filename
1300153eda0aSdan    execsql {
1301c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1302153eda0aSdan      CREATE TABLE x1(x);
1303153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1304153eda0aSdan      INSERT INTO x1 VALUES('James');
1305153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1306153eda0aSdan      SELECT * FROM x1;
1307153eda0aSdan    }
1308153eda0aSdan  } {Charles James Mary}
13090e986f51Sdan
13100e986f51Sdan  do_test pager1-8.$tn.2 {
13110e986f51Sdan    sqlite3 db2 $filename
13120e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1313153eda0aSdan  } {1 {no such table: x1}}
1314153eda0aSdan
13150e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
13160e986f51Sdan    BEGIN;
13170e986f51Sdan      INSERT INTO x1 VALUES('William');
13180e986f51Sdan      INSERT INTO x1 VALUES('Anne');
13190e986f51Sdan    ROLLBACK;
13200e986f51Sdan  } {}
13210e986f51Sdan}
13220e986f51Sdan
1323dca321aeSdan#-------------------------------------------------------------------------
1324dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1325dca321aeSdan# the pager and the backup API. Test cases:
1326dca321aeSdan#
1327dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1328dca321aeSdan#                 source db is written to during the backup op.
1329dca321aeSdan#
1330dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1331dca321aeSdan#                 source db is written to and then rolled back during a
1332dca321aeSdan#                 backup operation.
1333dca321aeSdan#
1334dca321aeSdando_test pager1-9.0.1 {
1335dca321aeSdan  faultsim_delete_and_reopen
1336dca321aeSdan  db func a_string a_string
1337dca321aeSdan  execsql {
1338dca321aeSdan    PRAGMA cache_size = 10;
1339dca321aeSdan    BEGIN;
1340dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1341dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1342dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1343dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1344dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1345dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1346dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1347dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1348dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1349dca321aeSdan    COMMIT;
1350dca321aeSdan  }
1351dca321aeSdan} {}
1352dca321aeSdando_test pager1-9.0.2 {
1353dca321aeSdan  sqlite3 db2 test.db2
1354dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1355dca321aeSdan  sqlite3_backup B db2 main db main
1356dca321aeSdan  list [B step 10000] [B finish]
1357dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1358dca321aeSdando_test pager1-9.0.3 {
1359dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1360dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1361dca321aeSdan
1362dca321aeSdando_test pager1-9.1.1 {
1363dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1364dca321aeSdan  sqlite3_backup B db2 main db main
1365dca321aeSdan  B step 30
1366dca321aeSdan} {SQLITE_OK}
1367dca321aeSdando_test pager1-9.1.2 {
1368dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1369dca321aeSdan  list [B step 10000] [B finish]
1370dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1371dca321aeSdando_test pager1-9.1.3 {
1372dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1373dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1374dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1375dca321aeSdan
1376dca321aeSdando_test pager1-9.2.1 {
1377dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1378dca321aeSdan  sqlite3_backup B db2 main db main
1379dca321aeSdan  B step 30
1380dca321aeSdan} {SQLITE_OK}
1381dca321aeSdando_test pager1-9.2.2 {
1382dca321aeSdan  execsql {
1383dca321aeSdan    BEGIN;
1384dca321aeSdan      UPDATE ab SET b = a_string(301);
1385dca321aeSdan    ROLLBACK;
1386dca321aeSdan  }
1387dca321aeSdan  list [B step 10000] [B finish]
1388dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1389dca321aeSdando_test pager1-9.2.3 {
1390dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1391dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1392dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1393ec6ffc1aSdandb close
1394ec6ffc1aSdandb2 close
1395ec6ffc1aSdan
1396c396d4afSdando_test pager1-9.3.1 {
1397c396d4afSdan  testvfs tv -default 1
1398c396d4afSdan  tv sectorsize 4096
1399c396d4afSdan  faultsim_delete_and_reopen
1400c396d4afSdan
1401c396d4afSdan  execsql { PRAGMA page_size = 1024 }
1402c396d4afSdan  for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
1403c396d4afSdan} {}
14044a8a6467Sdrhif {[nonzero_reserved_bytes]} {
14054a8a6467Sdrh  # backup with a page size changes is not possible with the codec
14064a8a6467Sdrh  #
14074a8a6467Sdrh  do_test pager1-9.3.2codec {
1408c396d4afSdan    sqlite3 db2 test.db2
1409c396d4afSdan    execsql {
1410c396d4afSdan      PRAGMA page_size = 4096;
1411c396d4afSdan      PRAGMA synchronous = OFF;
1412c396d4afSdan      CREATE TABLE t1(a, b);
1413c396d4afSdan      CREATE TABLE t2(a, b);
1414c396d4afSdan    } db2
14154a8a6467Sdrh    sqlite3_backup B db2 main db main
14164a8a6467Sdrh    B step 30
14174a8a6467Sdrh    list [B step 10000] [B finish]
14184a8a6467Sdrh  } {SQLITE_READONLY SQLITE_READONLY}
14194a8a6467Sdrh  do_test pager1-9.3.3codec {
14204a8a6467Sdrh    db2 close
14214a8a6467Sdrh    db close
14224a8a6467Sdrh    tv delete
14234a8a6467Sdrh    file size test.db2
14244a8a6467Sdrh  } [file size test.db2]
14254a8a6467Sdrh} else {
14264a8a6467Sdrh  do_test pager1-9.3.2 {
14274a8a6467Sdrh    sqlite3 db2 test.db2
14284a8a6467Sdrh    execsql {
14294a8a6467Sdrh      PRAGMA page_size = 4096;
14304a8a6467Sdrh      PRAGMA synchronous = OFF;
14314a8a6467Sdrh      CREATE TABLE t1(a, b);
14324a8a6467Sdrh      CREATE TABLE t2(a, b);
14334a8a6467Sdrh    } db2
1434c396d4afSdan    sqlite3_backup B db2 main db main
1435c396d4afSdan    B step 30
1436c396d4afSdan    list [B step 10000] [B finish]
1437c396d4afSdan  } {SQLITE_DONE SQLITE_OK}
1438c396d4afSdan  do_test pager1-9.3.3 {
1439c396d4afSdan    db2 close
1440c396d4afSdan    db close
1441c396d4afSdan    tv delete
1442c396d4afSdan    file size test.db2
1443c396d4afSdan  } [file size test.db]
14444a8a6467Sdrh}
1445c396d4afSdan
1446f412ee2eSdando_test pager1-9.4.1 {
1447f412ee2eSdan  faultsim_delete_and_reopen
1448f412ee2eSdan  sqlite3 db2 test.db2
1449f412ee2eSdan  execsql {
1450f412ee2eSdan    PRAGMA page_size = 4096;
1451f412ee2eSdan    CREATE TABLE t1(a, b);
1452f412ee2eSdan    CREATE TABLE t2(a, b);
1453f412ee2eSdan  } db2
1454f412ee2eSdan  sqlite3_backup B db2 main db main
1455f412ee2eSdan  list [B step 10000] [B finish]
1456f412ee2eSdan} {SQLITE_DONE SQLITE_OK}
1457f412ee2eSdando_test pager1-9.4.2 {
1458f412ee2eSdan  list [file size test.db2] [file size test.db]
1459b483eba0Sdan} {1024 0}
146033d85c9cSshanehdb2 close
1461d0b0d4dcSdan
1462ec6ffc1aSdan#-------------------------------------------------------------------------
1463ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1464ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1465ec6ffc1aSdan#
1466ec6ffc1aSdantestvfs tv -default 1
1467ec6ffc1aSdanforeach sectorsize {
1468d7a558a9Sdan    16
1469ec6ffc1aSdan    32   64   128   256   512   1024   2048
1470ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1471ec6ffc1aSdan} {
1472ec6ffc1aSdan  tv sectorsize $sectorsize
14731eaaf93aSdrh  tv devchar {}
1474ec6ffc1aSdan  set eff $sectorsize
1475ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1476ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1477ec6ffc1aSdan
1478d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1479ec6ffc1aSdan    faultsim_delete_and_reopen
1480d0b0d4dcSdan    db func a_string a_string
1481ec6ffc1aSdan    execsql {
1482ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1483ec6ffc1aSdan      PRAGMA page_size = 1024;
1484d0b0d4dcSdan      BEGIN;
1485ec6ffc1aSdan        CREATE TABLE t1(a, b);
1486d0b0d4dcSdan        CREATE TABLE t2(a, b);
1487d0b0d4dcSdan        CREATE TABLE t3(a, b);
1488d0b0d4dcSdan      COMMIT;
1489ec6ffc1aSdan    }
1490ec6ffc1aSdan    file size test.db-journal
1491d7a558a9Sdan  } [expr $sectorsize > 65536 ? 65536 : ($sectorsize<32 ? 512 : $sectorsize)]
1492d0b0d4dcSdan
1493d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1494d0b0d4dcSdan    execsql {
1495d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1496d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1497d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1498d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1499d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1500d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1501ec6ffc1aSdan    }
1502d0b0d4dcSdan  } {}
1503d0b0d4dcSdan
1504d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1505d0b0d4dcSdan    db close
1506d0b0d4dcSdan    sqlite3 db test.db
1507d0b0d4dcSdan    execsql {
1508d0b0d4dcSdan      PRAGMA cache_size = 10;
1509d0b0d4dcSdan      BEGIN;
1510d0b0d4dcSdan    }
1511d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1512d0b0d4dcSdan    execsql {
1513d0b0d4dcSdan      COMMIT;
1514d0b0d4dcSdan      SELECT * FROM t2;
1515d0b0d4dcSdan    }
1516d0b0d4dcSdan  } {1 2}
1517d0b0d4dcSdan
1518d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1519d0b0d4dcSdan    execsql {
1520d0b0d4dcSdan      CREATE TABLE t6(a, b);
1521d0b0d4dcSdan      CREATE TABLE t7(a, b);
1522d0b0d4dcSdan      CREATE TABLE t5(a, b);
1523d0b0d4dcSdan      DROP TABLE t6;
1524d0b0d4dcSdan      DROP TABLE t7;
1525d0b0d4dcSdan    }
1526d0b0d4dcSdan    execsql {
1527d0b0d4dcSdan      BEGIN;
1528d0b0d4dcSdan        CREATE TABLE t6(a, b);
1529d0b0d4dcSdan    }
1530d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1531d0b0d4dcSdan    execsql {
1532d0b0d4dcSdan      COMMIT;
1533d0b0d4dcSdan      SELECT * FROM t5;
1534d0b0d4dcSdan    }
1535d0b0d4dcSdan  } {1 2}
1536d0b0d4dcSdan
1537d0b0d4dcSdan}
1538d0b0d4dcSdandb close
1539d0b0d4dcSdan
1540d0b0d4dcSdantv sectorsize 4096
1541d0b0d4dcSdando_test pager1.10.x.1 {
1542d0b0d4dcSdan  faultsim_delete_and_reopen
1543d0b0d4dcSdan  execsql {
1544f43d7fceSdan    PRAGMA auto_vacuum = none;
1545d0b0d4dcSdan    PRAGMA page_size = 1024;
1546d0b0d4dcSdan    CREATE TABLE t1(x);
1547d0b0d4dcSdan  }
1548d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1549d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1550d0b0d4dcSdan  }
1551d0b0d4dcSdan  file size test.db
1552d0b0d4dcSdan} {32768}
1553d0b0d4dcSdando_test pager1.10.x.2 {
1554d0b0d4dcSdan  execsql {
1555d0b0d4dcSdan    CREATE TABLE t2(x);
1556d0b0d4dcSdan    DROP TABLE t2;
1557d0b0d4dcSdan  }
1558d0b0d4dcSdan  file size test.db
1559d0b0d4dcSdan} {33792}
1560d0b0d4dcSdando_test pager1.10.x.3 {
1561d0b0d4dcSdan  execsql {
1562d0b0d4dcSdan    BEGIN;
1563d0b0d4dcSdan    CREATE TABLE t2(x);
1564d0b0d4dcSdan  }
1565d0b0d4dcSdan  recursive_select 30 t1
1566d0b0d4dcSdan  execsql {
1567d0b0d4dcSdan    CREATE TABLE t3(x);
1568d0b0d4dcSdan    COMMIT;
1569d0b0d4dcSdan  }
1570d0b0d4dcSdan} {}
1571d0b0d4dcSdan
1572ec6ffc1aSdandb close
1573ec6ffc1aSdantv delete
1574ec6ffc1aSdan
1575ec6ffc1aSdantestvfs tv -default 1
1576ec6ffc1aSdanfaultsim_delete_and_reopen
1577ec6ffc1aSdandb func a_string a_string
1578ec6ffc1aSdando_execsql_test pager1-11.1 {
15793f94b609Sdan  PRAGMA journal_mode = DELETE;
1580ec6ffc1aSdan  PRAGMA cache_size = 10;
1581ec6ffc1aSdan  BEGIN;
1582ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1583ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1584ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1585ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1586ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1587ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1588ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1589ec6ffc1aSdan  COMMIT;
1590ec6ffc1aSdan  BEGIN;
1591ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
15923f94b609Sdan} {delete}
1593ec6ffc1aSdan
1594ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1595ec6ffc1aSdantv script lockout
1596ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1597ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1598ec6ffc1aSdan
1599ec6ffc1aSdantv script {}
1600ec6ffc1aSdando_test pager1-11.3 {
1601ec6ffc1aSdan  sqlite3 db2 test.db
1602ec6ffc1aSdan  execsql {
1603ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1604ec6ffc1aSdan    PRAGMA integrity_check;
1605ec6ffc1aSdan  } db2
1606ec6ffc1aSdan} {truncate ok}
1607ec6ffc1aSdando_test pager1-11.4 {
1608ec6ffc1aSdan  db2 close
1609f6c61471Sdan  file exists test.db-journal
1610ec6ffc1aSdan} {0}
1611ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1612f9b4419dSdandb close
1613f9b4419dSdantv delete
1614ec6ffc1aSdan
1615f9b4419dSdan#-------------------------------------------------------------------------
1616f9b4419dSdan# Test "PRAGMA page_size"
1617f9b4419dSdan#
1618f43d7fceSdantestvfs tv -default 1
1619f43d7fceSdantv sectorsize 1024
1620f9b4419dSdanforeach pagesize {
1621f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1622f9b4419dSdan} {
1623f9b4419dSdan  faultsim_delete_and_reopen
1624f9b4419dSdan
1625f43d7fceSdan  # The sector-size (according to the VFS) is 1024 bytes. So if the
1626f43d7fceSdan  # page-size requested using "PRAGMA page_size" is greater than the
1627f43d7fceSdan  # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
1628f43d7fceSdan  # page-size remains 1024 bytes.
1629f43d7fceSdan  #
1630f43d7fceSdan  set eff $pagesize
1631f43d7fceSdan  if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
1632f43d7fceSdan
1633f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1634f9b4419dSdan    sqlite3 db2 test.db
1635f9b4419dSdan    execsql "
1636f9b4419dSdan      PRAGMA page_size = $pagesize;
1637f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1638f9b4419dSdan    " db2
1639f9b4419dSdan    file size test.db
1640f43d7fceSdan  } $eff
1641f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1642f9b4419dSdan    sqlite3 db2 test.db
1643f9b4419dSdan    execsql {
1644f9b4419dSdan      SELECT count(*) FROM v;
1645f9b4419dSdan      PRAGMA main.page_size;
1646f9b4419dSdan    } db2
1647f43d7fceSdan  } [list 1 $eff]
1648f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1649f9b4419dSdan    execsql {
1650f9b4419dSdan      SELECT count(*) FROM v;
1651f9b4419dSdan      PRAGMA main.page_size;
1652f9b4419dSdan    }
1653f43d7fceSdan  } [list 1 $eff]
1654f9b4419dSdan  db2 close
1655f9b4419dSdan}
1656f43d7fceSdandb close
1657f43d7fceSdantv delete
1658dca321aeSdan
1659d353331aSdan#-------------------------------------------------------------------------
1660d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1661d353331aSdan#
1662d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1663d353331aSdan#                journal mode: If the journal associated with a transaction
1664d353331aSdan#                is smaller than the journal file (because a previous
1665d353331aSdan#                transaction left a very large non-hot journal file in the
1666d353331aSdan#                file-system), then SQLite has to be careful that there is
1667d353331aSdan#                not a journal-header left over from a previous transaction
1668d353331aSdan#                immediately following the journal content just written.
1669d353331aSdan#                If there is, and the process crashes so that the journal
1670d353331aSdan#                becomes a hot-journal and must be rolled back by another
1671d353331aSdan#                process, there is a danger that the other process may roll
1672d353331aSdan#                back the aborted transaction, then continue copying data
1673d353331aSdan#                from an older transaction from the remainder of the journal.
1674d353331aSdan#                See the syncJournal() function for details.
1675d353331aSdan#
1676d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1677d353331aSdan#                the mix to make the integrity-check more likely to catch
1678d353331aSdan#                errors.
1679d353331aSdan#
1680d353331aSdantestvfs tv -default 1
1681d353331aSdantv script xSyncCb
1682d353331aSdantv filter xSync
1683d353331aSdanproc xSyncCb {method filename args} {
1684d353331aSdan  set t [file tail $filename]
1685d353331aSdan  if {$t == "test.db"} faultsim_save
1686d353331aSdan  return SQLITE_OK
1687d353331aSdan}
1688d353331aSdanfaultsim_delete_and_reopen
1689d353331aSdandb func a_string a_string
1690e91a54e1Sdan
1691d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1692d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1693d353331aSdan# frequent journal headers.
1694d353331aSdan#
1695d353331aSdando_execsql_test pager1-13.1.1 {
1696d353331aSdan  PRAGMA page_size = 1024;
1697d353331aSdan  PRAGMA journal_mode = PERSIST;
1698d353331aSdan  PRAGMA cache_size = 10;
1699d353331aSdan  BEGIN;
1700d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1701d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1702d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1703d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1704d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1705d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1706d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1707d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1708d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1709d353331aSdan  COMMIT;
1710d353331aSdan  UPDATE t1 SET b = a_string(400);
1711d353331aSdan} {persist}
1712d353331aSdan
1713b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1714d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1715d353331aSdan# of these will write just enough content that one of the old headers created
1716d353331aSdan# by the transaction in the block above lies immediately after the content
1717d353331aSdan# journalled by the current transaction.
1718d353331aSdan#
1719d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1720d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1721d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1722d353331aSdan  } {}
1723d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1724d353331aSdan
1725d353331aSdan  # Try to access the snapshot of the file-system.
1726d353331aSdan  #
1727d353331aSdan  sqlite3 db2 sv_test.db
1728d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1729d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1730d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1731d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1732d353331aSdan    execsql { PRAGMA integrity_check } db2
1733d353331aSdan  } {ok}
1734d353331aSdan  db2 close
1735d353331aSdan}
1736b2f20bfcSshaneh}
1737d353331aSdan
1738b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1739d353331aSdan# Same test as above. But this time with an index on the table.
1740d353331aSdan#
1741d353331aSdando_execsql_test pager1-13.2.1 {
1742d353331aSdan  CREATE INDEX i1 ON t1(b);
1743d353331aSdan  UPDATE t1 SET b = a_string(400);
1744d353331aSdan} {}
1745d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1746d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1747d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1748d353331aSdan  } {}
1749d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1750d353331aSdan  sqlite3 db2 sv_test.db
1751d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1752d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1753d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1754d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1755d353331aSdan    execsql { PRAGMA integrity_check } db2
1756d353331aSdan  } {ok}
1757d353331aSdan  db2 close
1758d353331aSdan}
1759b2f20bfcSshaneh}
1760d353331aSdan
1761d353331aSdandb close
1762d353331aSdantv delete
1763d353331aSdan
1764d353331aSdan#-------------------------------------------------------------------------
1765d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1766d353331aSdan#
1767d353331aSdanfaultsim_delete_and_reopen
1768d353331aSdando_execsql_test pager1-14.1.1 {
1769d353331aSdan  PRAGMA journal_mode = OFF;
1770d353331aSdan  CREATE TABLE t1(a, b);
1771d353331aSdan  BEGIN;
1772d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1773d353331aSdan  COMMIT;
1774d353331aSdan  SELECT * FROM t1;
1775d353331aSdan} {off 1 2}
1776d353331aSdando_catchsql_test pager1-14.1.2 {
1777d353331aSdan  BEGIN;
1778d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1779d353331aSdan  ROLLBACK;
1780d353331aSdan} {0 {}}
1781d353331aSdando_execsql_test pager1-14.1.3 {
1782d353331aSdan  SELECT * FROM t1;
1783354bfe03Sdan} {1 2}
1784d353331aSdando_catchsql_test pager1-14.1.4 {
1785d353331aSdan  BEGIN;
1786d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1787d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1788f9c8ce3cSdrh} {1 {UNIQUE constraint failed: t1.rowid}}
1789d353331aSdando_execsql_test pager1-14.1.5 {
1790d353331aSdan  COMMIT;
1791d353331aSdan  SELECT * FROM t1;
1792354bfe03Sdan} {1 2 2 2}
1793d353331aSdan
1794c8ce3972Sdan#-------------------------------------------------------------------------
1795c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1796c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1797c8ce3972Sdan#
1798c8ce3972Sdanfaultsim_delete_and_reopen
1799c8ce3972Sdando_execsql_test pager1-15.0 {
1800c8ce3972Sdan  CREATE TABLE tx(y, z);
1801c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1802c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1803c8ce3972Sdan} {}
1804c8ce3972Sdandb close
1805c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1806c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1807c8ce3972Sdan  sqlite3 db test.db
1808c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1809c8ce3972Sdan    SELECT * FROM tx;
1810c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1811c8ce3972Sdan  db close
1812c8ce3972Sdan  tv delete
1813c8ce3972Sdan}
1814c8ce3972Sdan
1815c8ce3972Sdan#-------------------------------------------------------------------------
1816c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1817c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1818c8ce3972Sdan#
1819c8ce3972Sdantestvfs tv -default 1
1820c8ce3972Sdantv script xOpenCb
1821c8ce3972Sdantv filter xOpen
182233f5379cSdanproc xOpenCb {method filename args} {
1823c8ce3972Sdan  set ::file_len [string length $filename]
1824c8ce3972Sdan}
1825c8ce3972Sdansqlite3 db test.db
1826c8ce3972Sdandb close
1827c8ce3972Sdantv delete
1828c8ce3972Sdan
1829c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1830c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1831c8ce3972Sdan
1832c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1833c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1834c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1835c8ce3972Sdan  #
1836c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1837c8ce3972Sdan    set res {0 {}}
1838c8ce3972Sdan  } else {
1839c8ce3972Sdan    set res {1 {unable to open database file}}
1840c8ce3972Sdan  }
1841c8ce3972Sdan
1842c8ce3972Sdan  do_test pager1-16.1.$ii {
1843c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1844c8ce3972Sdan  } $res
1845c8ce3972Sdan
1846c8ce3972Sdan  catch {db close}
1847c8ce3972Sdan  tv delete
1848c8ce3972Sdan}
1849c8ce3972Sdan
1850c8ce3972Sdan
1851c8ce3972Sdan#-------------------------------------------------------------------------
1852c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1853c8ce3972Sdan# numbers:
1854c8ce3972Sdan#
1855c8ce3972Sdan#   + The locking page,
1856c8ce3972Sdan#   + Page 0,
1857c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1858c8ce3972Sdan#
1859f4ba1093Sdan# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
1860f4ba1093Sdan# that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
1861f4ba1093Sdan#
1862f4ba1093Sdanifcapable !direct_read {
1863c8ce3972Sdando_test pager1-18.1 {
1864c8ce3972Sdan  faultsim_delete_and_reopen
1865c8ce3972Sdan  db func a_string a_string
1866c8ce3972Sdan  execsql {
1867c8ce3972Sdan    PRAGMA page_size = 1024;
1868c8ce3972Sdan    CREATE TABLE t1(a, b);
1869c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1870c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1871c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1872c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1873c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1874c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1875c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1876c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1877c8ce3972Sdan  }
1878c8ce3972Sdan} {}
1879c8ce3972Sdando_test pager1-18.2 {
1880c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1881c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1882*6ab91a7aSdrh  sqlite3_db_config db DEFENSIVE 0
1883c8ce3972Sdan  execsql {
1884c8ce3972Sdan    PRAGMA writable_schema = 1;
1885c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1886c8ce3972Sdan  }
1887c8ce3972Sdan  sqlite3 db2 test.db
1888c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1889c8ce3972Sdan} {1 {database disk image is malformed}}
1890c8ce3972Sdandb2 close
1891a748fdccSdrhdo_test pager1-18.3.1 {
1892c8ce3972Sdan  execsql {
1893c8ce3972Sdan    CREATE TABLE t2(x);
1894c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1895c8ce3972Sdan  }
1896c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1897c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1898c8ce3972Sdan  sqlite3 db2 test.db
1899a748fdccSdrh  # even though x is malformed, because typeof() does
1900a748fdccSdrh  # not load the content of x, the error is not noticed.
1901a748fdccSdrh  catchsql { SELECT typeof(x) FROM t2 } db2
1902a748fdccSdrh} {0 text}
1903a748fdccSdrhdo_test pager1-18.3.2 {
1904a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1905a748fdccSdrh  # detected
1906a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1907a748fdccSdrh} {1 {database disk image is malformed}}
1908a748fdccSdrhdb2 close
1909a748fdccSdrhdo_test pager1-18.3.3 {
1910a748fdccSdrh  execsql {
1911a748fdccSdrh    DELETE FROM t2;
1912a748fdccSdrh    INSERT INTO t2 VALUES(randomblob(5000));
1913a748fdccSdrh  }
1914a748fdccSdrh  set pgno [expr ([file size test.db] / 1024)-2]
1915a748fdccSdrh  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1916a748fdccSdrh  sqlite3 db2 test.db
1917a748fdccSdrh  # even though x is malformed, because length() and typeof() do
1918a748fdccSdrh  # not load the content of x, the error is not noticed.
1919a748fdccSdrh  catchsql { SELECT length(x), typeof(x) FROM t2 } db2
1920a748fdccSdrh} {0 {5000 blob}}
1921a748fdccSdrhdo_test pager1-18.3.4 {
1922a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1923a748fdccSdrh  # detected
1924a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1925c8ce3972Sdan} {1 {database disk image is malformed}}
1926c8ce3972Sdandb2 close
1927c8ce3972Sdando_test pager1-18.4 {
1928c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1929c8ce3972Sdan  sqlite3 db2 test.db
1930a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1931c8ce3972Sdan} {1 {database disk image is malformed}}
1932c8ce3972Sdandb2 close
1933c8ce3972Sdando_test pager1-18.5 {
1934c8ce3972Sdan  sqlite3 db ""
1935*6ab91a7aSdrh  sqlite3_db_config db DEFENSIVE 0
1936c8ce3972Sdan  execsql {
1937c8ce3972Sdan    CREATE TABLE t1(a, b);
1938c8ce3972Sdan    CREATE TABLE t2(a, b);
1939c8ce3972Sdan    PRAGMA writable_schema = 1;
1940c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1941c8ce3972Sdan    PRAGMA writable_schema = 0;
1942c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1943c8ce3972Sdan  }
1944c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1945ba3cbf3dSdan} {1 {database disk image is malformed}}
1946c8ce3972Sdandb close
1947c8ce3972Sdan
1948ba3cbf3dSdando_test pager1-18.6 {
1949ba3cbf3dSdan  faultsim_delete_and_reopen
1950ba3cbf3dSdan  db func a_string a_string
1951ba3cbf3dSdan  execsql {
1952ba3cbf3dSdan    PRAGMA page_size = 1024;
1953ba3cbf3dSdan    CREATE TABLE t1(x);
1954ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1955ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1956ba3cbf3dSdan  }
1957ba3cbf3dSdan
1958ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1959ba3cbf3dSdan  db close
1960ba3cbf3dSdan
1961ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1962ba3cbf3dSdan  sqlite3 db test.db
1963ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1964ba3cbf3dSdan} {1 {database disk image is malformed}}
1965f4ba1093Sdan}
1966ba3cbf3dSdan
1967ba3cbf3dSdando_test pager1-19.1 {
1968ba3cbf3dSdan  sqlite3 db ""
1969ba3cbf3dSdan  db func a_string a_string
1970ba3cbf3dSdan  execsql {
1971ba3cbf3dSdan    PRAGMA page_size = 512;
1972ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1973ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1974ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1975ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1976ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1977ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1978ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1979ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1980ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1981ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1982ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1983ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1984ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1985ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1986ba3cbf3dSdan    );
1987ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1988ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1989ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1990ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1991ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1992ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1993ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1994ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1995ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1996ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1997ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1998ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1999ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
2000ba3cbf3dSdan    );
2001ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
2002ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
2003ba3cbf3dSdan    VACUUM;
2004ba3cbf3dSdan  }
2005ba3cbf3dSdan} {}
2006ba3cbf3dSdan
20076b63ab47Sdan#-------------------------------------------------------------------------
20086b63ab47Sdan# Test a couple of special cases that come up while committing
20096b63ab47Sdan# transactions:
20106b63ab47Sdan#
20116b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
20126b63ab47Sdan#                  database has not been modified at all.
20136b63ab47Sdan#
20146b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
20156b63ab47Sdan#
20166b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
20176b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
20186b63ab47Sdan#                  disk before the commit.
20196b63ab47Sdan#
20206b63ab47Sdando_test pager1-20.1.1 {
20216b63ab47Sdan  catch {db close}
20226b63ab47Sdan  sqlite3 db :memory:
20236b63ab47Sdan  execsql {
20246b63ab47Sdan    CREATE TABLE one(two, three);
20256b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
20266b63ab47Sdan  }
20276b63ab47Sdan} {}
20286b63ab47Sdando_test pager1-20.1.2 {
20296b63ab47Sdan  execsql {
20306b63ab47Sdan    BEGIN EXCLUSIVE;
20316b63ab47Sdan    COMMIT;
20326b63ab47Sdan  }
20336b63ab47Sdan} {}
20346b63ab47Sdan
20356b63ab47Sdando_test pager1-20.2.1 {
20366b63ab47Sdan  faultsim_delete_and_reopen
20376b63ab47Sdan  execsql {
20386b63ab47Sdan    PRAGMA locking_mode = exclusive;
20396b63ab47Sdan    PRAGMA journal_mode = persist;
20406b63ab47Sdan    CREATE TABLE one(two, three);
20416b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
20426b63ab47Sdan  }
20436b63ab47Sdan} {exclusive persist}
20446b63ab47Sdando_test pager1-20.2.2 {
20456b63ab47Sdan  execsql {
20466b63ab47Sdan    BEGIN EXCLUSIVE;
20476b63ab47Sdan    COMMIT;
20486b63ab47Sdan  }
20496b63ab47Sdan} {}
20506b63ab47Sdan
20519091f775Sshanehifcapable wal {
20526b63ab47Sdan  do_test pager1-20.3.1 {
20536b63ab47Sdan    faultsim_delete_and_reopen
20546b63ab47Sdan    db func a_string a_string
20556b63ab47Sdan    execsql {
20566b63ab47Sdan      PRAGMA cache_size = 10;
20576b63ab47Sdan      PRAGMA journal_mode = wal;
20586b63ab47Sdan      BEGIN;
20596b63ab47Sdan        CREATE TABLE t1(x);
20606b63ab47Sdan        CREATE TABLE t2(y);
20616b63ab47Sdan        INSERT INTO t1 VALUES(a_string(800));
20626b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
20636b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
20646b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
20656b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
20666b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
20676b63ab47Sdan      COMMIT;
20686b63ab47Sdan    }
20696b63ab47Sdan  } {wal}
20706b63ab47Sdan  do_test pager1-20.3.2 {
20716b63ab47Sdan    execsql {
20726b63ab47Sdan      BEGIN;
20736b63ab47Sdan      INSERT INTO t2 VALUES('xxxx');
20746b63ab47Sdan    }
2075c396d4afSdan    recursive_select 32 t1
20766b63ab47Sdan    execsql COMMIT
20776b63ab47Sdan  } {}
20789091f775Sshaneh}
20796b63ab47Sdan
208089ccf448Sdan#-------------------------------------------------------------------------
208189ccf448Sdan# Test that a WAL database may not be opened if:
208289ccf448Sdan#
208389ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
208489ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
208589ccf448Sdan#
20869091f775Sshanehifcapable wal {
208789ccf448Sdan  do_test pager1-21.0 {
208889ccf448Sdan    faultsim_delete_and_reopen
208989ccf448Sdan    execsql {
209089ccf448Sdan      PRAGMA journal_mode = WAL;
209189ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
209289ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
209389ccf448Sdan    }
209489ccf448Sdan  } {wal}
209589ccf448Sdan  do_test pager1-21.1 {
209689ccf448Sdan    testvfs tv -noshm 1
209789ccf448Sdan    sqlite3 db2 test.db -vfs tv
209889ccf448Sdan    catchsql { SELECT * FROM ko } db2
209989ccf448Sdan  } {1 {unable to open database file}}
210089ccf448Sdan  db2 close
210189ccf448Sdan  tv delete
210289ccf448Sdan  do_test pager1-21.2 {
210389ccf448Sdan    testvfs tv -iversion 1
210489ccf448Sdan    sqlite3 db2 test.db -vfs tv
210589ccf448Sdan    catchsql { SELECT * FROM ko } db2
210689ccf448Sdan  } {1 {unable to open database file}}
210789ccf448Sdan  db2 close
210889ccf448Sdan  tv delete
21099091f775Sshaneh}
211089ccf448Sdan
211189ccf448Sdan#-------------------------------------------------------------------------
211289ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
211389ccf448Sdan#
211489ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
211589ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
211689ccf448Sdan#
21175209132aSdanifcapable wal {
211889ccf448Sdan  do_test pager1-22.1.1 {
211989ccf448Sdan    faultsim_delete_and_reopen
212089ccf448Sdan    execsql {
212189ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
212289ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
212389ccf448Sdan    }
212489ccf448Sdan    execsql { PRAGMA wal_checkpoint }
2125bdd9af0fSdan  } {0 -1 -1}
212689ccf448Sdan  do_test pager1-22.2.1 {
212789ccf448Sdan    testvfs tv -default 1
212889ccf448Sdan    tv filter xSync
212989ccf448Sdan    tv script xSyncCb
213089ccf448Sdan    proc xSyncCb {args} {incr ::synccount}
213189ccf448Sdan    set ::synccount 0
213289ccf448Sdan    sqlite3 db test.db
213389ccf448Sdan    execsql {
213489ccf448Sdan      PRAGMA synchronous = off;
213589ccf448Sdan      PRAGMA journal_mode = WAL;
213689ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
213789ccf448Sdan    }
213889ccf448Sdan    execsql { PRAGMA wal_checkpoint }
213989ccf448Sdan    set synccount
214089ccf448Sdan  } {0}
214189ccf448Sdan  db close
214289ccf448Sdan  tv delete
21435209132aSdan}
214489ccf448Sdan
214589ccf448Sdan#-------------------------------------------------------------------------
214689ccf448Sdan# Tests for changing journal mode.
214789ccf448Sdan#
214889ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
214989ccf448Sdan#                  the journal file is deleted.
215089ccf448Sdan#
215189ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
215289ccf448Sdan#                  on the database file.
215389ccf448Sdan#
215489ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
215589ccf448Sdan#                  on the database file.
215689ccf448Sdan#
215789ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
215889ccf448Sdan#
215989ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
216089ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
216189ccf448Sdan#
2162d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
2163d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
2164d0b0d4dcSdan#                  locking_mode=exclusive).
2165d0b0d4dcSdan#
216689ccf448Sdando_test pager1-23.1.1 {
216789ccf448Sdan  faultsim_delete_and_reopen
216889ccf448Sdan  execsql {
216989ccf448Sdan    PRAGMA journal_mode = PERSIST;
217089ccf448Sdan    CREATE TABLE t1(a, b);
217189ccf448Sdan  }
217289ccf448Sdan  file exists test.db-journal
217389ccf448Sdan} {1}
217489ccf448Sdando_test pager1-23.1.2 {
217589ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
217689ccf448Sdan  file exists test.db-journal
217789ccf448Sdan} {0}
217889ccf448Sdan
217989ccf448Sdando_test pager1-23.2.1 {
218089ccf448Sdan  execsql {
218189ccf448Sdan    PRAGMA journal_mode = PERSIST;
218289ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
218389ccf448Sdan  }
218489ccf448Sdan  db eval { SELECT * FROM t1 } {
218589ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
218689ccf448Sdan  }
218789ccf448Sdan  execsql { PRAGMA journal_mode }
218889ccf448Sdan} {delete}
218989ccf448Sdando_test pager1-23.2.2 {
219089ccf448Sdan  file exists test.db-journal
219189ccf448Sdan} {0}
219289ccf448Sdan
219389ccf448Sdando_test pager1-23.3.1 {
219489ccf448Sdan  execsql {
219589ccf448Sdan    PRAGMA journal_mode = PERSIST;
219689ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
219789ccf448Sdan    BEGIN IMMEDIATE;
219889ccf448Sdan  }
219989ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
220089ccf448Sdan  execsql { PRAGMA journal_mode }
220189ccf448Sdan} {delete}
220289ccf448Sdando_test pager1-23.3.2 {
220389ccf448Sdan  file exists test.db-journal
220489ccf448Sdan} {0}
220589ccf448Sdando_test pager1-23.3.3 {
220689ccf448Sdan  execsql COMMIT
220789ccf448Sdan} {}
220889ccf448Sdan
220989ccf448Sdando_test pager1-23.4.1 {
221089ccf448Sdan  execsql {
221189ccf448Sdan    PRAGMA journal_mode = PERSIST;
221289ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
221389ccf448Sdan    BEGIN EXCLUSIVE;
221489ccf448Sdan  }
221589ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
221689ccf448Sdan  execsql { PRAGMA journal_mode }
221789ccf448Sdan} {delete}
221889ccf448Sdando_test pager1-23.4.2 {
221989ccf448Sdan  file exists test.db-journal
222089ccf448Sdan} {0}
222189ccf448Sdando_test pager1-23.4.3 {
222289ccf448Sdan  execsql COMMIT
222389ccf448Sdan} {}
222489ccf448Sdan
222589ccf448Sdando_test pager1-23.5.1 {
222689ccf448Sdan  faultsim_delete_and_reopen
222789ccf448Sdan  sqlite3 db :memory:
222889ccf448Sdan} {}
222989ccf448Sdanforeach {tn mode possible} {
223089ccf448Sdan  2  off      1
223189ccf448Sdan  3  memory   1
223289ccf448Sdan  4  persist  0
223389ccf448Sdan  5  delete   0
223489ccf448Sdan  6  wal      0
223589ccf448Sdan  7  truncate 0
223689ccf448Sdan} {
223789ccf448Sdan  do_test pager1-23.5.$tn.1 {
223889ccf448Sdan    execsql "PRAGMA journal_mode = off"
223989ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
224089ccf448Sdan  } [if $possible {list $mode} {list off}]
224189ccf448Sdan  do_test pager1-23.5.$tn.2 {
224289ccf448Sdan    execsql "PRAGMA journal_mode = memory"
224389ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
224489ccf448Sdan  } [if $possible {list $mode} {list memory}]
224589ccf448Sdan}
2246d0b0d4dcSdando_test pager1-23.6.1 {
224789ccf448Sdan  execsql {PRAGMA locking_mode = normal}
224889ccf448Sdan} {exclusive}
2249d0b0d4dcSdando_test pager1-23.6.2 {
225089ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
225189ccf448Sdan} {exclusive}
2252d0b0d4dcSdando_test pager1-23.6.3 {
225389ccf448Sdan  execsql {PRAGMA locking_mode}
225489ccf448Sdan} {exclusive}
2255d0b0d4dcSdando_test pager1-23.6.4 {
225689ccf448Sdan  execsql {PRAGMA main.locking_mode}
225789ccf448Sdan} {exclusive}
22586b63ab47Sdan
2259d0b0d4dcSdan#-------------------------------------------------------------------------
2260d0b0d4dcSdan#
2261d0b0d4dcSdando_test pager1-24.1.1 {
2262d0b0d4dcSdan  faultsim_delete_and_reopen
2263d0b0d4dcSdan  db func a_string a_string
2264d0b0d4dcSdan  execsql {
2265d0b0d4dcSdan    PRAGMA cache_size = 10;
2266d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2267d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2268d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2269d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2270d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2271d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2272d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2273d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2274d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2275d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2276d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2277d0b0d4dcSdan  }
2278d0b0d4dcSdan} {}
2279d0b0d4dcSdando_test pager1-24.1.2 {
2280d0b0d4dcSdan  execsql {
2281d0b0d4dcSdan    BEGIN;
2282d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2283d0b0d4dcSdan  }
2284c396d4afSdan  recursive_select 64 x2
2285d0b0d4dcSdan} {}
2286d0b0d4dcSdando_test pager1-24.1.3 {
2287d0b0d4dcSdan  execsql {
2288d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2289d0b0d4dcSdan    COMMIT;
2290d0b0d4dcSdan    PRAGMA integrity_check;
2291d0b0d4dcSdan    SELECT count(*) FROM x1;
2292d0b0d4dcSdan  }
2293d0b0d4dcSdan} {ok 33}
2294d0b0d4dcSdan
2295d0b0d4dcSdando_test pager1-24.1.4 {
2296d0b0d4dcSdan  execsql {
2297d0b0d4dcSdan    DELETE FROM x1;
2298d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2299d0b0d4dcSdan    BEGIN;
2300d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2301d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2302d0b0d4dcSdan  }
2303c396d4afSdan  recursive_select 64 x2 {db eval COMMIT}
2304d0b0d4dcSdan  execsql {
2305d0b0d4dcSdan    PRAGMA integrity_check;
2306d0b0d4dcSdan    SELECT count(*) FROM x1;
2307d0b0d4dcSdan  }
2308d0b0d4dcSdan} {ok 33}
2309d0b0d4dcSdan
2310d0b0d4dcSdando_test pager1-24.1.5 {
2311d0b0d4dcSdan  execsql {
2312d0b0d4dcSdan    DELETE FROM x1;
2313d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2314d0b0d4dcSdan  }
2315c396d4afSdan  recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
2316d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2317d0b0d4dcSdan} {}
2318d0b0d4dcSdan
2319d0b0d4dcSdan#-------------------------------------------------------------------------
2320d0b0d4dcSdan#
2321d0b0d4dcSdando_test pager1-25-1 {
2322d0b0d4dcSdan  faultsim_delete_and_reopen
2323d0b0d4dcSdan  execsql {
2324d0b0d4dcSdan    BEGIN;
2325d0b0d4dcSdan      SAVEPOINT abc;
2326d0b0d4dcSdan        CREATE TABLE t1(a, b);
2327d0b0d4dcSdan      ROLLBACK TO abc;
2328d0b0d4dcSdan    COMMIT;
2329d0b0d4dcSdan  }
2330d0b0d4dcSdan  db close
2331d0b0d4dcSdan} {}
2332d0b0d4dcSdando_test pager1-25-2 {
2333d0b0d4dcSdan  faultsim_delete_and_reopen
2334d0b0d4dcSdan  execsql {
2335d0b0d4dcSdan    SAVEPOINT abc;
2336d0b0d4dcSdan      CREATE TABLE t1(a, b);
2337d0b0d4dcSdan    ROLLBACK TO abc;
2338d0b0d4dcSdan    COMMIT;
2339d0b0d4dcSdan  }
2340d0b0d4dcSdan  db close
2341d0b0d4dcSdan} {}
23426b63ab47Sdan
2343c396d4afSdan#-------------------------------------------------------------------------
2344c396d4afSdan# Sector-size tests.
2345c396d4afSdan#
2346c396d4afSdando_test pager1-26.1 {
2347c396d4afSdan  testvfs tv -default 1
2348c396d4afSdan  tv sectorsize 4096
2349c396d4afSdan  faultsim_delete_and_reopen
2350c396d4afSdan  db func a_string a_string
2351c396d4afSdan  execsql {
2352c396d4afSdan    PRAGMA page_size = 512;
2353c396d4afSdan    CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
2354c396d4afSdan    BEGIN;
2355c396d4afSdan      INSERT INTO tbl VALUES(a_string(25), a_string(600));
2356c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2357c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2358c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2359c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2360c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2361c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2362c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2363c396d4afSdan    COMMIT;
2364c396d4afSdan  }
2365c396d4afSdan} {}
2366c396d4afSdando_execsql_test pager1-26.1 {
2367c396d4afSdan  UPDATE tbl SET b = a_string(550);
2368c396d4afSdan} {}
2369c396d4afSdandb close
2370c396d4afSdantv delete
2371c396d4afSdan
2372c396d4afSdan#-------------------------------------------------------------------------
237322b328b2Sdan#
2374c396d4afSdando_test pager1.27.1 {
2375c396d4afSdan  faultsim_delete_and_reopen
2376c396d4afSdan  sqlite3_pager_refcounts db
2377c396d4afSdan  execsql {
2378c396d4afSdan    BEGIN;
2379c396d4afSdan      CREATE TABLE t1(a, b);
2380c396d4afSdan  }
2381c396d4afSdan  sqlite3_pager_refcounts db
2382c396d4afSdan  execsql COMMIT
2383c396d4afSdan} {}
2384c396d4afSdan
238522b328b2Sdan#-------------------------------------------------------------------------
238622b328b2Sdan# Test that attempting to open a write-transaction with
238722b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on
238822b328b2Sdan# the same database.
238922b328b2Sdan#
239022b328b2Sdancatch { db close }
23919091f775Sshanehifcapable wal {
239222b328b2Sdan  do_multiclient_test tn {
239322b328b2Sdan    do_test pager1-28.$tn.1 {
239422b328b2Sdan      sql1 {
239522b328b2Sdan        PRAGMA journal_mode = WAL;
239622b328b2Sdan        CREATE TABLE t1(a, b);
239722b328b2Sdan        INSERT INTO t1 VALUES('a', 'b');
239822b328b2Sdan      }
239922b328b2Sdan    } {wal}
240022b328b2Sdan    do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
240122b328b2Sdan
240222b328b2Sdan    do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
240322b328b2Sdan    do_test pager1-28.$tn.4 {
240422b328b2Sdan      csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
240522b328b2Sdan    } {1 {database is locked}}
240622b328b2Sdan    code2 { db2 close ; sqlite3 db2 test.db }
240722b328b2Sdan    do_test pager1-28.$tn.4 {
240822b328b2Sdan      sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
240922b328b2Sdan    } {}
241022b328b2Sdan  }
24119091f775Sshaneh}
24125653e4daSdan
24135653e4daSdan#-------------------------------------------------------------------------
24145653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager
24155653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a
24165653e4daSdan# RESERVED lock on the database file, this step is skipped.
24175653e4daSdan#
24185653e4daSdando_multiclient_test tn {
24195653e4daSdan  do_test pager1-28.$tn.1 {
24205653e4daSdan    sql1 {
24215653e4daSdan      PRAGMA journal_mode = PERSIST;
24225653e4daSdan      CREATE TABLE t1(a, b);
24235653e4daSdan      INSERT INTO t1 VALUES('a', 'b');
24245653e4daSdan    }
24255653e4daSdan  } {persist}
24265653e4daSdan  do_test pager1-28.$tn.2 { file exists test.db-journal } 1
24275653e4daSdan  do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
24285653e4daSdan  do_test pager1-28.$tn.4 { file exists test.db-journal } 0
24295653e4daSdan
24305653e4daSdan  do_test pager1-28.$tn.5 {
24315653e4daSdan    sql1 {
24325653e4daSdan      PRAGMA journal_mode = PERSIST;
24335653e4daSdan      INSERT INTO t1 VALUES('c', 'd');
24345653e4daSdan    }
24355653e4daSdan  } {persist}
24365653e4daSdan  do_test pager1-28.$tn.6 { file exists test.db-journal } 1
24375653e4daSdan  do_test pager1-28.$tn.7 {
24385653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
24395653e4daSdan  } {}
24405653e4daSdan  do_test pager1-28.$tn.8  { file exists test.db-journal } 1
24415653e4daSdan  do_test pager1-28.$tn.9  { sql1 { PRAGMA journal_mode = DELETE } } delete
24425653e4daSdan  do_test pager1-28.$tn.10 { file exists test.db-journal } 1
24435653e4daSdan
24445653e4daSdan  do_test pager1-28.$tn.11 { sql2 COMMIT } {}
24455653e4daSdan  do_test pager1-28.$tn.12 { file exists test.db-journal } 0
24465653e4daSdan
24475653e4daSdan  do_test pager1-28-$tn.13 {
24485653e4daSdan    code1 { set channel [db incrblob -readonly t1 a 2] }
24495653e4daSdan    sql1 {
24505653e4daSdan      PRAGMA journal_mode = PERSIST;
24515653e4daSdan      INSERT INTO t1 VALUES('g', 'h');
24525653e4daSdan    }
24535653e4daSdan  } {persist}
24545653e4daSdan  do_test pager1-28.$tn.14 { file exists test.db-journal } 1
24555653e4daSdan  do_test pager1-28.$tn.15 {
24565653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
24575653e4daSdan  } {}
24585653e4daSdan  do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
24595653e4daSdan  do_test pager1-28.$tn.17 { file exists test.db-journal } 1
24605653e4daSdan
24615653e4daSdan  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
24625653e4daSdan  do_test pager1-28-$tn.18 { code1 { read $channel } } c
24635653e4daSdan  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
24645653e4daSdan  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
24655653e4daSdan}
24665653e4daSdan
24671879b088Sdando_test pager1-29.1 {
24681879b088Sdan  faultsim_delete_and_reopen
24691879b088Sdan  execsql {
24701879b088Sdan    PRAGMA page_size = 1024;
24711879b088Sdan    PRAGMA auto_vacuum = full;
24721879b088Sdan    PRAGMA locking_mode=exclusive;
24731879b088Sdan    CREATE TABLE t1(a, b);
24741879b088Sdan    INSERT INTO t1 VALUES(1, 2);
24751879b088Sdan  }
24761879b088Sdan  file size test.db
24771879b088Sdan} [expr 1024*3]
24784a8a6467Sdrhif {[nonzero_reserved_bytes]} {
24794a8a6467Sdrh  # VACUUM with size changes is not possible with the codec.
24804a8a6467Sdrh  do_test pager1-29.2 {
24814a8a6467Sdrh    catchsql {
24824a8a6467Sdrh      PRAGMA page_size = 4096;
24834a8a6467Sdrh      VACUUM;
24844a8a6467Sdrh    }
24854a8a6467Sdrh  } {1 {attempt to write a readonly database}}
24864a8a6467Sdrh} else {
24871879b088Sdan  do_test pager1-29.2 {
24881879b088Sdan    execsql {
24891879b088Sdan      PRAGMA page_size = 4096;
24901879b088Sdan      VACUUM;
24911879b088Sdan    }
24921879b088Sdan    file size test.db
24931879b088Sdan  } [expr 4096*3]
24944a8a6467Sdrh}
24951879b088Sdan
2496e08c2066Sdan#-------------------------------------------------------------------------
2497e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in
2498e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system
2499e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while
2500e08c2066Sdan# doing this is not released.
2501e08c2066Sdan#
2502e08c2066Sdando_test pager1-30.1 {
2503e08c2066Sdan  db close
2504fda06befSmistachkin  delete_file test.db
2505fda06befSmistachkin  delete_file test.db-journal
2506e08c2066Sdan  set fd [open test.db-journal w]
2507e08c2066Sdan  seek $fd [expr 512+1032*2]
2508e08c2066Sdan  puts -nonewline $fd x
2509e08c2066Sdan  close $fd
2510e08c2066Sdan
2511e08c2066Sdan  sqlite3 db test.db
2512e08c2066Sdan  execsql {
2513e08c2066Sdan    PRAGMA locking_mode=EXCLUSIVE;
2514e08c2066Sdan    SELECT count(*) FROM sqlite_master;
2515e08c2066Sdan    PRAGMA lock_status;
2516e08c2066Sdan  }
2517e08c2066Sdan} {exclusive 0 main reserved temp closed}
2518e08c2066Sdan
2519e08c2066Sdan#-------------------------------------------------------------------------
2520e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal
2521e08c2066Sdan# file can still be rolled back. This is required for backward compatibility -
2522e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero.
2523e08c2066Sdan#
252433f5379cSdanif {$tcl_platform(platform)=="unix"} {
2525e08c2066Sdando_test pager1-31.1 {
2526e08c2066Sdan  faultsim_delete_and_reopen
2527e08c2066Sdan  execsql {
2528e08c2066Sdan    PRAGMA cache_size = 10;
2529e08c2066Sdan    PRAGMA page_size = 1024;
2530e08c2066Sdan    CREATE TABLE t1(x, y, UNIQUE(x, y));
2531e08c2066Sdan    INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
2532e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2533e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2534e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2535e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2536e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2537e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2538e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2539e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2540e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2541e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2542e08c2066Sdan    BEGIN;
2543e08c2066Sdan      UPDATE t1 SET y = randomblob(1499);
2544e08c2066Sdan  }
2545fda06befSmistachkin  copy_file test.db test.db2
2546fda06befSmistachkin  copy_file test.db-journal test.db2-journal
2547e08c2066Sdan
2548e08c2066Sdan  hexio_write test.db2-journal 24 00000000
2549e08c2066Sdan  sqlite3 db2 test.db2
2550e08c2066Sdan  execsql { PRAGMA integrity_check } db2
2551e08c2066Sdan} {ok}
255233f5379cSdan}
2553e08c2066Sdan
255431e80976Sdrh#-------------------------------------------------------------------------
255531e80976Sdrh# Test that a database file can be "pre-hinted" to a certain size and that
255631e80976Sdrh# subsequent spilling of the pager cache does not result in the database
255731e80976Sdrh# file being shrunk.
255831e80976Sdrh#
255931e80976Sdrhcatch {db close}
256031e80976Sdrhforcedelete test.db
256131e80976Sdrh
256231e80976Sdrhdo_test pager1-32.1 {
256331e80976Sdrh  sqlite3 db test.db
256431e80976Sdrh  execsql {
256531e80976Sdrh    CREATE TABLE t1(x, y);
256631e80976Sdrh  }
256731e80976Sdrh  db close
256831e80976Sdrh  sqlite3 db test.db
256931e80976Sdrh  execsql {
257031e80976Sdrh    BEGIN;
257131e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
257231e80976Sdrh  }
25732f7820d8Sdrh  file_control_chunksize_test db main 1024
257431e80976Sdrh  file_control_sizehint_test db main 20971520; # 20MB
257531e80976Sdrh  execsql {
257631e80976Sdrh    PRAGMA cache_size = 10;
257731e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
257831e80976Sdrh    INSERT INTO t1 VALUES(2, randomblob(10000));
257931e80976Sdrh    INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
258031e80976Sdrh    INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
258131e80976Sdrh    INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
258231e80976Sdrh    INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
258331e80976Sdrh    SELECT count(*) FROM t1;
258431e80976Sdrh    COMMIT;
258531e80976Sdrh  }
258631e80976Sdrh  db close
258731e80976Sdrh  file size test.db
258831e80976Sdrh} {20971520}
258931e80976Sdrh
259031e80976Sdrh# Cleanup 20MB file left by the previous test.
259131e80976Sdrhforcedelete test.db
25925653e4daSdan
25939fc5b4a5Sdan#-------------------------------------------------------------------------
25949fc5b4a5Sdan# Test that if a transaction is committed in journal_mode=DELETE mode,
25959fc5b4a5Sdan# and the call to unlink() returns an ENOENT error, the COMMIT does not
25969fc5b4a5Sdan# succeed.
25979fc5b4a5Sdan#
25989fc5b4a5Sdanif {$::tcl_platform(platform)=="unix"} {
25999fc5b4a5Sdan  do_test pager1-33.1 {
26009fc5b4a5Sdan    sqlite3 db test.db
26019fc5b4a5Sdan    execsql {
26029fc5b4a5Sdan      CREATE TABLE t1(x);
26039fc5b4a5Sdan      INSERT INTO t1 VALUES('one');
26049fc5b4a5Sdan      INSERT INTO t1 VALUES('two');
26059fc5b4a5Sdan      BEGIN;
26069fc5b4a5Sdan        INSERT INTO t1 VALUES('three');
26079fc5b4a5Sdan        INSERT INTO t1 VALUES('four');
26089fc5b4a5Sdan    }
26099fc5b4a5Sdan    forcedelete bak-journal
26109fc5b4a5Sdan    file rename test.db-journal bak-journal
26119fc5b4a5Sdan
26129fc5b4a5Sdan    catchsql COMMIT
26139fc5b4a5Sdan  } {1 {disk I/O error}}
26149fc5b4a5Sdan
26159fc5b4a5Sdan  do_test pager1-33.2 {
26169fc5b4a5Sdan    file rename bak-journal test.db-journal
26179fc5b4a5Sdan    execsql { SELECT * FROM t1 }
26189fc5b4a5Sdan  } {one two}
26199fc5b4a5Sdan}
26209fc5b4a5Sdan
2621d7a558a9Sdan#-------------------------------------------------------------------------
2622d7a558a9Sdan# Test that appending pages to the database file then moving those pages
2623d7a558a9Sdan# to the free-list before the transaction is committed does not cause
2624d7a558a9Sdan# an error.
2625d7a558a9Sdan#
2626d7a558a9Sdanforeach {tn pragma strsize} {
26279b4c59faSdrh  1 { PRAGMA mmap_size = 0 } 2400
2628d7a558a9Sdan  2 { }                       2400
26299b4c59faSdrh  3 { PRAGMA mmap_size = 0 } 4400
2630d7a558a9Sdan  4 { }                       4400
2631d7a558a9Sdan} {
2632d7a558a9Sdan  reset_db
2633d7a558a9Sdan  db func a_string a_string
2634d7a558a9Sdan  db eval $pragma
2635d7a558a9Sdan  do_execsql_test 34.$tn.1 {
2636d7a558a9Sdan    CREATE TABLE t1(a, b);
2637d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2638d7a558a9Sdan  }
2639d7a558a9Sdan  do_execsql_test 34.$tn.2 {
2640d7a558a9Sdan    BEGIN;
2641d7a558a9Sdan    INSERT INTO t1 VALUES(2, a_string($strsize));
2642d7a558a9Sdan    DELETE FROM t1 WHERE oid=2;
2643d7a558a9Sdan    COMMIT;
2644d7a558a9Sdan    PRAGMA integrity_check;
2645d7a558a9Sdan  } {ok}
2646d7a558a9Sdan}
2647d7a558a9Sdan
2648d7a558a9Sdan#-------------------------------------------------------------------------
2649d7a558a9Sdan#
2650d7a558a9Sdanreset_db
2651d7a558a9Sdando_test 35 {
2652d7a558a9Sdan  sqlite3 db test.db
2653d7a558a9Sdan
2654d7a558a9Sdan  execsql {
2655d7a558a9Sdan    CREATE TABLE t1(x, y);
2656d7a558a9Sdan    PRAGMA journal_mode = WAL;
2657d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2658d7a558a9Sdan  }
2659d7a558a9Sdan
2660d7a558a9Sdan  execsql {
2661d7a558a9Sdan    BEGIN;
2662d7a558a9Sdan      CREATE TABLE t2(a, b);
2663d7a558a9Sdan  }
2664d7a558a9Sdan
2665d7a558a9Sdan  hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192]
2666d7a558a9Sdan  catchsql ROLLBACK
2667d7a558a9Sdan} {0 {}}
2668d7a558a9Sdan
2669d7a558a9Sdando_multiclient_test tn {
2670d7a558a9Sdan  sql1 {
2671d7a558a9Sdan    PRAGMA auto_vacuum = 0;
2672d7a558a9Sdan    CREATE TABLE t1(x, y);
2673d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2674d7a558a9Sdan  }
2675d7a558a9Sdan
2676d7a558a9Sdan  do_test 36.$tn.1 {
2677d7a558a9Sdan    sql2 { PRAGMA max_page_count = 2 }
2678d7a558a9Sdan    list [catch { sql2 { CREATE TABLE t2(x) } } msg] $msg
2679d7a558a9Sdan  } {1 {database or disk is full}}
2680d7a558a9Sdan
2681d7a558a9Sdan  sql1 { PRAGMA checkpoint_fullfsync = 1 }
2682d7a558a9Sdan  sql1 { CREATE TABLE t2(x) }
2683d7a558a9Sdan
2684d7a558a9Sdan  do_test 36.$tn.2 {
2685d7a558a9Sdan    sql2 { INSERT INTO t2 VALUES('xyz') }
2686d7a558a9Sdan    list [catch { sql2 { CREATE TABLE t3(x) } } msg] $msg
2687d7a558a9Sdan  } {1 {database or disk is full}}
2688d7a558a9Sdan}
2689d7a558a9Sdan
2690d7a558a9Sdanforcedelete test1 test2
2691d7a558a9Sdanforeach {tn uri} {
2692d7a558a9Sdan  1   {file:?mode=memory&cache=shared}
2693d7a558a9Sdan  2   {file:one?mode=memory&cache=shared}
2694d7a558a9Sdan  3   {file:test1?cache=shared}
2695d7a558a9Sdan  4   {file:test2?another=parameter&yet=anotherone}
2696d7a558a9Sdan} {
2697d7a558a9Sdan  do_test 37.$tn {
2698d7a558a9Sdan    catch { db close }
2699d7a558a9Sdan    sqlite3_shutdown
2700d7a558a9Sdan    sqlite3_config_uri 1
2701d7a558a9Sdan    sqlite3 db $uri
2702abd6d84aSdan
2703d7a558a9Sdan    db eval {
2704d7a558a9Sdan      CREATE TABLE t1(x);
2705d7a558a9Sdan      INSERT INTO t1 VALUES(1);
2706d7a558a9Sdan      SELECT * FROM t1;
2707d7a558a9Sdan    }
2708d7a558a9Sdan  } {1}
2709abd6d84aSdan
2710abd6d84aSdan  do_execsql_test 37.$tn.2 {
2711abd6d84aSdan    VACUUM;
2712abd6d84aSdan    SELECT * FROM t1;
2713abd6d84aSdan  } {1}
2714abd6d84aSdan
2715d7a558a9Sdan  db close
2716d7a558a9Sdan  sqlite3_shutdown
2717d7a558a9Sdan  sqlite3_config_uri 0
2718d7a558a9Sdan}
2719d7a558a9Sdan
2720d7a558a9Sdando_test 38.1 {
2721d7a558a9Sdan  catch { db close }
2722d7a558a9Sdan  forcedelete test.db
2723d7a558a9Sdan  set fd [open test.db w]
2724d7a558a9Sdan  puts $fd "hello world"
2725d7a558a9Sdan  close $fd
2726d7a558a9Sdan  sqlite3 db test.db
2727d7a558a9Sdan  catchsql { CREATE TABLE t1(x) }
2728ff4fa772Sdrh} {1 {file is not a database}}
2729d7a558a9Sdando_test 38.2 {
2730d7a558a9Sdan  catch { db close }
2731d7a558a9Sdan  forcedelete test.db
2732d7a558a9Sdan} {}
2733d7a558a9Sdan
2734d7a558a9Sdando_test 39.1 {
2735d7a558a9Sdan  sqlite3 db test.db
2736d7a558a9Sdan  execsql {
2737d7a558a9Sdan    PRAGMA auto_vacuum = 1;
2738d7a558a9Sdan    CREATE TABLE t1(x);
2739d7a558a9Sdan    INSERT INTO t1 VALUES('xxx');
2740d7a558a9Sdan    INSERT INTO t1 VALUES('two');
2741d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2742d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2743d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2744d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2745d7a558a9Sdan    BEGIN;
2746d7a558a9Sdan    UPDATE t1 SET x = 'one' WHERE rowid=1;
2747d7a558a9Sdan  }
2748d7a558a9Sdan  set ::stmt [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
2749d7a558a9Sdan  sqlite3_step $::stmt
2750d7a558a9Sdan  sqlite3_column_text $::stmt 0
2751d7a558a9Sdan} {one}
2752d7a558a9Sdando_test 39.2 {
2753d7a558a9Sdan  execsql { CREATE TABLE t2(x) }
2754d7a558a9Sdan  sqlite3_step $::stmt
2755d7a558a9Sdan  sqlite3_column_text $::stmt 0
2756d7a558a9Sdan} {two}
2757d7a558a9Sdando_test 39.3 {
2758d7a558a9Sdan  sqlite3_finalize $::stmt
2759d7a558a9Sdan  execsql COMMIT
2760d7a558a9Sdan} {}
2761d7a558a9Sdan
2762d7a558a9Sdando_execsql_test 39.4 {
2763d7a558a9Sdan  PRAGMA auto_vacuum = 2;
2764d7a558a9Sdan  CREATE TABLE t3(x);
2765d7a558a9Sdan  CREATE TABLE t4(x);
2766d7a558a9Sdan
2767d7a558a9Sdan  DROP TABLE t2;
2768d7a558a9Sdan  DROP TABLE t3;
2769d7a558a9Sdan  DROP TABLE t4;
2770d7a558a9Sdan}
2771d7a558a9Sdando_test 39.5 {
2772d7a558a9Sdan  db close
2773d7a558a9Sdan  sqlite3 db test.db
2774d7a558a9Sdan  execsql {
2775d7a558a9Sdan    PRAGMA cache_size = 1;
2776d7a558a9Sdan    PRAGMA incremental_vacuum;
2777d7a558a9Sdan    PRAGMA integrity_check;
2778d7a558a9Sdan  }
2779d7a558a9Sdan} {ok}
2780d7a558a9Sdan
2781d7a558a9Sdando_test 40.1 {
2782d7a558a9Sdan  reset_db
2783d7a558a9Sdan  execsql {
2784d7a558a9Sdan    PRAGMA auto_vacuum = 1;
2785d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
2786d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2787d7a558a9Sdan    PRAGMA page_count;
2788d7a558a9Sdan  }
2789d7a558a9Sdan} {6}
2790d7a558a9Sdando_test 40.2 {
2791d7a558a9Sdan  execsql {
2792d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2793d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2794d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2795d7a558a9Sdan  }
2796d7a558a9Sdan} {}
2797d7a558a9Sdando_test 40.3 {
2798d7a558a9Sdan  db close
2799d7a558a9Sdan  sqlite3 db test.db
2800d7a558a9Sdan  execsql {
2801d7a558a9Sdan    PRAGMA cache_size = 1;
2802d7a558a9Sdan    CREATE TABLE t2(x);
2803d7a558a9Sdan    PRAGMA integrity_check;
2804d7a558a9Sdan  }
2805d7a558a9Sdan} {ok}
2806d7a558a9Sdan
2807d7a558a9Sdando_test 41.1 {
2808d7a558a9Sdan  reset_db
2809d7a558a9Sdan  execsql {
2810d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
2811d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(200));
2812d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2813d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2814d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2815d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2816d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2817d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2818d7a558a9Sdan  }
2819d7a558a9Sdan} {}
2820d7a558a9Sdando_test 41.2 {
2821d7a558a9Sdan  testvfs tv -default 1
2822d7a558a9Sdan  tv sectorsize 16384;
2823d7a558a9Sdan  tv devchar [list]
2824d7a558a9Sdan  db close
2825d7a558a9Sdan  sqlite3 db test.db
2826d7a558a9Sdan  execsql {
2827d7a558a9Sdan    PRAGMA cache_size = 1;
2828d7a558a9Sdan    DELETE FROM t1 WHERE rowid%4;
2829d7a558a9Sdan    PRAGMA integrity_check;
2830d7a558a9Sdan  }
2831d7a558a9Sdan} {ok}
2832abd6d84aSdandb close
2833abd6d84aSdantv delete
2834d7a558a9Sdan
2835abd6d84aSdanset pending_prev [sqlite3_test_control_pending_byte 0x1000000]
2836abd6d84aSdando_test 42.1 {
2837abd6d84aSdan  reset_db
2838abd6d84aSdan  execsql {
2839abd6d84aSdan    CREATE TABLE t1(x, y);
2840abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
2841abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2842abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2843abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2844abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2845abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2846abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2847abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2848abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2849abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2850abd6d84aSdan  }
2851abd6d84aSdan  db close
2852abd6d84aSdan  sqlite3_test_control_pending_byte 0x0010000
2853abd6d84aSdan  sqlite3 db test.db
28549b4c59faSdrh  db eval { PRAGMA mmap_size = 0 }
2855abd6d84aSdan  catchsql { SELECT sum(length(y)) FROM t1 }
2856abd6d84aSdan} {1 {database disk image is malformed}}
2857abd6d84aSdando_test 42.2 {
2858abd6d84aSdan  reset_db
2859abd6d84aSdan  execsql {
2860abd6d84aSdan    CREATE TABLE t1(x, y);
2861abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
2862abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2863abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2864abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2865abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2866abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2867abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2868abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2869abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2870abd6d84aSdan  }
2871abd6d84aSdan  db close
2872abd6d84aSdan
2873abd6d84aSdan  testvfs tv -default 1
2874abd6d84aSdan  tv sectorsize 16384;
2875abd6d84aSdan  tv devchar [list]
2876abd6d84aSdan  sqlite3 db test.db -vfs tv
2877abd6d84aSdan  execsql { UPDATE t1 SET x = randomblob(200) }
2878abd6d84aSdan} {}
2879abd6d84aSdandb close
2880abd6d84aSdantv delete
2881abd6d84aSdansqlite3_test_control_pending_byte $pending_prev
2882abd6d84aSdan
2883abd6d84aSdando_test 43.1 {
2884abd6d84aSdan  reset_db
2885abd6d84aSdan  execsql {
2886abd6d84aSdan    CREATE TABLE t1(x, y);
2887abd6d84aSdan    INSERT INTO t1 VALUES(1, 2);
2888abd6d84aSdan    CREATE TABLE t2(x, y);
2889abd6d84aSdan    INSERT INTO t2 VALUES(1, 2);
2890abd6d84aSdan    CREATE TABLE t3(x, y);
2891abd6d84aSdan    INSERT INTO t3 VALUES(1, 2);
2892abd6d84aSdan  }
2893abd6d84aSdan  db close
2894abd6d84aSdan  sqlite3 db test.db
2895abd6d84aSdan
28969b4c59faSdrh  db eval { PRAGMA mmap_size = 0 }
2897abd6d84aSdan  db eval { SELECT * FROM t1 }
2898abd6d84aSdan  sqlite3_db_status db CACHE_MISS 0
2899abd6d84aSdan} {0 2 0}
2900abd6d84aSdan
2901abd6d84aSdando_test 43.2 {
2902abd6d84aSdan  db eval { SELECT * FROM t2 }
2903abd6d84aSdan  sqlite3_db_status db CACHE_MISS 1
2904abd6d84aSdan} {0 3 0}
2905abd6d84aSdan
2906abd6d84aSdando_test 43.3 {
2907abd6d84aSdan  db eval { SELECT * FROM t3 }
2908abd6d84aSdan  sqlite3_db_status db CACHE_MISS 0
2909abd6d84aSdan} {0 1 0}
2910d7a558a9Sdan
2911d353331aSdanfinish_test
2912