xref: /sqlite-3.40.0/test/pager1.test (revision 7f9026dd)
1e91a54e1Sdan# 2010 June 15
2e91a54e1Sdan#
3e91a54e1Sdan# The author disclaims copyright to this source code.  In place of
4e91a54e1Sdan# a legal notice, here is a blessing:
5e91a54e1Sdan#
6e91a54e1Sdan#    May you do good and not evil.
7e91a54e1Sdan#    May you find forgiveness for yourself and forgive others.
8e91a54e1Sdan#    May you share freely, never taking more than you give.
9e91a54e1Sdan#
10e91a54e1Sdan#***********************************************************************
11e91a54e1Sdan#
12e91a54e1Sdan
13e91a54e1Sdanset testdir [file dirname $argv0]
14e91a54e1Sdansource $testdir/tester.tcl
15e91a54e1Sdansource $testdir/lock_common.tcl
16e91a54e1Sdansource $testdir/malloc_common.tcl
17153eda0aSdansource $testdir/wal_common.tcl
1868928b6cSdan
1968928b6cSdan# Do not use a codec for tests in this file, as the database file is
2068928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command).
2168928b6cSdan#
2268928b6cSdando_not_use_codec
23e91a54e1Sdan
24b0ac3e3aSdan#
25b0ac3e3aSdan# pager1-1.*: Test inter-process locking (clients in multiple processes).
26b0ac3e3aSdan#
27b0ac3e3aSdan# pager1-2.*: Test intra-process locking (multiple clients in this process).
28b0ac3e3aSdan#
29b0ac3e3aSdan# pager1-3.*: Savepoint related tests.
30b0ac3e3aSdan#
311f4cb65aSdan# pager1-4.*: Hot-journal related tests.
321f4cb65aSdan#
33de4996e2Sdan# pager1-5.*: Cases related to multi-file commits.
34de4996e2Sdan#
35146ed78bSdan# pager1-6.*: Cases related to "PRAGMA max_page_count"
36146ed78bSdan#
37153eda0aSdan# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
38153eda0aSdan#
390e986f51Sdan# pager1-8.*: Cases using temporary and in-memory databases.
400e986f51Sdan#
41dca321aeSdan# pager1-9.*: Tests related to the backup API.
42dca321aeSdan#
43ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to
44ec6ffc1aSdan#              64KB.
45ec6ffc1aSdan#
46d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size"
47d353331aSdan#
48d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST"
49d353331aSdan#
50d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF"
51ec6ffc1aSdan#
52c8ce3972Sdan# pager1-15.*: Varying sqlite3_vfs.szOsFile
53c8ce3972Sdan#
54c8ce3972Sdan# pager1-16.*: Varying sqlite3_vfs.mxPathname
55c8ce3972Sdan#
56c8ce3972Sdan# pager1-17.*: Tests related to "PRAGMA omit_readlock"
57c8ce3972Sdan#
58c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree
59c8ce3972Sdan#              requests an invalid page number (due to db corruption).
60c8ce3972Sdan#
61b0ac3e3aSdan
62c396d4afSdanproc recursive_select {id table {script {}}} {
63c396d4afSdan  set cnt 0
64c396d4afSdan  db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
65c396d4afSdan    recursive_select $rowid $table $script
66c396d4afSdan    incr cnt
67c396d4afSdan  }
68c396d4afSdan  if {$cnt==0} { eval $script }
69c396d4afSdan}
70c396d4afSdan
7153f04f3bSdanset a_string_counter 1
7253f04f3bSdanproc a_string {n} {
7353f04f3bSdan  global a_string_counter
7453f04f3bSdan  incr a_string_counter
7553f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
7653f04f3bSdan}
7753f04f3bSdandb func a_string a_string
7853f04f3bSdan
79a4a9095eSdando_multiclient_test tn {
80e91a54e1Sdan
81e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
82e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
83e91a54e1Sdan  #
84e91a54e1Sdan  do_test pager1-$tn.1 {
85e91a54e1Sdan    sql1 {
86e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
87e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
88d353331aSdan      INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
89e91a54e1Sdan    }
90e91a54e1Sdan  } {}
91e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
92e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
93e91a54e1Sdan
94e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
95e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
96e91a54e1Sdan  # read the database content as it was before the transaction was
97e91a54e1Sdan  # opened. [db] should see the inserted row.
98e91a54e1Sdan  #
99e91a54e1Sdan  do_test pager1-$tn.4 {
100e91a54e1Sdan    sql1 {
101e91a54e1Sdan      BEGIN;
102e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
103e91a54e1Sdan    }
104e91a54e1Sdan  } {}
105e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
106e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
107e91a54e1Sdan
108e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
109e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
110e91a54e1Sdan  #
111e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
112e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
113e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
114e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
115e91a54e1Sdan  #
116e91a54e1Sdan  do_test pager1-$tn.8 {
117e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
118e91a54e1Sdan  } {1 {database is locked}}
119e91a54e1Sdan  do_test pager1-$tn.9 {
120e91a54e1Sdan    csql2 {
121e91a54e1Sdan      BEGIN;
122e91a54e1Sdan      UPDATE t1 SET a = a + 10;
123e91a54e1Sdan    }
124e91a54e1Sdan  } {1 {database is locked}}
125e91a54e1Sdan
126e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
127e91a54e1Sdan  # now see the new database content.
128e91a54e1Sdan  #
129e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
130e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
131e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
132e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
133e91a54e1Sdan
134e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
135e91a54e1Sdan  # after the attempt to write the database failed.
136e91a54e1Sdan  #
137e91a54e1Sdan  do_test pager1-$tn.14 {
138e91a54e1Sdan    csql2 { BEGIN }
139e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
140e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
141e91a54e1Sdan
142e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
143e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
144e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
145e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
146e91a54e1Sdan  #
147e91a54e1Sdan  do_test pager1-$tn.15 {
148e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
149e91a54e1Sdan  } {1 one 2 two 3 three}
150e91a54e1Sdan  do_test pager1-$tn.16 {
151e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
152e91a54e1Sdan  } {1 {database is locked}}
153e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
154e91a54e1Sdan
155e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
156e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
157e91a54e1Sdan  # the SHARED lock [db2] is holding.
158e91a54e1Sdan  #
159e91a54e1Sdan  do_test pager1-$tn.18 {
160e91a54e1Sdan    sql1 {
161e91a54e1Sdan      BEGIN;
162e91a54e1Sdan      UPDATE t1 SET a = a + 10;
163e91a54e1Sdan    }
164e91a54e1Sdan  } {}
165e91a54e1Sdan  do_test pager1-$tn-19 {
166e91a54e1Sdan    sql1 { PRAGMA lock_status }
167e91a54e1Sdan  } {main reserved temp closed}
168e91a54e1Sdan  do_test pager1-$tn-20 {
169e91a54e1Sdan    sql2 { PRAGMA lock_status }
170e91a54e1Sdan  } {main shared temp closed}
171e91a54e1Sdan
172e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
173e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
174e91a54e1Sdan  #
175e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
176e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
177e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
178e91a54e1Sdan
179e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
180e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
181e91a54e1Sdan  # upgrades to a PENDING lock.
182e91a54e1Sdan  #
183e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
184e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
185e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
186e91a54e1Sdan  # the database.
187e91a54e1Sdan  #
188e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
189e91a54e1Sdan  do_test pager1-$tn-25 {
190e91a54e1Sdan    sql1 { PRAGMA lock_status }
191e91a54e1Sdan  } {main pending temp closed}
192e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
193e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
194e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
195e91a54e1Sdan
196e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
197e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
198e91a54e1Sdan  # is still holding a PENDING).
199e91a54e1Sdan  #
200e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
201e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
202e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
203e91a54e1Sdan
204e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
205e91a54e1Sdan  # committed, all three connections can read the new content.
206e91a54e1Sdan  #
207e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
208e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
209e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
210e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
211e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
212d353331aSdan
213d353331aSdan  # Install a busy-handler for connection [db].
214d353331aSdan  #
215d353331aSdan  set ::nbusy [list]
216d353331aSdan  proc busy {n} {
217d353331aSdan    lappend ::nbusy $n
218d353331aSdan    if {$n>5} { sql2 COMMIT }
219d353331aSdan    return 0
220d353331aSdan  }
221d353331aSdan  db busy busy
222d353331aSdan
223d353331aSdan  do_test pager1-$tn.29 {
224d353331aSdan    sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
225d353331aSdan  } {}
226d353331aSdan  do_test pager1-$tn.30 {
227d353331aSdan    sql2 { BEGIN ; SELECT * FROM t1 }
228d353331aSdan  } {21 one 22 two 23 three}
229d353331aSdan  do_test pager1-$tn.31 { sql1 COMMIT } {}
230d353331aSdan  do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
231e91a54e1Sdan}
232e91a54e1Sdan
23353f04f3bSdan#-------------------------------------------------------------------------
23453f04f3bSdan# Savepoint related test cases.
23553f04f3bSdan#
236dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
237dca321aeSdan#                 to grow.
238dca321aeSdan#
239273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
240273f3f0dSdan#                 of a savepoint rollback.
241273f3f0dSdan#
2420e986f51Sdando_test pager1-3.1.1 {
243b0ac3e3aSdan  faultsim_delete_and_reopen
244b0ac3e3aSdan  execsql {
245b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
246b0ac3e3aSdan    CREATE TABLE counter(
247b0ac3e3aSdan      i CHECK (i<5),
248b0ac3e3aSdan      u CHECK (u<10)
249b0ac3e3aSdan    );
250b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
251b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
252b0ac3e3aSdan      UPDATE counter SET i = i+1;
253b0ac3e3aSdan    END;
254b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
255b0ac3e3aSdan      UPDATE counter SET u = u+1;
256b0ac3e3aSdan    END;
257b0ac3e3aSdan  }
258b0ac3e3aSdan  execsql { SELECT * FROM counter }
259b0ac3e3aSdan} {0 0}
260b0ac3e3aSdan
2610e986f51Sdando_execsql_test pager1-3.1.2 {
262d353331aSdan  PRAGMA cache_size = 10;
263b0ac3e3aSdan  BEGIN;
264b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
265b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
266b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
267b0ac3e3aSdan    SELECT * FROM counter;
268b0ac3e3aSdan} {3 0}
2690e986f51Sdando_catchsql_test pager1-3.1.3 {
270b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
271b0ac3e3aSdan} {1 {constraint failed}}
272b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
273b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
274b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
275b0ac3e3aSdan
276273f3f0dSdanforeach {tn sql tcl} {
277d353331aSdan  7  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
278273f3f0dSdan    testvfs tv -default 1
279273f3f0dSdan    tv devchar safe_append
280273f3f0dSdan  }
281d353331aSdan  8  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
282d353331aSdan    testvfs tv -default 1
283d353331aSdan    tv devchar sequential
284d353331aSdan  }
285d353331aSdan  9  { PRAGMA synchronous = FULL } { }
286d353331aSdan  10 { PRAGMA synchronous = NORMAL } { }
287d353331aSdan  11 { PRAGMA synchronous = OFF } { }
288d353331aSdan  12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
289d353331aSdan  13 { PRAGMA synchronous = FULL } {
290d353331aSdan    testvfs tv -default 1
291d353331aSdan    tv devchar sequential
292d353331aSdan  }
2936b63ab47Sdan  14 { PRAGMA locking_mode = EXCLUSIVE } {
2946b63ab47Sdan  }
295273f3f0dSdan} {
296273f3f0dSdan  do_test pager1-3.$tn.1 {
297273f3f0dSdan    eval $tcl
298dca321aeSdan    faultsim_delete_and_reopen
299dca321aeSdan    db func a_string a_string
300273f3f0dSdan    execsql $sql
301dca321aeSdan    execsql {
302dca321aeSdan      PRAGMA auto_vacuum = 2;
303dca321aeSdan      PRAGMA cache_size = 10;
304dca321aeSdan      CREATE TABLE z(x INTEGER PRIMARY KEY, y);
305dca321aeSdan      BEGIN;
306dca321aeSdan        INSERT INTO z VALUES(NULL, a_string(800));
307dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
308dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
309dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
310dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
311dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
312dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
313dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
314dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
315dca321aeSdan      COMMIT;
316dca321aeSdan    }
317dca321aeSdan    execsql { PRAGMA auto_vacuum }
318dca321aeSdan  } {2}
319273f3f0dSdan  do_execsql_test pager1-3.$tn.2 {
320dca321aeSdan    BEGIN;
321dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
322dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
323dca321aeSdan      SAVEPOINT one;
324273f3f0dSdan        UPDATE z SET y = NULL WHERE x>256;
325dca321aeSdan        PRAGMA incremental_vacuum;
326dca321aeSdan        SELECT count(*) FROM z WHERE x < 100;
327dca321aeSdan      ROLLBACK TO one;
328dca321aeSdan    COMMIT;
329dca321aeSdan  } {99}
330dca321aeSdan
331273f3f0dSdan  do_execsql_test pager1-3.$tn.3 {
332273f3f0dSdan    BEGIN;
333273f3f0dSdan      SAVEPOINT one;
334273f3f0dSdan        UPDATE z SET y = y||x;
335273f3f0dSdan      ROLLBACK TO one;
336273f3f0dSdan    COMMIT;
337273f3f0dSdan    SELECT count(*) FROM z;
338273f3f0dSdan  } {258}
339273f3f0dSdan
340273f3f0dSdan  do_execsql_test pager1-3.$tn.4 {
341273f3f0dSdan    SAVEPOINT one;
342273f3f0dSdan      UPDATE z SET y = y||x;
343273f3f0dSdan    ROLLBACK TO one;
344273f3f0dSdan  } {}
345273f3f0dSdan  do_execsql_test pager1-3.$tn.5 {
346273f3f0dSdan    SELECT count(*) FROM z;
347273f3f0dSdan    RELEASE one;
348273f3f0dSdan    PRAGMA integrity_check;
349273f3f0dSdan  } {258 ok}
350273f3f0dSdan
35178f1e538Sdan  do_execsql_test pager1-3.$tn.6 {
35278f1e538Sdan    SAVEPOINT one;
35378f1e538Sdan    RELEASE one;
35478f1e538Sdan  } {}
35578f1e538Sdan
356273f3f0dSdan  db close
357273f3f0dSdan  catch { tv delete }
358273f3f0dSdan}
359273f3f0dSdan
36053f04f3bSdan#-------------------------------------------------------------------------
36153f04f3bSdan# Hot journal rollback related test cases.
36253f04f3bSdan#
36353f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
36453f04f3bSdan#               journal files.
36553f04f3bSdan#
36653f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
36753f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
36853f04f3bSdan#               compute) the associated journal is rolled back (and no
36953f04f3bSdan#               xAccess() call to check for the presence of any master
37053f04f3bSdan#               journal file is made).
37153f04f3bSdan#
372de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
373de4996e2Sdan#               page-size or sector-size in the journal header appear to
374de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
375de4996e2Sdan#
376e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
377e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
378e08341c6Sdan#               modes.
379e08341c6Sdan#
380e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
381e08341c6Sdan#               journal-record for which the checksum fails.
382e08341c6Sdan#
383ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
384ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
385ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
386ec6ffc1aSdan#
387c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can
388c8ce3972Sdan#               open it for reading only, the database cannot be accessed and
389c8ce3972Sdan#               SQLITE_CANTOPEN is returned.
390c8ce3972Sdan#
39153f04f3bSdando_test pager1.4.1.1 {
39253f04f3bSdan  faultsim_delete_and_reopen
39353f04f3bSdan  execsql {
39453f04f3bSdan    CREATE TABLE x(y, z);
39553f04f3bSdan    INSERT INTO x VALUES(1, 2);
39653f04f3bSdan  }
39753f04f3bSdan  set fd [open test.db-journal w]
39853f04f3bSdan  puts -nonewline $fd "helloworld"
39953f04f3bSdan  close $fd
40053f04f3bSdan  file exists test.db-journal
40153f04f3bSdan} {1}
40253f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
40353f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
40453f04f3bSdan
40553f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
40653f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
40753f04f3bSdan#
40853f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
40953f04f3bSdan# up the file system to contain two databases, two hot-journal files and
41053f04f3bSdan# a master-journal.
41153f04f3bSdan#
41253f04f3bSdando_test pager1.4.2.1 {
41353f04f3bSdan  testvfs tstvfs -default 1
41453f04f3bSdan  tstvfs filter xDelete
41553f04f3bSdan  tstvfs script xDeleteCallback
41653f04f3bSdan  proc xDeleteCallback {method file args} {
41753f04f3bSdan    set file [file tail $file]
41853f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
41953f04f3bSdan  }
42053f04f3bSdan  faultsim_delete_and_reopen
42153f04f3bSdan  db func a_string a_string
42253f04f3bSdan  execsql {
42353f04f3bSdan    ATTACH 'test.db2' AS aux;
42453f04f3bSdan    PRAGMA journal_mode = DELETE;
42553f04f3bSdan    PRAGMA main.cache_size = 10;
42653f04f3bSdan    PRAGMA aux.cache_size = 10;
42753f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
42853f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
42953f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
43053f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43153f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43253f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
43353f04f3bSdan    BEGIN;
43453f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
43553f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
43653f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
43753f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
43853f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
43953f04f3bSdan    COMMIT;
44053f04f3bSdan  }
44153f04f3bSdan  db close
44253f04f3bSdan  tstvfs delete
44353f04f3bSdan} {}
444b2f20bfcSshaneh
445b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
44653f04f3bSdando_test pager1.4.2.2 {
44753f04f3bSdan  faultsim_restore_and_reopen
44853f04f3bSdan  execsql {
44953f04f3bSdan    SELECT count(*) FROM t1;
45053f04f3bSdan    PRAGMA integrity_check;
45153f04f3bSdan  }
45253f04f3bSdan} {4 ok}
45353f04f3bSdando_test pager1.4.2.3 {
45453f04f3bSdan  faultsim_restore_and_reopen
455fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
45653f04f3bSdan  execsql {
45753f04f3bSdan    SELECT count(*) FROM t1;
45853f04f3bSdan    PRAGMA integrity_check;
45953f04f3bSdan  }
46053f04f3bSdan} {64 ok}
46153f04f3bSdando_test pager1.4.2.4 {
46253f04f3bSdan  faultsim_restore_and_reopen
46353f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
46453f04f3bSdan  execsql {
46553f04f3bSdan    SELECT count(*) FROM t1;
46653f04f3bSdan    PRAGMA integrity_check;
46753f04f3bSdan  }
46853f04f3bSdan} {4 ok}
46953f04f3bSdando_test pager1.4.2.5 {
47053f04f3bSdan  faultsim_restore_and_reopen
47153f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
472fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
47353f04f3bSdan  execsql {
47453f04f3bSdan    SELECT count(*) FROM t1;
47553f04f3bSdan    PRAGMA integrity_check;
47653f04f3bSdan  }
47753f04f3bSdan} {4 ok}
478b2f20bfcSshaneh}
47953f04f3bSdan
480de4996e2Sdando_test pager1.4.3.1 {
481de4996e2Sdan  testvfs tstvfs -default 1
482de4996e2Sdan  tstvfs filter xSync
483de4996e2Sdan  tstvfs script xSyncCallback
484de4996e2Sdan  proc xSyncCallback {method file args} {
485de4996e2Sdan    set file [file tail $file]
486de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
487de4996e2Sdan  }
488de4996e2Sdan  faultsim_delete_and_reopen
489de4996e2Sdan  execsql {
490de4996e2Sdan    PRAGMA journal_mode = DELETE;
491de4996e2Sdan    CREATE TABLE t1(a, b);
492de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
493de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
494de4996e2Sdan  }
495de4996e2Sdan  db close
496de4996e2Sdan  tstvfs delete
497de4996e2Sdan} {}
498de4996e2Sdan
499de4996e2Sdanforeach {tn ofst value result} {
500de4996e2Sdan          2   20    31       {1 2 3 4}
501de4996e2Sdan          3   20    32       {1 2 3 4}
502de4996e2Sdan          4   20    33       {1 2 3 4}
503de4996e2Sdan          5   20    65536    {1 2 3 4}
504de4996e2Sdan          6   20    131072   {1 2 3 4}
505de4996e2Sdan
506de4996e2Sdan          7   24    511      {1 2 3 4}
507de4996e2Sdan          8   24    513      {1 2 3 4}
508b2eced5dSdrh          9   24    131072   {1 2 3 4}
509de4996e2Sdan
510de4996e2Sdan         10   32    65536    {1 2}
511de4996e2Sdan} {
512de4996e2Sdan  do_test pager1.4.3.$tn {
513de4996e2Sdan    faultsim_restore_and_reopen
514de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
515de4996e2Sdan    execsql { SELECT * FROM t1 }
516de4996e2Sdan  } $result
517de4996e2Sdan}
518de4996e2Sdandb close
519de4996e2Sdan
520e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
521e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
522e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
523e08341c6Sdan# master journal file from the file-system.
524e08341c6Sdan#
525e08341c6Sdantestvfs tv -default 1
526e08341c6Sdantv script copy_on_mj_delete
527e08341c6Sdanset ::mj_filename_length 0
528e08341c6Sdanproc copy_on_mj_delete {method filename args} {
529e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
530e08341c6Sdan    set ::mj_filename_length [string length $filename]
531e08341c6Sdan    faultsim_save
532e08341c6Sdan  }
533e08341c6Sdan  return SQLITE_OK
534e08341c6Sdan}
535e08341c6Sdan
536e08341c6Sdanset pwd [pwd]
537e08341c6Sdanforeach {tn1 tcl} {
538e08341c6Sdan  1 { set prefix "test.db" }
539e08341c6Sdan  2 {
540e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
541e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
542e08341c6Sdan    # contains a master-journal pointer so large that it could contain
543e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
544e08341c6Sdan    # make sure SQLite doesn't get confused by this.
545e08341c6Sdan    #
546e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
54733d85c9cSshaneh    if {$tcl_platform(platform)=="windows"} {
54833d85c9cSshaneh      # TBD need to figure out how to do this correctly for Windows!!!
54933d85c9cSshaneh      set nPadding [expr 255 - $::mj_filename_length]
55033d85c9cSshaneh    }
551e08341c6Sdan
552e08341c6Sdan    # We cannot just create a really long database file name to open, as
553e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
554e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
555e08341c6Sdan    # hierarchy to work in.
556e08341c6Sdan    #
557e08341c6Sdan    set dirname "d123456789012345678901234567890/"
558e08341c6Sdan    set nDir [expr $nPadding / 32]
559e08341c6Sdan    if { $nDir } {
560e08341c6Sdan      set p [string repeat $dirname $nDir]
561e08341c6Sdan      file mkdir $p
562e08341c6Sdan      cd $p
563e08341c6Sdan    }
564e08341c6Sdan
565e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
566e08341c6Sdan    set prefix "test.db${padding}"
567e08341c6Sdan  }
568e08341c6Sdan} {
569e08341c6Sdan  eval $tcl
570e08341c6Sdan  foreach {tn2 sql} {
571e08341c6Sdan    o {
572e08341c6Sdan      PRAGMA main.synchronous=OFF;
573e08341c6Sdan      PRAGMA aux.synchronous=OFF;
5743f94b609Sdan      PRAGMA journal_mode = DELETE;
575e08341c6Sdan    }
576e08341c6Sdan    o512 {
577e08341c6Sdan      PRAGMA main.synchronous=OFF;
578e08341c6Sdan      PRAGMA aux.synchronous=OFF;
579e08341c6Sdan      PRAGMA main.page_size = 512;
580e08341c6Sdan      PRAGMA aux.page_size = 512;
5813f94b609Sdan      PRAGMA journal_mode = DELETE;
582e08341c6Sdan    }
583e08341c6Sdan    n {
584e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
585e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
5863f94b609Sdan      PRAGMA journal_mode = DELETE;
587e08341c6Sdan    }
588e08341c6Sdan    f {
589e08341c6Sdan      PRAGMA main.synchronous=FULL;
590e08341c6Sdan      PRAGMA aux.synchronous=FULL;
5913f94b609Sdan      PRAGMA journal_mode = DELETE;
592e08341c6Sdan    }
593e08341c6Sdan  } {
594e08341c6Sdan
595e08341c6Sdan    set tn "${tn1}.${tn2}"
596e08341c6Sdan
597e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
598e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
599e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
600e08341c6Sdan    # file is deleted to commit the transaction.
601e08341c6Sdan    #
602e08341c6Sdan    tv filter xDelete
603e08341c6Sdan    do_test pager1-4.4.$tn.1 {
604e08341c6Sdan      faultsim_delete_and_reopen $prefix
605e08341c6Sdan      execsql "
606e08341c6Sdan        ATTACH '${prefix}2' AS aux;
607e08341c6Sdan        $sql
608e08341c6Sdan        CREATE TABLE a(x);
609e08341c6Sdan        CREATE TABLE aux.b(x);
610e08341c6Sdan        INSERT INTO a VALUES('double-you');
611e08341c6Sdan        INSERT INTO a VALUES('why');
612e08341c6Sdan        INSERT INTO a VALUES('zed');
613e08341c6Sdan        INSERT INTO b VALUES('won');
614e08341c6Sdan        INSERT INTO b VALUES('too');
615e08341c6Sdan        INSERT INTO b VALUES('free');
616e08341c6Sdan      "
617e08341c6Sdan      execsql {
618e08341c6Sdan        BEGIN;
619e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
620e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
621e08341c6Sdan        COMMIT;
622e08341c6Sdan      }
623e08341c6Sdan    } {}
624e08341c6Sdan    tv filter {}
625e08341c6Sdan
626e08341c6Sdan    # Check that the transaction was committed successfully.
627e08341c6Sdan    #
628e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
629e08341c6Sdan      SELECT * FROM a
630e08341c6Sdan    } {double-you why zed won too free}
631e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
632e08341c6Sdan      SELECT * FROM b
633e08341c6Sdan    } {won too free double-you why zed}
634e08341c6Sdan
635e08341c6Sdan    # Restore the file-system and reopen the databases. Check that it now
636e08341c6Sdan    # appears that the transaction was not committed (because the file-system
637e08341c6Sdan    # was restored to the state where it had not been).
638e08341c6Sdan    #
639e08341c6Sdan    do_test pager1-4.4.$tn.4 {
640e08341c6Sdan      faultsim_restore_and_reopen $prefix
641e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
642e08341c6Sdan    } {}
643e08341c6Sdan    do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
644e08341c6Sdan    do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
645e08341c6Sdan
646e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
647e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
648e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
649e08341c6Sdan    #
650e08341c6Sdan    do_test pager1-4.4.$tn.7 {
651e08341c6Sdan      faultsim_restore_and_reopen $prefix
652fda06befSmistachkin      foreach f [glob ${prefix}-mj*] { forcedelete $f }
653e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
654e08341c6Sdan    } {}
655e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
656e08341c6Sdan      SELECT * FROM a
657e08341c6Sdan    } {double-you why zed won too free}
658e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
659e08341c6Sdan      SELECT * FROM b
660e08341c6Sdan    } {won too free double-you why zed}
661e08341c6Sdan  }
662e08341c6Sdan
663e08341c6Sdan  cd $pwd
664e08341c6Sdan}
665e08341c6Sdandb close
666e08341c6Sdantv delete
667fda06befSmistachkinforcedelete $dirname
6680e986f51Sdan
6690e986f51Sdan
6700e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
6710e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
6720e986f51Sdan# two database pages (and page 1 - the change counter).
6730e986f51Sdan#
6740e986f51Sdantestvfs tv -default 1
6750e986f51Sdantv sectorsize 512
6760e986f51Sdantv script copy_on_journal_delete
6770e986f51Sdantv filter xDelete
6780e986f51Sdanproc copy_on_journal_delete {method filename args} {
6790e986f51Sdan  if {[string match *journal $filename]} faultsim_save
6800e986f51Sdan  return SQLITE_OK
6810e986f51Sdan}
6820e986f51Sdanfaultsim_delete_and_reopen
6830e986f51Sdando_execsql_test pager1.4.5.1 {
6843f94b609Sdan  PRAGMA journal_mode = DELETE;
6850e986f51Sdan  PRAGMA page_size = 1024;
6860e986f51Sdan  CREATE TABLE t1(a, b);
6870e986f51Sdan  CREATE TABLE t2(a, b);
6880e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
6890e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
6900e986f51Sdan  BEGIN;
6910e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
6920e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
6930e986f51Sdan  COMMIT;
6943f94b609Sdan} {delete}
6950e986f51Sdantv filter {}
6960e986f51Sdan
6970e986f51Sdan# Check the transaction was committed:
6980e986f51Sdan#
6990e986f51Sdando_execsql_test pager1.4.5.2 {
7000e986f51Sdan  SELECT * FROM t1;
7010e986f51Sdan  SELECT * FROM t2;
7020e986f51Sdan} {I II 1 2 III IV 3 4}
7030e986f51Sdan
704ec6ffc1aSdan# Now try four tests:
7050e986f51Sdan#
7060e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
7070e986f51Sdan#                is rolled back.
7080e986f51Sdan#
7090e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
7100e986f51Sdan#                journal. Check the transaction is not rolled back.
7110e986f51Sdan#
7120e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
7130e986f51Sdan#                journal. Check that the first record in the transaction is
7140e986f51Sdan#                played back, but not the second.
7150e986f51Sdan#
71610f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
71710f5a50eSdan#                readonly connection. This should fail, as a read-only
71810f5a50eSdan#                connection cannot roll back the database file.
71910f5a50eSdan#
7200e986f51Sdanfaultsim_restore_and_reopen
7210e986f51Sdando_execsql_test pager1.4.5.3 {
7220e986f51Sdan  SELECT * FROM t1;
7230e986f51Sdan  SELECT * FROM t2;
7240e986f51Sdan} {I II III IV}
7250e986f51Sdanfaultsim_restore_and_reopen
7260e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
7270e986f51Sdando_execsql_test pager1.4.5.4 {
7280e986f51Sdan  SELECT * FROM t1;
7290e986f51Sdan  SELECT * FROM t2;
7300e986f51Sdan} {I II 1 2 III IV 3 4}
7310e986f51Sdanfaultsim_restore_and_reopen
7320e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
7330e986f51Sdando_execsql_test pager1.4.5.5 {
7340e986f51Sdan  SELECT * FROM t1;
7350e986f51Sdan  SELECT * FROM t2;
7360e986f51Sdan} {I II III IV 3 4}
7370e986f51Sdan
73810f5a50eSdanfaultsim_restore_and_reopen
73910f5a50eSdandb close
74010f5a50eSdansqlite3 db test.db -readonly 1
74110f5a50eSdando_catchsql_test pager1.4.5.6 {
74210f5a50eSdan  SELECT * FROM t1;
74310f5a50eSdan  SELECT * FROM t2;
74410f5a50eSdan} {1 {disk I/O error}}
745ec6ffc1aSdandb close
746ec6ffc1aSdan
747ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
748ec6ffc1aSdan# of the master journal file in $::mj_filename.
749ec6ffc1aSdan#
750ec6ffc1aSdantv script copy_on_mj_delete
751ec6ffc1aSdantv filter xDelete
752ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
753ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
754ec6ffc1aSdan    set ::mj_filename $filename
755ec6ffc1aSdan    faultsim_save
756ec6ffc1aSdan  }
757ec6ffc1aSdan  return SQLITE_OK
758ec6ffc1aSdan}
759ec6ffc1aSdando_test pager1.4.6.1 {
760ec6ffc1aSdan  faultsim_delete_and_reopen
761ec6ffc1aSdan  execsql {
7623f94b609Sdan    PRAGMA journal_mode = DELETE;
763ec6ffc1aSdan    ATTACH 'test.db2' AS two;
764ec6ffc1aSdan    CREATE TABLE t1(a, b);
765ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
766ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
767ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
768ec6ffc1aSdan    BEGIN;
769ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
770ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
771ec6ffc1aSdan    COMMIT;
772ec6ffc1aSdan  }
773ec6ffc1aSdan  tv filter {}
774ec6ffc1aSdan  db close
775ec6ffc1aSdan} {}
776ec6ffc1aSdan
777ec6ffc1aSdanfaultsim_restore_and_reopen
778ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
779ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
780ec6ffc1aSdando_execsql_test pager1.4.6.4 {
781ec6ffc1aSdan  ATTACH 'test.db2' AS two;
782ec6ffc1aSdan  SELECT * FROM t2;
783ec6ffc1aSdan} {1 t2.1}
784ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
785ec6ffc1aSdan
786ec6ffc1aSdanfaultsim_restore_and_reopen
787ec6ffc1aSdandb close
788ec6ffc1aSdando_test pager1.4.6.8 {
789ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
790ec6ffc1aSdan  tv filter xDelete
791ec6ffc1aSdan  sqlite3 db test.db2
792ec6ffc1aSdan  execsql {
7933f94b609Sdan    PRAGMA journal_mode = DELETE;
794ec6ffc1aSdan    ATTACH 'test.db3' AS three;
795ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
796ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
797ec6ffc1aSdan    BEGIN;
798ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
799ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
800ec6ffc1aSdan    COMMIT;
801ec6ffc1aSdan  }
802ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
803ec6ffc1aSdan} {1}
804ec6ffc1aSdanfaultsim_restore_and_reopen
805ec6ffc1aSdantv filter {}
806ec6ffc1aSdan
807ec6ffc1aSdan# The file-system now contains:
808ec6ffc1aSdan#
809ec6ffc1aSdan#   * three databases
810ec6ffc1aSdan#   * three hot-journal files
811ec6ffc1aSdan#   * two master-journal files.
812ec6ffc1aSdan#
813ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
814ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
815ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
816ec6ffc1aSdan# test.db should delete $::mj_filename1.
817ec6ffc1aSdan#
818ec6ffc1aSdando_test pager1.4.6.9 {
819ec6ffc1aSdan  lsort [glob test.db*]
820ec6ffc1aSdan} [lsort [list                                           \
821ec6ffc1aSdan  test.db test.db2 test.db3                              \
822ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
823ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
824ec6ffc1aSdan]]
825ec6ffc1aSdan
826ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
827ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
828ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
829ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
830ec6ffc1aSdan#
831ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
832ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
833ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
834ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
835ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
836ec6ffc1aSdan
837ec6ffc1aSdando_execsql_test pager1.4.6.12 {
838ec6ffc1aSdan  ATTACH 'test.db2' AS two;
839ec6ffc1aSdan  SELECT * FROM t2;
840ec6ffc1aSdan} {1 t2.1}
841ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
842ec6ffc1aSdando_execsql_test pager1.4.6.14 {
843ec6ffc1aSdan  ATTACH 'test.db3' AS three;
844ec6ffc1aSdan  SELECT * FROM t3;
845ec6ffc1aSdan} {1 t3.1}
846ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
84710f5a50eSdan
8480e986f51Sdandb close
8490e986f51Sdantv delete
850e08341c6Sdan
851c8ce3972Sdantestvfs tv -default 1
852c8ce3972Sdantv sectorsize 512
853c8ce3972Sdantv script copy_on_journal_delete
854c8ce3972Sdantv filter xDelete
855c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
856c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
857c8ce3972Sdan  return SQLITE_OK
858c8ce3972Sdan}
859c8ce3972Sdanfaultsim_delete_and_reopen
860c8ce3972Sdando_execsql_test pager1.4.7.1 {
8613f94b609Sdan  PRAGMA journal_mode = DELETE;
862c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
863c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
864c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
865c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
866c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
867c8ce3972Sdan  BEGIN;
868c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
869c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
870c8ce3972Sdan  COMMIT;
8713f94b609Sdan} {delete}
872c8ce3972Sdantv filter {}
873c8ce3972Sdandb close
874c8ce3972Sdantv delete
875c8ce3972Sdando_test pager1.4.7.2 {
876c8ce3972Sdan  faultsim_restore_and_reopen
877c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
878c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
879c8ce3972Sdan  catchsql { SELECT * FROM t1 }
880c8ce3972Sdan} {1 {unable to open database file}}
881c8ce3972Sdando_test pager1.4.7.3 {
882c8ce3972Sdan  db close
883c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
884c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
885fda06befSmistachkin  delete_file test.db-journal
886c8ce3972Sdan  file exists test.db-journal
887c8ce3972Sdan} {0}
888c8ce3972Sdan
889de4996e2Sdan#-------------------------------------------------------------------------
890146ed78bSdan# The following tests deal with multi-file commits.
891de4996e2Sdan#
892146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
893146ed78bSdan#               another connection is holding a SHARED lock on one of the
894146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
895146ed78bSdan#
896146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
897146ed78bSdan#
898146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
899146ed78bSdan#
900146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
901146ed78bSdan#               name is added to a journal file immediately after the last
902146ed78bSdan#               journal record. But with synchronous=full, extra unused space
903146ed78bSdan#               is allocated between the last journal record and the
904146ed78bSdan#               master-journal file name so that the master-journal file
905146ed78bSdan#               name does not lie on the same sector as the last journal file
906146ed78bSdan#               record.
907146ed78bSdan#
908e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
909e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
910e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
911e08341c6Sdan#
912146ed78bSdan#
913146ed78bSdando_test pager1-5.1.1 {
914146ed78bSdan  faultsim_delete_and_reopen
915146ed78bSdan  execsql {
916146ed78bSdan    ATTACH 'test.db2' AS aux;
917146ed78bSdan    CREATE TABLE t1(a, b);
918146ed78bSdan    CREATE TABLE aux.t2(a, b);
919146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
920146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
921146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
922146ed78bSdan  }
923146ed78bSdan} {}
924146ed78bSdando_test pager1-5.1.2 {
925146ed78bSdan  execsql {
926146ed78bSdan    BEGIN;
927146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
928146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
929146ed78bSdan  }
930146ed78bSdan  sqlite3 db2 test.db2
931146ed78bSdan  execsql {
932146ed78bSdan    BEGIN;
933146ed78bSdan      SELECT * FROM t2;
934146ed78bSdan  } db2
935146ed78bSdan} {}
936146ed78bSdando_test pager1-5.1.3 {
937146ed78bSdan  catchsql COMMIT
938146ed78bSdan} {1 {database is locked}}
939146ed78bSdando_test pager1-5.1.4 {
940146ed78bSdan  execsql COMMIT db2
941146ed78bSdan  execsql COMMIT
942146ed78bSdan  execsql { SELECT * FROM t2 } db2
943146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
944146ed78bSdando_test pager1-5.1.5 {
945146ed78bSdan  db2 close
946146ed78bSdan} {}
947146ed78bSdan
948146ed78bSdando_test pager1-5.2.1 {
949146ed78bSdan  execsql {
950146ed78bSdan    PRAGMA journal_mode = memory;
951146ed78bSdan    BEGIN;
952146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
953146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
954146ed78bSdan    COMMIT;
955146ed78bSdan  }
956146ed78bSdan} {memory}
957146ed78bSdando_test pager1-5.3.1 {
958146ed78bSdan  execsql {
959146ed78bSdan    PRAGMA journal_mode = off;
960146ed78bSdan    BEGIN;
961146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
962146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
963146ed78bSdan    COMMIT;
964146ed78bSdan  }
965146ed78bSdan} {off}
966146ed78bSdan
967146ed78bSdando_test pager1-5.4.1 {
968146ed78bSdan  db close
969146ed78bSdan  testvfs tv
970146ed78bSdan  sqlite3 db test.db -vfs tv
971146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
972146ed78bSdan
973146ed78bSdan  tv filter xDelete
974146ed78bSdan  tv script max_journal_size
975146ed78bSdan  tv sectorsize 512
976146ed78bSdan  set ::max_journal 0
977146ed78bSdan  proc max_journal_size {method args} {
978146ed78bSdan    set sz 0
979146ed78bSdan    catch { set sz [file size test.db-journal] }
980146ed78bSdan    if {$sz > $::max_journal} {
981146ed78bSdan      set ::max_journal $sz
982146ed78bSdan    }
983146ed78bSdan    return SQLITE_OK
984146ed78bSdan  }
985146ed78bSdan  execsql {
986146ed78bSdan    PRAGMA journal_mode = DELETE;
987146ed78bSdan    PRAGMA synchronous = NORMAL;
988146ed78bSdan    BEGIN;
989146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
990146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
991146ed78bSdan    COMMIT;
992146ed78bSdan  }
993*7f9026ddSdan
994*7f9026ddSdan  # The size of the journal file is now:
995*7f9026ddSdan  #
996*7f9026ddSdan  #   1) 512 byte header +
997*7f9026ddSdan  #   2) 2 * (1024+8) byte records +
998*7f9026ddSdan  #   3) 20+N bytes of master-journal pointer, where N is the size of
999*7f9026ddSdan  #      the master-journal name encoded as utf-8 with no nul term.
1000*7f9026ddSdan  #
1001*7f9026ddSdan  set mj_pointer [expr {
1002*7f9026ddSdan    20 + [string length [pwd]] + [string length "/test.db-mjXXXXXX9XX"]
1003*7f9026ddSdan  }]
1004*7f9026ddSdan  expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
1005*7f9026ddSdan} 1
1006146ed78bSdando_test pager1-5.4.2 {
1007146ed78bSdan  set ::max_journal 0
1008146ed78bSdan  execsql {
1009146ed78bSdan    PRAGMA synchronous = full;
1010146ed78bSdan    BEGIN;
1011146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
1012146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
1013146ed78bSdan    COMMIT;
1014146ed78bSdan  }
1015*7f9026ddSdan
1016*7f9026ddSdan  # In synchronous=full mode, the master-journal pointer is not written
1017*7f9026ddSdan  # directly after the last record in the journal file. Instead, it is
1018*7f9026ddSdan  # written starting at the next (in this case 512 byte) sector boundary.
1019*7f9026ddSdan  #
1020*7f9026ddSdan  set mj_pointer [expr {
1021*7f9026ddSdan    20 + [string length [pwd]] + [string length "/test.db-mjXXXXXX9XX"]
1022*7f9026ddSdan  }]
1023*7f9026ddSdan  expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
1024*7f9026ddSdan} 1
1025146ed78bSdandb close
1026146ed78bSdantv delete
1027146ed78bSdan
1028146ed78bSdando_test pager1-5.5.1 {
1029146ed78bSdan  sqlite3 db test.db
1030146ed78bSdan  execsql {
1031146ed78bSdan    ATTACH 'test.db2' AS aux;
1032146ed78bSdan    PRAGMA journal_mode = PERSIST;
1033146ed78bSdan    CREATE TABLE t3(a, b);
1034146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
1035146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
1036146ed78bSdan  }
1037146ed78bSdan  expr [file size test.db-journal] > 15000
1038146ed78bSdan} {1}
1039146ed78bSdando_test pager1-5.5.2 {
1040146ed78bSdan  execsql {
1041146ed78bSdan    PRAGMA synchronous = full;
1042146ed78bSdan    BEGIN;
1043146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
1044146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
1045146ed78bSdan    COMMIT;
1046146ed78bSdan  }
1047146ed78bSdan  file size test.db-journal
1048146ed78bSdan} {0}
1049146ed78bSdan
1050146ed78bSdan
1051146ed78bSdan#-------------------------------------------------------------------------
1052146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1053146ed78bSdan#
1054146ed78bSdando_test pager1-6.1 {
1055146ed78bSdan  faultsim_delete_and_reopen
1056146ed78bSdan  execsql {
1057f43d7fceSdan    PRAGMA auto_vacuum = none;
1058146ed78bSdan    PRAGMA max_page_count = 10;
1059146ed78bSdan    CREATE TABLE t2(a, b);
1060146ed78bSdan    CREATE TABLE t3(a, b);
1061146ed78bSdan    CREATE TABLE t4(a, b);
1062146ed78bSdan    CREATE TABLE t5(a, b);
1063146ed78bSdan    CREATE TABLE t6(a, b);
1064146ed78bSdan    CREATE TABLE t7(a, b);
1065146ed78bSdan    CREATE TABLE t8(a, b);
1066146ed78bSdan    CREATE TABLE t9(a, b);
1067146ed78bSdan    CREATE TABLE t10(a, b);
1068146ed78bSdan  }
1069146ed78bSdan} {10}
1070d353331aSdando_catchsql_test pager1-6.2 {
1071d353331aSdan  CREATE TABLE t11(a, b)
1072146ed78bSdan} {1 {database or disk is full}}
1073d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1074d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1075d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1076d353331aSdando_execsql_test pager1-6.7 {
1077d353331aSdan  BEGIN;
1078d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1079d353331aSdan    PRAGMA max_page_count = 13;
1080d353331aSdan} {13}
1081d353331aSdando_execsql_test pager1-6.8 {
1082d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1083d353331aSdan    PRAGMA max_page_count = 10;
1084d353331aSdan} {11}
1085d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1086de4996e2Sdan
108760ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
108822b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
108922b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
109022b328b2Sdan
1091153eda0aSdan
1092153eda0aSdan#-------------------------------------------------------------------------
1093153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1094153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1095153eda0aSdan#
1096153eda0aSdan# Each test is specified with 5 variables. As follows:
1097153eda0aSdan#
1098153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1099153eda0aSdan#   $sql: SQL to execute.
1100153eda0aSdan#   $res: Expected result of executing $sql.
1101153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1102153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1103153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1104153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1105153eda0aSdan#
110638e1a279Sdanifcapable wal {
1107153eda0aSdan  faultsim_delete_and_reopen
1108153eda0aSdan  foreach {tn sql res js ws} [subst {
1109153eda0aSdan
1110153eda0aSdan    1  {
1111153eda0aSdan      CREATE TABLE t1(a, b);
1112153eda0aSdan      PRAGMA auto_vacuum=OFF;
1113153eda0aSdan      PRAGMA synchronous=NORMAL;
1114153eda0aSdan      PRAGMA page_size=1024;
1115153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1116153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1117153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1118153eda0aSdan    } {exclusive truncate} 0 -1
1119153eda0aSdan
1120153eda0aSdan    2  {
1121153eda0aSdan      BEGIN IMMEDIATE;
1122153eda0aSdan        SELECT * FROM t1;
1123153eda0aSdan      COMMIT;
1124153eda0aSdan    } {1 2} 0 -1
1125153eda0aSdan
1126153eda0aSdan    3  {
1127153eda0aSdan      BEGIN;
1128153eda0aSdan        SELECT * FROM t1;
1129153eda0aSdan      COMMIT;
1130153eda0aSdan    } {1 2} 0 -1
1131153eda0aSdan
1132153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal       -1 -1
1133153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}        -1 [wal_file_size 1 1024]
11348c408004Sdan    6  { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
1135153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
1136153eda0aSdan
1137153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1138153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1139153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1140153eda0aSdan
1141153eda0aSdan  }] {
1142153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1143153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1144153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1145153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1146153eda0aSdan  }
114738e1a279Sdan}
1148153eda0aSdan
114989ccf448Sdando_test pager1-7.2.1 {
115089ccf448Sdan  faultsim_delete_and_reopen
115189ccf448Sdan  execsql {
115289ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
115389ccf448Sdan    CREATE TABLE t1(a, b);
115489ccf448Sdan    BEGIN;
115589ccf448Sdan      PRAGMA journal_mode = delete;
115689ccf448Sdan      PRAGMA journal_mode = truncate;
115789ccf448Sdan  }
115889ccf448Sdan} {exclusive delete truncate}
115989ccf448Sdando_test pager1-7.2.2 {
116089ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
116189ccf448Sdan  execsql { PRAGMA journal_mode = persist }
116289ccf448Sdan} {truncate}
116389ccf448Sdando_test pager1-7.2.3 {
116489ccf448Sdan  execsql { COMMIT }
116589ccf448Sdan  execsql {
116689ccf448Sdan    PRAGMA journal_mode = persist;
116789ccf448Sdan    PRAGMA journal_size_limit;
116889ccf448Sdan  }
116989ccf448Sdan} {persist -1}
117089ccf448Sdan
1171d353331aSdan#-------------------------------------------------------------------------
1172d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1173d353331aSdan# ":memory:" and "" open temporary databases.
1174d353331aSdan#
11750e986f51Sdanforeach {tn filename} {
11760e986f51Sdan  1 :memory:
11770e986f51Sdan  2 ""
11780e986f51Sdan} {
11790e986f51Sdan  do_test pager1-8.$tn.1 {
1180153eda0aSdan    faultsim_delete_and_reopen
1181153eda0aSdan    db close
11820e986f51Sdan    sqlite3 db $filename
1183153eda0aSdan    execsql {
1184c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1185153eda0aSdan      CREATE TABLE x1(x);
1186153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1187153eda0aSdan      INSERT INTO x1 VALUES('James');
1188153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1189153eda0aSdan      SELECT * FROM x1;
1190153eda0aSdan    }
1191153eda0aSdan  } {Charles James Mary}
11920e986f51Sdan
11930e986f51Sdan  do_test pager1-8.$tn.2 {
11940e986f51Sdan    sqlite3 db2 $filename
11950e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1196153eda0aSdan  } {1 {no such table: x1}}
1197153eda0aSdan
11980e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
11990e986f51Sdan    BEGIN;
12000e986f51Sdan      INSERT INTO x1 VALUES('William');
12010e986f51Sdan      INSERT INTO x1 VALUES('Anne');
12020e986f51Sdan    ROLLBACK;
12030e986f51Sdan  } {}
12040e986f51Sdan}
12050e986f51Sdan
1206dca321aeSdan#-------------------------------------------------------------------------
1207dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1208dca321aeSdan# the pager and the backup API. Test cases:
1209dca321aeSdan#
1210dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1211dca321aeSdan#                 source db is written to during the backup op.
1212dca321aeSdan#
1213dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1214dca321aeSdan#                 source db is written to and then rolled back during a
1215dca321aeSdan#                 backup operation.
1216dca321aeSdan#
1217dca321aeSdando_test pager1-9.0.1 {
1218dca321aeSdan  faultsim_delete_and_reopen
1219dca321aeSdan  db func a_string a_string
1220dca321aeSdan  execsql {
1221dca321aeSdan    PRAGMA cache_size = 10;
1222dca321aeSdan    BEGIN;
1223dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1224dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1225dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1226dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1227dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1228dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1229dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1230dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1231dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1232dca321aeSdan    COMMIT;
1233dca321aeSdan  }
1234dca321aeSdan} {}
1235dca321aeSdando_test pager1-9.0.2 {
1236dca321aeSdan  sqlite3 db2 test.db2
1237dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1238dca321aeSdan  sqlite3_backup B db2 main db main
1239dca321aeSdan  list [B step 10000] [B finish]
1240dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1241dca321aeSdando_test pager1-9.0.3 {
1242dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1243dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1244dca321aeSdan
1245dca321aeSdando_test pager1-9.1.1 {
1246dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1247dca321aeSdan  sqlite3_backup B db2 main db main
1248dca321aeSdan  B step 30
1249dca321aeSdan} {SQLITE_OK}
1250dca321aeSdando_test pager1-9.1.2 {
1251dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1252dca321aeSdan  list [B step 10000] [B finish]
1253dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1254dca321aeSdando_test pager1-9.1.3 {
1255dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1256dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1257dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1258dca321aeSdan
1259dca321aeSdando_test pager1-9.2.1 {
1260dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1261dca321aeSdan  sqlite3_backup B db2 main db main
1262dca321aeSdan  B step 30
1263dca321aeSdan} {SQLITE_OK}
1264dca321aeSdando_test pager1-9.2.2 {
1265dca321aeSdan  execsql {
1266dca321aeSdan    BEGIN;
1267dca321aeSdan      UPDATE ab SET b = a_string(301);
1268dca321aeSdan    ROLLBACK;
1269dca321aeSdan  }
1270dca321aeSdan  list [B step 10000] [B finish]
1271dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1272dca321aeSdando_test pager1-9.2.3 {
1273dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1274dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1275dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1276ec6ffc1aSdandb close
1277ec6ffc1aSdandb2 close
1278ec6ffc1aSdan
1279c396d4afSdando_test pager1-9.3.1 {
1280c396d4afSdan  testvfs tv -default 1
1281c396d4afSdan  tv sectorsize 4096
1282c396d4afSdan  faultsim_delete_and_reopen
1283c396d4afSdan
1284c396d4afSdan  execsql { PRAGMA page_size = 1024 }
1285c396d4afSdan  for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
1286c396d4afSdan} {}
1287c396d4afSdando_test pager1-9.3.2 {
1288c396d4afSdan  sqlite3 db2 test.db2
1289f412ee2eSdan
1290c396d4afSdan  execsql {
1291c396d4afSdan    PRAGMA page_size = 4096;
1292c396d4afSdan    PRAGMA synchronous = OFF;
1293c396d4afSdan    CREATE TABLE t1(a, b);
1294c396d4afSdan    CREATE TABLE t2(a, b);
1295c396d4afSdan  } db2
1296c396d4afSdan
1297c396d4afSdan  sqlite3_backup B db2 main db main
1298c396d4afSdan  B step 30
1299c396d4afSdan  list [B step 10000] [B finish]
1300c396d4afSdan} {SQLITE_DONE SQLITE_OK}
1301c396d4afSdando_test pager1-9.3.3 {
1302c396d4afSdan  db2 close
1303c396d4afSdan  db close
1304c396d4afSdan  tv delete
1305c396d4afSdan  file size test.db2
1306c396d4afSdan} [file size test.db]
1307c396d4afSdan
1308f412ee2eSdando_test pager1-9.4.1 {
1309f412ee2eSdan  faultsim_delete_and_reopen
1310f412ee2eSdan  sqlite3 db2 test.db2
1311f412ee2eSdan  execsql {
1312f412ee2eSdan    PRAGMA page_size = 4096;
1313f412ee2eSdan    CREATE TABLE t1(a, b);
1314f412ee2eSdan    CREATE TABLE t2(a, b);
1315f412ee2eSdan  } db2
1316f412ee2eSdan  sqlite3_backup B db2 main db main
1317f412ee2eSdan  list [B step 10000] [B finish]
1318f412ee2eSdan} {SQLITE_DONE SQLITE_OK}
1319f412ee2eSdando_test pager1-9.4.2 {
1320f412ee2eSdan  list [file size test.db2] [file size test.db]
1321f412ee2eSdan} {0 0}
132233d85c9cSshanehdb2 close
1323d0b0d4dcSdan
1324ec6ffc1aSdan#-------------------------------------------------------------------------
1325ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1326ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1327ec6ffc1aSdan#
1328ec6ffc1aSdantestvfs tv -default 1
1329ec6ffc1aSdanforeach sectorsize {
1330ec6ffc1aSdan    32   64   128   256   512   1024   2048
1331ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1332ec6ffc1aSdan} {
1333ec6ffc1aSdan  tv sectorsize $sectorsize
1334ec6ffc1aSdan  set eff $sectorsize
1335ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1336ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1337ec6ffc1aSdan
1338d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1339ec6ffc1aSdan    faultsim_delete_and_reopen
1340d0b0d4dcSdan    db func a_string a_string
1341ec6ffc1aSdan    execsql {
1342ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1343ec6ffc1aSdan      PRAGMA page_size = 1024;
1344d0b0d4dcSdan      BEGIN;
1345ec6ffc1aSdan        CREATE TABLE t1(a, b);
1346d0b0d4dcSdan        CREATE TABLE t2(a, b);
1347d0b0d4dcSdan        CREATE TABLE t3(a, b);
1348d0b0d4dcSdan      COMMIT;
1349ec6ffc1aSdan    }
1350ec6ffc1aSdan    file size test.db-journal
1351ec6ffc1aSdan  } [expr $sectorsize > 65536 ? 65536 : $sectorsize]
1352d0b0d4dcSdan
1353d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1354d0b0d4dcSdan    execsql {
1355d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1356d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1357d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1358d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1359d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1360d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1361ec6ffc1aSdan    }
1362d0b0d4dcSdan  } {}
1363d0b0d4dcSdan
1364d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1365d0b0d4dcSdan    db close
1366d0b0d4dcSdan    sqlite3 db test.db
1367d0b0d4dcSdan    execsql {
1368d0b0d4dcSdan      PRAGMA cache_size = 10;
1369d0b0d4dcSdan      BEGIN;
1370d0b0d4dcSdan    }
1371d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1372d0b0d4dcSdan    execsql {
1373d0b0d4dcSdan      COMMIT;
1374d0b0d4dcSdan      SELECT * FROM t2;
1375d0b0d4dcSdan    }
1376d0b0d4dcSdan  } {1 2}
1377d0b0d4dcSdan
1378d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1379d0b0d4dcSdan    execsql {
1380d0b0d4dcSdan      CREATE TABLE t6(a, b);
1381d0b0d4dcSdan      CREATE TABLE t7(a, b);
1382d0b0d4dcSdan      CREATE TABLE t5(a, b);
1383d0b0d4dcSdan      DROP TABLE t6;
1384d0b0d4dcSdan      DROP TABLE t7;
1385d0b0d4dcSdan    }
1386d0b0d4dcSdan    execsql {
1387d0b0d4dcSdan      BEGIN;
1388d0b0d4dcSdan        CREATE TABLE t6(a, b);
1389d0b0d4dcSdan    }
1390d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1391d0b0d4dcSdan    execsql {
1392d0b0d4dcSdan      COMMIT;
1393d0b0d4dcSdan      SELECT * FROM t5;
1394d0b0d4dcSdan    }
1395d0b0d4dcSdan  } {1 2}
1396d0b0d4dcSdan
1397d0b0d4dcSdan}
1398d0b0d4dcSdandb close
1399d0b0d4dcSdan
1400d0b0d4dcSdantv sectorsize 4096
1401d0b0d4dcSdando_test pager1.10.x.1 {
1402d0b0d4dcSdan  faultsim_delete_and_reopen
1403d0b0d4dcSdan  execsql {
1404f43d7fceSdan    PRAGMA auto_vacuum = none;
1405d0b0d4dcSdan    PRAGMA page_size = 1024;
1406d0b0d4dcSdan    CREATE TABLE t1(x);
1407d0b0d4dcSdan  }
1408d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1409d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1410d0b0d4dcSdan  }
1411d0b0d4dcSdan  file size test.db
1412d0b0d4dcSdan} {32768}
1413d0b0d4dcSdando_test pager1.10.x.2 {
1414d0b0d4dcSdan  execsql {
1415d0b0d4dcSdan    CREATE TABLE t2(x);
1416d0b0d4dcSdan    DROP TABLE t2;
1417d0b0d4dcSdan  }
1418d0b0d4dcSdan  file size test.db
1419d0b0d4dcSdan} {33792}
1420d0b0d4dcSdando_test pager1.10.x.3 {
1421d0b0d4dcSdan  execsql {
1422d0b0d4dcSdan    BEGIN;
1423d0b0d4dcSdan    CREATE TABLE t2(x);
1424d0b0d4dcSdan  }
1425d0b0d4dcSdan  recursive_select 30 t1
1426d0b0d4dcSdan  execsql {
1427d0b0d4dcSdan    CREATE TABLE t3(x);
1428d0b0d4dcSdan    COMMIT;
1429d0b0d4dcSdan  }
1430d0b0d4dcSdan} {}
1431d0b0d4dcSdan
1432ec6ffc1aSdandb close
1433ec6ffc1aSdantv delete
1434ec6ffc1aSdan
1435ec6ffc1aSdantestvfs tv -default 1
1436ec6ffc1aSdanfaultsim_delete_and_reopen
1437ec6ffc1aSdandb func a_string a_string
1438ec6ffc1aSdando_execsql_test pager1-11.1 {
14393f94b609Sdan  PRAGMA journal_mode = DELETE;
1440ec6ffc1aSdan  PRAGMA cache_size = 10;
1441ec6ffc1aSdan  BEGIN;
1442ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1443ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1444ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1445ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1446ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1447ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1448ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1449ec6ffc1aSdan  COMMIT;
1450ec6ffc1aSdan  BEGIN;
1451ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
14523f94b609Sdan} {delete}
1453ec6ffc1aSdan
1454ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1455ec6ffc1aSdantv script lockout
1456ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1457ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1458ec6ffc1aSdan
1459ec6ffc1aSdantv script {}
1460ec6ffc1aSdando_test pager1-11.3 {
1461ec6ffc1aSdan  sqlite3 db2 test.db
1462ec6ffc1aSdan  execsql {
1463ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1464ec6ffc1aSdan    PRAGMA integrity_check;
1465ec6ffc1aSdan  } db2
1466ec6ffc1aSdan} {truncate ok}
1467ec6ffc1aSdando_test pager1-11.4 {
1468ec6ffc1aSdan  db2 close
1469f6c61471Sdan  file exists test.db-journal
1470ec6ffc1aSdan} {0}
1471ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1472f9b4419dSdandb close
1473f9b4419dSdantv delete
1474ec6ffc1aSdan
1475f9b4419dSdan#-------------------------------------------------------------------------
1476f9b4419dSdan# Test "PRAGMA page_size"
1477f9b4419dSdan#
1478f43d7fceSdantestvfs tv -default 1
1479f43d7fceSdantv sectorsize 1024
1480f9b4419dSdanforeach pagesize {
1481f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1482f9b4419dSdan} {
1483f9b4419dSdan  faultsim_delete_and_reopen
1484f9b4419dSdan
1485f43d7fceSdan  # The sector-size (according to the VFS) is 1024 bytes. So if the
1486f43d7fceSdan  # page-size requested using "PRAGMA page_size" is greater than the
1487f43d7fceSdan  # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
1488f43d7fceSdan  # page-size remains 1024 bytes.
1489f43d7fceSdan  #
1490f43d7fceSdan  set eff $pagesize
1491f43d7fceSdan  if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
1492f43d7fceSdan
1493f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1494f9b4419dSdan    sqlite3 db2 test.db
1495f9b4419dSdan    execsql "
1496f9b4419dSdan      PRAGMA page_size = $pagesize;
1497f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1498f9b4419dSdan    " db2
1499f9b4419dSdan    file size test.db
1500f43d7fceSdan  } $eff
1501f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1502f9b4419dSdan    sqlite3 db2 test.db
1503f9b4419dSdan    execsql {
1504f9b4419dSdan      SELECT count(*) FROM v;
1505f9b4419dSdan      PRAGMA main.page_size;
1506f9b4419dSdan    } db2
1507f43d7fceSdan  } [list 1 $eff]
1508f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1509f9b4419dSdan    execsql {
1510f9b4419dSdan      SELECT count(*) FROM v;
1511f9b4419dSdan      PRAGMA main.page_size;
1512f9b4419dSdan    }
1513f43d7fceSdan  } [list 1 $eff]
1514f9b4419dSdan  db2 close
1515f9b4419dSdan}
1516f43d7fceSdandb close
1517f43d7fceSdantv delete
1518dca321aeSdan
1519d353331aSdan#-------------------------------------------------------------------------
1520d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1521d353331aSdan#
1522d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1523d353331aSdan#                journal mode: If the journal associated with a transaction
1524d353331aSdan#                is smaller than the journal file (because a previous
1525d353331aSdan#                transaction left a very large non-hot journal file in the
1526d353331aSdan#                file-system), then SQLite has to be careful that there is
1527d353331aSdan#                not a journal-header left over from a previous transaction
1528d353331aSdan#                immediately following the journal content just written.
1529d353331aSdan#                If there is, and the process crashes so that the journal
1530d353331aSdan#                becomes a hot-journal and must be rolled back by another
1531d353331aSdan#                process, there is a danger that the other process may roll
1532d353331aSdan#                back the aborted transaction, then continue copying data
1533d353331aSdan#                from an older transaction from the remainder of the journal.
1534d353331aSdan#                See the syncJournal() function for details.
1535d353331aSdan#
1536d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1537d353331aSdan#                the mix to make the integrity-check more likely to catch
1538d353331aSdan#                errors.
1539d353331aSdan#
1540d353331aSdantestvfs tv -default 1
1541d353331aSdantv script xSyncCb
1542d353331aSdantv filter xSync
1543d353331aSdanproc xSyncCb {method filename args} {
1544d353331aSdan  set t [file tail $filename]
1545d353331aSdan  if {$t == "test.db"} faultsim_save
1546d353331aSdan  return SQLITE_OK
1547d353331aSdan}
1548d353331aSdanfaultsim_delete_and_reopen
1549d353331aSdandb func a_string a_string
1550e91a54e1Sdan
1551d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1552d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1553d353331aSdan# frequent journal headers.
1554d353331aSdan#
1555d353331aSdando_execsql_test pager1-13.1.1 {
1556d353331aSdan  PRAGMA page_size = 1024;
1557d353331aSdan  PRAGMA journal_mode = PERSIST;
1558d353331aSdan  PRAGMA cache_size = 10;
1559d353331aSdan  BEGIN;
1560d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1561d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1562d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1563d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1564d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1565d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1566d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1567d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1568d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1569d353331aSdan  COMMIT;
1570d353331aSdan  UPDATE t1 SET b = a_string(400);
1571d353331aSdan} {persist}
1572d353331aSdan
1573b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1574d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1575d353331aSdan# of these will write just enough content that one of the old headers created
1576d353331aSdan# by the transaction in the block above lies immediately after the content
1577d353331aSdan# journalled by the current transaction.
1578d353331aSdan#
1579d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1580d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1581d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1582d353331aSdan  } {}
1583d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1584d353331aSdan
1585d353331aSdan  # Try to access the snapshot of the file-system.
1586d353331aSdan  #
1587d353331aSdan  sqlite3 db2 sv_test.db
1588d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1589d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1590d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1591d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1592d353331aSdan    execsql { PRAGMA integrity_check } db2
1593d353331aSdan  } {ok}
1594d353331aSdan  db2 close
1595d353331aSdan}
1596b2f20bfcSshaneh}
1597d353331aSdan
1598b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1599d353331aSdan# Same test as above. But this time with an index on the table.
1600d353331aSdan#
1601d353331aSdando_execsql_test pager1-13.2.1 {
1602d353331aSdan  CREATE INDEX i1 ON t1(b);
1603d353331aSdan  UPDATE t1 SET b = a_string(400);
1604d353331aSdan} {}
1605d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1606d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1607d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1608d353331aSdan  } {}
1609d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1610d353331aSdan  sqlite3 db2 sv_test.db
1611d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1612d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1613d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1614d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1615d353331aSdan    execsql { PRAGMA integrity_check } db2
1616d353331aSdan  } {ok}
1617d353331aSdan  db2 close
1618d353331aSdan}
1619b2f20bfcSshaneh}
1620d353331aSdan
1621d353331aSdandb close
1622d353331aSdantv delete
1623d353331aSdan
1624d353331aSdan#-------------------------------------------------------------------------
1625d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1626d353331aSdan#
1627d353331aSdanfaultsim_delete_and_reopen
1628d353331aSdando_execsql_test pager1-14.1.1 {
1629d353331aSdan  PRAGMA journal_mode = OFF;
1630d353331aSdan  CREATE TABLE t1(a, b);
1631d353331aSdan  BEGIN;
1632d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1633d353331aSdan  COMMIT;
1634d353331aSdan  SELECT * FROM t1;
1635d353331aSdan} {off 1 2}
1636d353331aSdando_catchsql_test pager1-14.1.2 {
1637d353331aSdan  BEGIN;
1638d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1639d353331aSdan  ROLLBACK;
1640d353331aSdan} {0 {}}
1641d353331aSdando_execsql_test pager1-14.1.3 {
1642d353331aSdan  SELECT * FROM t1;
1643354bfe03Sdan} {1 2}
1644d353331aSdando_catchsql_test pager1-14.1.4 {
1645d353331aSdan  BEGIN;
1646d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1647d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1648d353331aSdan} {1 {PRIMARY KEY must be unique}}
1649d353331aSdando_execsql_test pager1-14.1.5 {
1650d353331aSdan  COMMIT;
1651d353331aSdan  SELECT * FROM t1;
1652354bfe03Sdan} {1 2 2 2}
1653d353331aSdan
1654c8ce3972Sdan#-------------------------------------------------------------------------
1655c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1656c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1657c8ce3972Sdan#
1658c8ce3972Sdanfaultsim_delete_and_reopen
1659c8ce3972Sdando_execsql_test pager1-15.0 {
1660c8ce3972Sdan  CREATE TABLE tx(y, z);
1661c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1662c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1663c8ce3972Sdan} {}
1664c8ce3972Sdandb close
1665c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1666c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1667c8ce3972Sdan  sqlite3 db test.db
1668c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1669c8ce3972Sdan    SELECT * FROM tx;
1670c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1671c8ce3972Sdan  db close
1672c8ce3972Sdan  tv delete
1673c8ce3972Sdan}
1674c8ce3972Sdan
1675c8ce3972Sdan#-------------------------------------------------------------------------
1676c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1677c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1678c8ce3972Sdan#
1679c8ce3972Sdantestvfs tv -default 1
1680c8ce3972Sdantv script xOpenCb
1681c8ce3972Sdantv filter xOpen
168233f5379cSdanproc xOpenCb {method filename args} {
1683c8ce3972Sdan  set ::file_len [string length $filename]
1684c8ce3972Sdan}
1685c8ce3972Sdansqlite3 db test.db
1686c8ce3972Sdandb close
1687c8ce3972Sdantv delete
1688c8ce3972Sdan
1689c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1690c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1691c8ce3972Sdan
1692c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1693c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1694c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1695c8ce3972Sdan  #
1696c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1697c8ce3972Sdan    set res {0 {}}
1698c8ce3972Sdan  } else {
1699c8ce3972Sdan    set res {1 {unable to open database file}}
1700c8ce3972Sdan  }
1701c8ce3972Sdan
1702c8ce3972Sdan  do_test pager1-16.1.$ii {
1703c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1704c8ce3972Sdan  } $res
1705c8ce3972Sdan
1706c8ce3972Sdan  catch {db close}
1707c8ce3972Sdan  tv delete
1708c8ce3972Sdan}
1709c8ce3972Sdan
1710c8ce3972Sdan#-------------------------------------------------------------------------
1711c8ce3972Sdan# Test "PRAGMA omit_readlock".
1712c8ce3972Sdan#
1713c8ce3972Sdan#   pager1-17.$tn.1.*: Test that if a second connection has an open
1714c8ce3972Sdan#                      read-transaction, it is not usually possible to write
1715c8ce3972Sdan#                      the database.
1716c8ce3972Sdan#
1717c8ce3972Sdan#   pager1-17.$tn.2.*: Test that if the second connection was opened with
1718c8ce3972Sdan#                      the SQLITE_OPEN_READONLY flag, and
1719c8ce3972Sdan#                      "PRAGMA omit_readlock = 1" is executed before attaching
1720c8ce3972Sdan#                      the database and opening a read-transaction on it, it is
1721c8ce3972Sdan#                      possible to write the db.
1722c8ce3972Sdan#
1723c8ce3972Sdan#   pager1-17.$tn.3.*: Test that if the second connection was *not* opened with
1724c8ce3972Sdan#                      the SQLITE_OPEN_READONLY flag, executing
1725c8ce3972Sdan#                      "PRAGMA omit_readlock = 1" has no effect.
1726c8ce3972Sdan#
1727c8ce3972Sdando_multiclient_test tn {
1728c8ce3972Sdan  do_test pager1-17.$tn.1.1 {
1729c8ce3972Sdan    sql1 {
1730c8ce3972Sdan      CREATE TABLE t1(a, b);
1731c8ce3972Sdan      INSERT INTO t1 VALUES(1, 2);
1732c8ce3972Sdan    }
1733c8ce3972Sdan    sql2 {
1734c8ce3972Sdan      BEGIN;
1735c8ce3972Sdan      SELECT * FROM t1;
1736c8ce3972Sdan    }
1737c8ce3972Sdan  } {1 2}
1738c8ce3972Sdan  do_test pager1-17.$tn.1.2 {
1739c8ce3972Sdan    csql1 { INSERT INTO t1 VALUES(3, 4) }
1740c8ce3972Sdan  } {1 {database is locked}}
1741c8ce3972Sdan  do_test pager1-17.$tn.1.3 {
1742c8ce3972Sdan    sql2 { COMMIT }
1743c8ce3972Sdan    sql1 { INSERT INTO t1 VALUES(3, 4) }
1744c8ce3972Sdan  } {}
1745c8ce3972Sdan
1746c8ce3972Sdan  do_test pager1-17.$tn.2.1 {
1747c8ce3972Sdan    code2 {
1748c8ce3972Sdan      db2 close
1749c8ce3972Sdan      sqlite3 db2 :memory: -readonly 1
1750c8ce3972Sdan    }
1751c8ce3972Sdan    sql2 {
1752c8ce3972Sdan      PRAGMA omit_readlock = 1;
1753c8ce3972Sdan      ATTACH 'test.db' AS two;
1754c8ce3972Sdan      BEGIN;
1755c8ce3972Sdan      SELECT * FROM t1;
1756c8ce3972Sdan    }
1757c8ce3972Sdan  } {1 2 3 4}
1758c8ce3972Sdan  do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {}
1759c8ce3972Sdan  do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" }            {1 2 3 4}
1760c8ce3972Sdan  do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" }   {1 2 3 4 5 6}
1761c8ce3972Sdan
1762c8ce3972Sdan  do_test pager1-17.$tn.3.1 {
1763c8ce3972Sdan    code2 {
1764c8ce3972Sdan      db2 close
1765c8ce3972Sdan      sqlite3 db2 :memory:
1766c8ce3972Sdan    }
1767c8ce3972Sdan    sql2 {
1768c8ce3972Sdan      PRAGMA omit_readlock = 1;
1769c8ce3972Sdan      ATTACH 'test.db' AS two;
1770c8ce3972Sdan      BEGIN;
1771c8ce3972Sdan      SELECT * FROM t1;
1772c8ce3972Sdan    }
1773c8ce3972Sdan  } {1 2 3 4 5 6}
1774c8ce3972Sdan  do_test pager1-17.$tn.3.2 {
1775c8ce3972Sdan  csql1 { INSERT INTO t1 VALUES(3, 4) }
1776c8ce3972Sdan  } {1 {database is locked}}
1777c8ce3972Sdan  do_test pager1-17.$tn.3.3 { sql2 COMMIT } {}
1778c8ce3972Sdan}
1779c8ce3972Sdan
1780c8ce3972Sdan#-------------------------------------------------------------------------
1781c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1782c8ce3972Sdan# numbers:
1783c8ce3972Sdan#
1784c8ce3972Sdan#   + The locking page,
1785c8ce3972Sdan#   + Page 0,
1786c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1787c8ce3972Sdan#
1788f4ba1093Sdan# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
1789f4ba1093Sdan# that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
1790f4ba1093Sdan#
1791f4ba1093Sdanifcapable !direct_read {
1792c8ce3972Sdando_test pager1-18.1 {
1793c8ce3972Sdan  faultsim_delete_and_reopen
1794c8ce3972Sdan  db func a_string a_string
1795c8ce3972Sdan  execsql {
1796c8ce3972Sdan    PRAGMA page_size = 1024;
1797c8ce3972Sdan    CREATE TABLE t1(a, b);
1798c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1799c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1800c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1801c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1802c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1803c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1804c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1805c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1806c8ce3972Sdan  }
1807c8ce3972Sdan} {}
1808c8ce3972Sdando_test pager1-18.2 {
1809c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1810c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1811c8ce3972Sdan  execsql {
1812c8ce3972Sdan    PRAGMA writable_schema = 1;
1813c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1814c8ce3972Sdan  }
1815c8ce3972Sdan  sqlite3 db2 test.db
1816c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1817c8ce3972Sdan} {1 {database disk image is malformed}}
1818c8ce3972Sdandb2 close
1819c8ce3972Sdando_test pager1-18.3 {
1820c8ce3972Sdan  execsql {
1821c8ce3972Sdan    CREATE TABLE t2(x);
1822c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1823c8ce3972Sdan  }
1824c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1825c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1826c8ce3972Sdan  sqlite3 db2 test.db
1827c8ce3972Sdan  catchsql { SELECT length(x) FROM t2 } db2
1828c8ce3972Sdan} {1 {database disk image is malformed}}
1829c8ce3972Sdandb2 close
1830c8ce3972Sdando_test pager1-18.4 {
1831c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1832c8ce3972Sdan  sqlite3 db2 test.db
1833c8ce3972Sdan  catchsql { SELECT length(x) FROM t2 } db2
1834c8ce3972Sdan} {1 {database disk image is malformed}}
1835c8ce3972Sdandb2 close
1836c8ce3972Sdando_test pager1-18.5 {
1837c8ce3972Sdan  sqlite3 db ""
1838c8ce3972Sdan  execsql {
1839c8ce3972Sdan    CREATE TABLE t1(a, b);
1840c8ce3972Sdan    CREATE TABLE t2(a, b);
1841c8ce3972Sdan    PRAGMA writable_schema = 1;
1842c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1843c8ce3972Sdan    PRAGMA writable_schema = 0;
1844c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1845c8ce3972Sdan  }
1846c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1847ba3cbf3dSdan} {1 {database disk image is malformed}}
1848c8ce3972Sdandb close
1849c8ce3972Sdan
1850ba3cbf3dSdando_test pager1-18.6 {
1851ba3cbf3dSdan  faultsim_delete_and_reopen
1852ba3cbf3dSdan  db func a_string a_string
1853ba3cbf3dSdan  execsql {
1854ba3cbf3dSdan    PRAGMA page_size = 1024;
1855ba3cbf3dSdan    CREATE TABLE t1(x);
1856ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1857ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1858ba3cbf3dSdan  }
1859ba3cbf3dSdan
1860ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1861ba3cbf3dSdan  db close
1862ba3cbf3dSdan
1863ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1864ba3cbf3dSdan  sqlite3 db test.db
1865ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1866ba3cbf3dSdan} {1 {database disk image is malformed}}
1867f4ba1093Sdan}
1868ba3cbf3dSdan
1869ba3cbf3dSdando_test pager1-19.1 {
1870ba3cbf3dSdan  sqlite3 db ""
1871ba3cbf3dSdan  db func a_string a_string
1872ba3cbf3dSdan  execsql {
1873ba3cbf3dSdan    PRAGMA page_size = 512;
1874ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1875ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1876ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1877ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1878ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1879ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1880ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1881ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1882ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1883ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1884ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1885ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1886ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1887ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1888ba3cbf3dSdan    );
1889ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1890ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1891ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1892ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1893ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1894ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1895ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1896ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1897ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1898ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1899ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1900ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1901ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1902ba3cbf3dSdan    );
1903ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
1904ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
1905ba3cbf3dSdan    VACUUM;
1906ba3cbf3dSdan  }
1907ba3cbf3dSdan} {}
1908ba3cbf3dSdan
19096b63ab47Sdan#-------------------------------------------------------------------------
19106b63ab47Sdan# Test a couple of special cases that come up while committing
19116b63ab47Sdan# transactions:
19126b63ab47Sdan#
19136b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
19146b63ab47Sdan#                  database has not been modified at all.
19156b63ab47Sdan#
19166b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
19176b63ab47Sdan#
19186b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
19196b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
19206b63ab47Sdan#                  disk before the commit.
19216b63ab47Sdan#
19226b63ab47Sdando_test pager1-20.1.1 {
19236b63ab47Sdan  catch {db close}
19246b63ab47Sdan  sqlite3 db :memory:
19256b63ab47Sdan  execsql {
19266b63ab47Sdan    CREATE TABLE one(two, three);
19276b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19286b63ab47Sdan  }
19296b63ab47Sdan} {}
19306b63ab47Sdando_test pager1-20.1.2 {
19316b63ab47Sdan  execsql {
19326b63ab47Sdan    BEGIN EXCLUSIVE;
19336b63ab47Sdan    COMMIT;
19346b63ab47Sdan  }
19356b63ab47Sdan} {}
19366b63ab47Sdan
19376b63ab47Sdando_test pager1-20.2.1 {
19386b63ab47Sdan  faultsim_delete_and_reopen
19396b63ab47Sdan  execsql {
19406b63ab47Sdan    PRAGMA locking_mode = exclusive;
19416b63ab47Sdan    PRAGMA journal_mode = persist;
19426b63ab47Sdan    CREATE TABLE one(two, three);
19436b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19446b63ab47Sdan  }
19456b63ab47Sdan} {exclusive persist}
19466b63ab47Sdando_test pager1-20.2.2 {
19476b63ab47Sdan  execsql {
19486b63ab47Sdan    BEGIN EXCLUSIVE;
19496b63ab47Sdan    COMMIT;
19506b63ab47Sdan  }
19516b63ab47Sdan} {}
19526b63ab47Sdan
19539091f775Sshanehifcapable wal {
19546b63ab47Sdan  do_test pager1-20.3.1 {
19556b63ab47Sdan    faultsim_delete_and_reopen
19566b63ab47Sdan    db func a_string a_string
19576b63ab47Sdan    execsql {
19586b63ab47Sdan      PRAGMA cache_size = 10;
19596b63ab47Sdan      PRAGMA journal_mode = wal;
19606b63ab47Sdan      BEGIN;
19616b63ab47Sdan        CREATE TABLE t1(x);
19626b63ab47Sdan        CREATE TABLE t2(y);
19636b63ab47Sdan        INSERT INTO t1 VALUES(a_string(800));
19646b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
19656b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
19666b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
19676b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
19686b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
19696b63ab47Sdan      COMMIT;
19706b63ab47Sdan    }
19716b63ab47Sdan  } {wal}
19726b63ab47Sdan  do_test pager1-20.3.2 {
19736b63ab47Sdan    execsql {
19746b63ab47Sdan      BEGIN;
19756b63ab47Sdan      INSERT INTO t2 VALUES('xxxx');
19766b63ab47Sdan    }
1977c396d4afSdan    recursive_select 32 t1
19786b63ab47Sdan    execsql COMMIT
19796b63ab47Sdan  } {}
19809091f775Sshaneh}
19816b63ab47Sdan
198289ccf448Sdan#-------------------------------------------------------------------------
198389ccf448Sdan# Test that a WAL database may not be opened if:
198489ccf448Sdan#
198589ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
198689ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
198789ccf448Sdan#
19889091f775Sshanehifcapable wal {
198989ccf448Sdan  do_test pager1-21.0 {
199089ccf448Sdan    faultsim_delete_and_reopen
199189ccf448Sdan    execsql {
199289ccf448Sdan      PRAGMA journal_mode = WAL;
199389ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
199489ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
199589ccf448Sdan    }
199689ccf448Sdan  } {wal}
199789ccf448Sdan  do_test pager1-21.1 {
199889ccf448Sdan    testvfs tv -noshm 1
199989ccf448Sdan    sqlite3 db2 test.db -vfs tv
200089ccf448Sdan    catchsql { SELECT * FROM ko } db2
200189ccf448Sdan  } {1 {unable to open database file}}
200289ccf448Sdan  db2 close
200389ccf448Sdan  tv delete
200489ccf448Sdan  do_test pager1-21.2 {
200589ccf448Sdan    testvfs tv -iversion 1
200689ccf448Sdan    sqlite3 db2 test.db -vfs tv
200789ccf448Sdan    catchsql { SELECT * FROM ko } db2
200889ccf448Sdan  } {1 {unable to open database file}}
200989ccf448Sdan  db2 close
201089ccf448Sdan  tv delete
20119091f775Sshaneh}
201289ccf448Sdan
201389ccf448Sdan#-------------------------------------------------------------------------
201489ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
201589ccf448Sdan#
201689ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
201789ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
201889ccf448Sdan#
20195209132aSdanifcapable wal {
202089ccf448Sdan  do_test pager1-22.1.1 {
202189ccf448Sdan    faultsim_delete_and_reopen
202289ccf448Sdan    execsql {
202389ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
202489ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
202589ccf448Sdan    }
202689ccf448Sdan    execsql { PRAGMA wal_checkpoint }
2027bdd9af0fSdan  } {0 -1 -1}
202889ccf448Sdan  do_test pager1-22.2.1 {
202989ccf448Sdan    testvfs tv -default 1
203089ccf448Sdan    tv filter xSync
203189ccf448Sdan    tv script xSyncCb
203289ccf448Sdan    proc xSyncCb {args} {incr ::synccount}
203389ccf448Sdan    set ::synccount 0
203489ccf448Sdan    sqlite3 db test.db
203589ccf448Sdan    execsql {
203689ccf448Sdan      PRAGMA synchronous = off;
203789ccf448Sdan      PRAGMA journal_mode = WAL;
203889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
203989ccf448Sdan    }
204089ccf448Sdan    execsql { PRAGMA wal_checkpoint }
204189ccf448Sdan    set synccount
204289ccf448Sdan  } {0}
204389ccf448Sdan  db close
204489ccf448Sdan  tv delete
20455209132aSdan}
204689ccf448Sdan
204789ccf448Sdan#-------------------------------------------------------------------------
204889ccf448Sdan# Tests for changing journal mode.
204989ccf448Sdan#
205089ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
205189ccf448Sdan#                  the journal file is deleted.
205289ccf448Sdan#
205389ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
205489ccf448Sdan#                  on the database file.
205589ccf448Sdan#
205689ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
205789ccf448Sdan#                  on the database file.
205889ccf448Sdan#
205989ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
206089ccf448Sdan#
206189ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
206289ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
206389ccf448Sdan#
2064d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
2065d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
2066d0b0d4dcSdan#                  locking_mode=exclusive).
2067d0b0d4dcSdan#
206889ccf448Sdando_test pager1-23.1.1 {
206989ccf448Sdan  faultsim_delete_and_reopen
207089ccf448Sdan  execsql {
207189ccf448Sdan    PRAGMA journal_mode = PERSIST;
207289ccf448Sdan    CREATE TABLE t1(a, b);
207389ccf448Sdan  }
207489ccf448Sdan  file exists test.db-journal
207589ccf448Sdan} {1}
207689ccf448Sdando_test pager1-23.1.2 {
207789ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
207889ccf448Sdan  file exists test.db-journal
207989ccf448Sdan} {0}
208089ccf448Sdan
208189ccf448Sdando_test pager1-23.2.1 {
208289ccf448Sdan  execsql {
208389ccf448Sdan    PRAGMA journal_mode = PERSIST;
208489ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
208589ccf448Sdan  }
208689ccf448Sdan  db eval { SELECT * FROM t1 } {
208789ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
208889ccf448Sdan  }
208989ccf448Sdan  execsql { PRAGMA journal_mode }
209089ccf448Sdan} {delete}
209189ccf448Sdando_test pager1-23.2.2 {
209289ccf448Sdan  file exists test.db-journal
209389ccf448Sdan} {0}
209489ccf448Sdan
209589ccf448Sdando_test pager1-23.3.1 {
209689ccf448Sdan  execsql {
209789ccf448Sdan    PRAGMA journal_mode = PERSIST;
209889ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
209989ccf448Sdan    BEGIN IMMEDIATE;
210089ccf448Sdan  }
210189ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
210289ccf448Sdan  execsql { PRAGMA journal_mode }
210389ccf448Sdan} {delete}
210489ccf448Sdando_test pager1-23.3.2 {
210589ccf448Sdan  file exists test.db-journal
210689ccf448Sdan} {0}
210789ccf448Sdando_test pager1-23.3.3 {
210889ccf448Sdan  execsql COMMIT
210989ccf448Sdan} {}
211089ccf448Sdan
211189ccf448Sdando_test pager1-23.4.1 {
211289ccf448Sdan  execsql {
211389ccf448Sdan    PRAGMA journal_mode = PERSIST;
211489ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
211589ccf448Sdan    BEGIN EXCLUSIVE;
211689ccf448Sdan  }
211789ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
211889ccf448Sdan  execsql { PRAGMA journal_mode }
211989ccf448Sdan} {delete}
212089ccf448Sdando_test pager1-23.4.2 {
212189ccf448Sdan  file exists test.db-journal
212289ccf448Sdan} {0}
212389ccf448Sdando_test pager1-23.4.3 {
212489ccf448Sdan  execsql COMMIT
212589ccf448Sdan} {}
212689ccf448Sdan
212789ccf448Sdando_test pager1-23.5.1 {
212889ccf448Sdan  faultsim_delete_and_reopen
212989ccf448Sdan  sqlite3 db :memory:
213089ccf448Sdan} {}
213189ccf448Sdanforeach {tn mode possible} {
213289ccf448Sdan  2  off      1
213389ccf448Sdan  3  memory   1
213489ccf448Sdan  4  persist  0
213589ccf448Sdan  5  delete   0
213689ccf448Sdan  6  wal      0
213789ccf448Sdan  7  truncate 0
213889ccf448Sdan} {
213989ccf448Sdan  do_test pager1-23.5.$tn.1 {
214089ccf448Sdan    execsql "PRAGMA journal_mode = off"
214189ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
214289ccf448Sdan  } [if $possible {list $mode} {list off}]
214389ccf448Sdan  do_test pager1-23.5.$tn.2 {
214489ccf448Sdan    execsql "PRAGMA journal_mode = memory"
214589ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
214689ccf448Sdan  } [if $possible {list $mode} {list memory}]
214789ccf448Sdan}
2148d0b0d4dcSdando_test pager1-23.6.1 {
214989ccf448Sdan  execsql {PRAGMA locking_mode = normal}
215089ccf448Sdan} {exclusive}
2151d0b0d4dcSdando_test pager1-23.6.2 {
215289ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
215389ccf448Sdan} {exclusive}
2154d0b0d4dcSdando_test pager1-23.6.3 {
215589ccf448Sdan  execsql {PRAGMA locking_mode}
215689ccf448Sdan} {exclusive}
2157d0b0d4dcSdando_test pager1-23.6.4 {
215889ccf448Sdan  execsql {PRAGMA main.locking_mode}
215989ccf448Sdan} {exclusive}
21606b63ab47Sdan
2161d0b0d4dcSdan#-------------------------------------------------------------------------
2162d0b0d4dcSdan#
2163d0b0d4dcSdando_test pager1-24.1.1 {
2164d0b0d4dcSdan  faultsim_delete_and_reopen
2165d0b0d4dcSdan  db func a_string a_string
2166d0b0d4dcSdan  execsql {
2167d0b0d4dcSdan    PRAGMA cache_size = 10;
2168d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2169d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2170d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2171d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2172d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2173d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2174d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2175d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2176d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2177d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2178d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2179d0b0d4dcSdan  }
2180d0b0d4dcSdan} {}
2181d0b0d4dcSdando_test pager1-24.1.2 {
2182d0b0d4dcSdan  execsql {
2183d0b0d4dcSdan    BEGIN;
2184d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2185d0b0d4dcSdan  }
2186c396d4afSdan  recursive_select 64 x2
2187d0b0d4dcSdan} {}
2188d0b0d4dcSdando_test pager1-24.1.3 {
2189d0b0d4dcSdan  execsql {
2190d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2191d0b0d4dcSdan    COMMIT;
2192d0b0d4dcSdan    PRAGMA integrity_check;
2193d0b0d4dcSdan    SELECT count(*) FROM x1;
2194d0b0d4dcSdan  }
2195d0b0d4dcSdan} {ok 33}
2196d0b0d4dcSdan
2197d0b0d4dcSdando_test pager1-24.1.4 {
2198d0b0d4dcSdan  execsql {
2199d0b0d4dcSdan    DELETE FROM x1;
2200d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2201d0b0d4dcSdan    BEGIN;
2202d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2203d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2204d0b0d4dcSdan  }
2205c396d4afSdan  recursive_select 64 x2 {db eval COMMIT}
2206d0b0d4dcSdan  execsql {
2207d0b0d4dcSdan    PRAGMA integrity_check;
2208d0b0d4dcSdan    SELECT count(*) FROM x1;
2209d0b0d4dcSdan  }
2210d0b0d4dcSdan} {ok 33}
2211d0b0d4dcSdan
2212d0b0d4dcSdando_test pager1-24.1.5 {
2213d0b0d4dcSdan  execsql {
2214d0b0d4dcSdan    DELETE FROM x1;
2215d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2216d0b0d4dcSdan  }
2217c396d4afSdan  recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
2218d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2219d0b0d4dcSdan} {}
2220d0b0d4dcSdan
2221d0b0d4dcSdan#-------------------------------------------------------------------------
2222d0b0d4dcSdan#
2223d0b0d4dcSdando_test pager1-25-1 {
2224d0b0d4dcSdan  faultsim_delete_and_reopen
2225d0b0d4dcSdan  execsql {
2226d0b0d4dcSdan    BEGIN;
2227d0b0d4dcSdan      SAVEPOINT abc;
2228d0b0d4dcSdan        CREATE TABLE t1(a, b);
2229d0b0d4dcSdan      ROLLBACK TO abc;
2230d0b0d4dcSdan    COMMIT;
2231d0b0d4dcSdan  }
2232d0b0d4dcSdan  db close
2233d0b0d4dcSdan} {}
2234d0b0d4dcSdanbreakpoint
2235d0b0d4dcSdando_test pager1-25-2 {
2236d0b0d4dcSdan  faultsim_delete_and_reopen
2237d0b0d4dcSdan  execsql {
2238d0b0d4dcSdan    SAVEPOINT abc;
2239d0b0d4dcSdan      CREATE TABLE t1(a, b);
2240d0b0d4dcSdan    ROLLBACK TO abc;
2241d0b0d4dcSdan    COMMIT;
2242d0b0d4dcSdan  }
2243d0b0d4dcSdan  db close
2244d0b0d4dcSdan} {}
22456b63ab47Sdan
2246c396d4afSdan#-------------------------------------------------------------------------
2247c396d4afSdan# Sector-size tests.
2248c396d4afSdan#
2249c396d4afSdando_test pager1-26.1 {
2250c396d4afSdan  testvfs tv -default 1
2251c396d4afSdan  tv sectorsize 4096
2252c396d4afSdan  faultsim_delete_and_reopen
2253c396d4afSdan  db func a_string a_string
2254c396d4afSdan  execsql {
2255c396d4afSdan    PRAGMA page_size = 512;
2256c396d4afSdan    CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
2257c396d4afSdan    BEGIN;
2258c396d4afSdan      INSERT INTO tbl VALUES(a_string(25), a_string(600));
2259c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2260c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2261c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2262c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2263c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2264c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2265c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2266c396d4afSdan    COMMIT;
2267c396d4afSdan  }
2268c396d4afSdan} {}
2269c396d4afSdando_execsql_test pager1-26.1 {
2270c396d4afSdan  UPDATE tbl SET b = a_string(550);
2271c396d4afSdan} {}
2272c396d4afSdandb close
2273c396d4afSdantv delete
2274c396d4afSdan
2275c396d4afSdan#-------------------------------------------------------------------------
227622b328b2Sdan#
2277c396d4afSdando_test pager1.27.1 {
2278c396d4afSdan  faultsim_delete_and_reopen
2279c396d4afSdan  sqlite3_pager_refcounts db
2280c396d4afSdan  execsql {
2281c396d4afSdan    BEGIN;
2282c396d4afSdan      CREATE TABLE t1(a, b);
2283c396d4afSdan  }
2284c396d4afSdan  sqlite3_pager_refcounts db
2285c396d4afSdan  execsql COMMIT
2286c396d4afSdan} {}
2287c396d4afSdan
228822b328b2Sdan#-------------------------------------------------------------------------
228922b328b2Sdan# Test that attempting to open a write-transaction with
229022b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on
229122b328b2Sdan# the same database.
229222b328b2Sdan#
229322b328b2Sdancatch { db close }
22949091f775Sshanehifcapable wal {
229522b328b2Sdan  do_multiclient_test tn {
229622b328b2Sdan    do_test pager1-28.$tn.1 {
229722b328b2Sdan      sql1 {
229822b328b2Sdan        PRAGMA journal_mode = WAL;
229922b328b2Sdan        CREATE TABLE t1(a, b);
230022b328b2Sdan        INSERT INTO t1 VALUES('a', 'b');
230122b328b2Sdan      }
230222b328b2Sdan    } {wal}
230322b328b2Sdan    do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
230422b328b2Sdan
230522b328b2Sdan    do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
230622b328b2Sdan    do_test pager1-28.$tn.4 {
230722b328b2Sdan      csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
230822b328b2Sdan    } {1 {database is locked}}
230922b328b2Sdan    code2 { db2 close ; sqlite3 db2 test.db }
231022b328b2Sdan    do_test pager1-28.$tn.4 {
231122b328b2Sdan      sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
231222b328b2Sdan    } {}
231322b328b2Sdan  }
23149091f775Sshaneh}
23155653e4daSdan
23165653e4daSdan#-------------------------------------------------------------------------
23175653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager
23185653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a
23195653e4daSdan# RESERVED lock on the database file, this step is skipped.
23205653e4daSdan#
23215653e4daSdando_multiclient_test tn {
23225653e4daSdan  do_test pager1-28.$tn.1 {
23235653e4daSdan    sql1 {
23245653e4daSdan      PRAGMA journal_mode = PERSIST;
23255653e4daSdan      CREATE TABLE t1(a, b);
23265653e4daSdan      INSERT INTO t1 VALUES('a', 'b');
23275653e4daSdan    }
23285653e4daSdan  } {persist}
23295653e4daSdan  do_test pager1-28.$tn.2 { file exists test.db-journal } 1
23305653e4daSdan  do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
23315653e4daSdan  do_test pager1-28.$tn.4 { file exists test.db-journal } 0
23325653e4daSdan
23335653e4daSdan  do_test pager1-28.$tn.5 {
23345653e4daSdan    sql1 {
23355653e4daSdan      PRAGMA journal_mode = PERSIST;
23365653e4daSdan      INSERT INTO t1 VALUES('c', 'd');
23375653e4daSdan    }
23385653e4daSdan  } {persist}
23395653e4daSdan  do_test pager1-28.$tn.6 { file exists test.db-journal } 1
23405653e4daSdan  do_test pager1-28.$tn.7 {
23415653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
23425653e4daSdan  } {}
23435653e4daSdan  do_test pager1-28.$tn.8  { file exists test.db-journal } 1
23445653e4daSdan  do_test pager1-28.$tn.9  { sql1 { PRAGMA journal_mode = DELETE } } delete
23455653e4daSdan  do_test pager1-28.$tn.10 { file exists test.db-journal } 1
23465653e4daSdan
23475653e4daSdan  do_test pager1-28.$tn.11 { sql2 COMMIT } {}
23485653e4daSdan  do_test pager1-28.$tn.12 { file exists test.db-journal } 0
23495653e4daSdan
23505653e4daSdan  do_test pager1-28-$tn.13 {
23515653e4daSdan    code1 { set channel [db incrblob -readonly t1 a 2] }
23525653e4daSdan    sql1 {
23535653e4daSdan      PRAGMA journal_mode = PERSIST;
23545653e4daSdan      INSERT INTO t1 VALUES('g', 'h');
23555653e4daSdan    }
23565653e4daSdan  } {persist}
23575653e4daSdan  do_test pager1-28.$tn.14 { file exists test.db-journal } 1
23585653e4daSdan  do_test pager1-28.$tn.15 {
23595653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
23605653e4daSdan  } {}
23615653e4daSdan  do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
23625653e4daSdan  do_test pager1-28.$tn.17 { file exists test.db-journal } 1
23635653e4daSdan
23645653e4daSdan  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
23655653e4daSdan  do_test pager1-28-$tn.18 { code1 { read $channel } } c
23665653e4daSdan  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
23675653e4daSdan  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
23685653e4daSdan}
23695653e4daSdan
23701879b088Sdando_test pager1-29.1 {
23711879b088Sdan  faultsim_delete_and_reopen
23721879b088Sdan  execsql {
23731879b088Sdan    PRAGMA page_size = 1024;
23741879b088Sdan    PRAGMA auto_vacuum = full;
23751879b088Sdan    PRAGMA locking_mode=exclusive;
23761879b088Sdan    CREATE TABLE t1(a, b);
23771879b088Sdan    INSERT INTO t1 VALUES(1, 2);
23781879b088Sdan  }
23791879b088Sdan  file size test.db
23801879b088Sdan} [expr 1024*3]
23811879b088Sdando_test pager1-29.2 {
23821879b088Sdan  execsql {
23831879b088Sdan    PRAGMA page_size = 4096;
23841879b088Sdan    VACUUM;
23851879b088Sdan  }
23861879b088Sdan  file size test.db
23871879b088Sdan} [expr 4096*3]
23881879b088Sdan
2389e08c2066Sdan#-------------------------------------------------------------------------
2390e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in
2391e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system
2392e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while
2393e08c2066Sdan# doing this is not released.
2394e08c2066Sdan#
2395e08c2066Sdando_test pager1-30.1 {
2396e08c2066Sdan  db close
2397fda06befSmistachkin  delete_file test.db
2398fda06befSmistachkin  delete_file test.db-journal
2399e08c2066Sdan  set fd [open test.db-journal w]
2400e08c2066Sdan  seek $fd [expr 512+1032*2]
2401e08c2066Sdan  puts -nonewline $fd x
2402e08c2066Sdan  close $fd
2403e08c2066Sdan
2404e08c2066Sdan  sqlite3 db test.db
2405e08c2066Sdan  execsql {
2406e08c2066Sdan    PRAGMA locking_mode=EXCLUSIVE;
2407e08c2066Sdan    SELECT count(*) FROM sqlite_master;
2408e08c2066Sdan    PRAGMA lock_status;
2409e08c2066Sdan  }
2410e08c2066Sdan} {exclusive 0 main reserved temp closed}
2411e08c2066Sdan
2412e08c2066Sdan#-------------------------------------------------------------------------
2413e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal
2414e08c2066Sdan# file can still be rolled back. This is required for backward compatibility -
2415e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero.
2416e08c2066Sdan#
241733f5379cSdanif {$tcl_platform(platform)=="unix"} {
2418e08c2066Sdando_test pager1-31.1 {
2419e08c2066Sdan  faultsim_delete_and_reopen
2420e08c2066Sdan  execsql {
2421e08c2066Sdan    PRAGMA cache_size = 10;
2422e08c2066Sdan    PRAGMA page_size = 1024;
2423e08c2066Sdan    CREATE TABLE t1(x, y, UNIQUE(x, y));
2424e08c2066Sdan    INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
2425e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2426e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2427e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2428e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2429e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2430e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2431e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2432e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2433e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2434e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2435e08c2066Sdan    BEGIN;
2436e08c2066Sdan      UPDATE t1 SET y = randomblob(1499);
2437e08c2066Sdan  }
2438fda06befSmistachkin  copy_file test.db test.db2
2439fda06befSmistachkin  copy_file test.db-journal test.db2-journal
2440e08c2066Sdan
2441e08c2066Sdan  hexio_write test.db2-journal 24 00000000
2442e08c2066Sdan  sqlite3 db2 test.db2
2443e08c2066Sdan  execsql { PRAGMA integrity_check } db2
2444e08c2066Sdan} {ok}
244533f5379cSdan}
2446e08c2066Sdan
244731e80976Sdrh#-------------------------------------------------------------------------
244831e80976Sdrh# Test that a database file can be "pre-hinted" to a certain size and that
244931e80976Sdrh# subsequent spilling of the pager cache does not result in the database
245031e80976Sdrh# file being shrunk.
245131e80976Sdrh#
245231e80976Sdrhcatch {db close}
245331e80976Sdrhforcedelete test.db
245431e80976Sdrh
245531e80976Sdrhdo_test pager1-32.1 {
245631e80976Sdrh  sqlite3 db test.db
245731e80976Sdrh  execsql {
245831e80976Sdrh    CREATE TABLE t1(x, y);
245931e80976Sdrh  }
246031e80976Sdrh  db close
246131e80976Sdrh  sqlite3 db test.db
246231e80976Sdrh  execsql {
246331e80976Sdrh    BEGIN;
246431e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
246531e80976Sdrh  }
24662f7820d8Sdrh  file_control_chunksize_test db main 1024
246731e80976Sdrh  file_control_sizehint_test db main 20971520; # 20MB
246831e80976Sdrh  execsql {
246931e80976Sdrh    PRAGMA cache_size = 10;
247031e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
247131e80976Sdrh    INSERT INTO t1 VALUES(2, randomblob(10000));
247231e80976Sdrh    INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
247331e80976Sdrh    INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
247431e80976Sdrh    INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
247531e80976Sdrh    INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
247631e80976Sdrh    SELECT count(*) FROM t1;
247731e80976Sdrh    COMMIT;
247831e80976Sdrh  }
247931e80976Sdrh  db close
248031e80976Sdrh  file size test.db
248131e80976Sdrh} {20971520}
248231e80976Sdrh
248331e80976Sdrh# Cleanup 20MB file left by the previous test.
248431e80976Sdrhforcedelete test.db
24855653e4daSdan
2486d353331aSdanfinish_test
2487