xref: /sqlite-3.40.0/test/pager1.test (revision 9fc5b4a5)
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"
5733f111dcSdrh#              (The omit_readlock pragma has been removed and so have
5833f111dcSdrh#              these tests.)
59c8ce3972Sdan#
60c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree
61c8ce3972Sdan#              requests an invalid page number (due to db corruption).
62c8ce3972Sdan#
63b0ac3e3aSdan
64c396d4afSdanproc recursive_select {id table {script {}}} {
65c396d4afSdan  set cnt 0
66c396d4afSdan  db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
67c396d4afSdan    recursive_select $rowid $table $script
68c396d4afSdan    incr cnt
69c396d4afSdan  }
70c396d4afSdan  if {$cnt==0} { eval $script }
71c396d4afSdan}
72c396d4afSdan
7353f04f3bSdanset a_string_counter 1
7453f04f3bSdanproc a_string {n} {
7553f04f3bSdan  global a_string_counter
7653f04f3bSdan  incr a_string_counter
7753f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
7853f04f3bSdan}
7953f04f3bSdandb func a_string a_string
8053f04f3bSdan
81a4a9095eSdando_multiclient_test tn {
82e91a54e1Sdan
83e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
84e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
85e91a54e1Sdan  #
86e91a54e1Sdan  do_test pager1-$tn.1 {
87e91a54e1Sdan    sql1 {
88e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
89e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
90d353331aSdan      INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
91e91a54e1Sdan    }
92e91a54e1Sdan  } {}
93e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
94e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
95e91a54e1Sdan
96e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
97e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
98e91a54e1Sdan  # read the database content as it was before the transaction was
99e91a54e1Sdan  # opened. [db] should see the inserted row.
100e91a54e1Sdan  #
101e91a54e1Sdan  do_test pager1-$tn.4 {
102e91a54e1Sdan    sql1 {
103e91a54e1Sdan      BEGIN;
104e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
105e91a54e1Sdan    }
106e91a54e1Sdan  } {}
107e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
108e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
109e91a54e1Sdan
110e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
111e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
112e91a54e1Sdan  #
113e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
114e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
115e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
116e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
117e91a54e1Sdan  #
118e91a54e1Sdan  do_test pager1-$tn.8 {
119e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
120e91a54e1Sdan  } {1 {database is locked}}
121e91a54e1Sdan  do_test pager1-$tn.9 {
122e91a54e1Sdan    csql2 {
123e91a54e1Sdan      BEGIN;
124e91a54e1Sdan      UPDATE t1 SET a = a + 10;
125e91a54e1Sdan    }
126e91a54e1Sdan  } {1 {database is locked}}
127e91a54e1Sdan
128e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
129e91a54e1Sdan  # now see the new database content.
130e91a54e1Sdan  #
131e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
132e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
133e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
134e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
135e91a54e1Sdan
136e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
137e91a54e1Sdan  # after the attempt to write the database failed.
138e91a54e1Sdan  #
139e91a54e1Sdan  do_test pager1-$tn.14 {
140e91a54e1Sdan    csql2 { BEGIN }
141e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
142e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
143e91a54e1Sdan
144e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
145e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
146e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
147e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
148e91a54e1Sdan  #
149e91a54e1Sdan  do_test pager1-$tn.15 {
150e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
151e91a54e1Sdan  } {1 one 2 two 3 three}
152e91a54e1Sdan  do_test pager1-$tn.16 {
153e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
154e91a54e1Sdan  } {1 {database is locked}}
155e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
156e91a54e1Sdan
157e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
158e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
159e91a54e1Sdan  # the SHARED lock [db2] is holding.
160e91a54e1Sdan  #
161e91a54e1Sdan  do_test pager1-$tn.18 {
162e91a54e1Sdan    sql1 {
163e91a54e1Sdan      BEGIN;
164e91a54e1Sdan      UPDATE t1 SET a = a + 10;
165e91a54e1Sdan    }
166e91a54e1Sdan  } {}
167e91a54e1Sdan  do_test pager1-$tn-19 {
168e91a54e1Sdan    sql1 { PRAGMA lock_status }
169e91a54e1Sdan  } {main reserved temp closed}
170e91a54e1Sdan  do_test pager1-$tn-20 {
171e91a54e1Sdan    sql2 { PRAGMA lock_status }
172e91a54e1Sdan  } {main shared temp closed}
173e91a54e1Sdan
174e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
175e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
176e91a54e1Sdan  #
177e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
178e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
179e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
180e91a54e1Sdan
181e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
182e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
183e91a54e1Sdan  # upgrades to a PENDING lock.
184e91a54e1Sdan  #
185e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
186e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
187e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
188e91a54e1Sdan  # the database.
189e91a54e1Sdan  #
190e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
191e91a54e1Sdan  do_test pager1-$tn-25 {
192e91a54e1Sdan    sql1 { PRAGMA lock_status }
193e91a54e1Sdan  } {main pending temp closed}
194e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
195e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
196e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
197e91a54e1Sdan
198e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
199e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
200e91a54e1Sdan  # is still holding a PENDING).
201e91a54e1Sdan  #
202e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
203e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
204e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
205e91a54e1Sdan
206e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
207e91a54e1Sdan  # committed, all three connections can read the new content.
208e91a54e1Sdan  #
209e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
210e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
211e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
212e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
213e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
214d353331aSdan
215d353331aSdan  # Install a busy-handler for connection [db].
216d353331aSdan  #
217d353331aSdan  set ::nbusy [list]
218d353331aSdan  proc busy {n} {
219d353331aSdan    lappend ::nbusy $n
220d353331aSdan    if {$n>5} { sql2 COMMIT }
221d353331aSdan    return 0
222d353331aSdan  }
223d353331aSdan  db busy busy
224d353331aSdan
225d353331aSdan  do_test pager1-$tn.29 {
226d353331aSdan    sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
227d353331aSdan  } {}
228d353331aSdan  do_test pager1-$tn.30 {
229d353331aSdan    sql2 { BEGIN ; SELECT * FROM t1 }
230d353331aSdan  } {21 one 22 two 23 three}
231d353331aSdan  do_test pager1-$tn.31 { sql1 COMMIT } {}
232d353331aSdan  do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
233e91a54e1Sdan}
234e91a54e1Sdan
23553f04f3bSdan#-------------------------------------------------------------------------
23653f04f3bSdan# Savepoint related test cases.
23753f04f3bSdan#
238dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
239dca321aeSdan#                 to grow.
240dca321aeSdan#
241273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
242273f3f0dSdan#                 of a savepoint rollback.
243273f3f0dSdan#
2440e986f51Sdando_test pager1-3.1.1 {
245b0ac3e3aSdan  faultsim_delete_and_reopen
246b0ac3e3aSdan  execsql {
247b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
248b0ac3e3aSdan    CREATE TABLE counter(
249b0ac3e3aSdan      i CHECK (i<5),
250b0ac3e3aSdan      u CHECK (u<10)
251b0ac3e3aSdan    );
252b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
253b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
254b0ac3e3aSdan      UPDATE counter SET i = i+1;
255b0ac3e3aSdan    END;
256b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
257b0ac3e3aSdan      UPDATE counter SET u = u+1;
258b0ac3e3aSdan    END;
259b0ac3e3aSdan  }
260b0ac3e3aSdan  execsql { SELECT * FROM counter }
261b0ac3e3aSdan} {0 0}
262b0ac3e3aSdan
2630e986f51Sdando_execsql_test pager1-3.1.2 {
264d353331aSdan  PRAGMA cache_size = 10;
265b0ac3e3aSdan  BEGIN;
266b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
267b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
268b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
269b0ac3e3aSdan    SELECT * FROM counter;
270b0ac3e3aSdan} {3 0}
2710e986f51Sdando_catchsql_test pager1-3.1.3 {
272b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
273b0ac3e3aSdan} {1 {constraint failed}}
274b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
275b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
276b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
277b0ac3e3aSdan
278273f3f0dSdanforeach {tn sql tcl} {
279d353331aSdan  7  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
280273f3f0dSdan    testvfs tv -default 1
281273f3f0dSdan    tv devchar safe_append
282273f3f0dSdan  }
283d353331aSdan  8  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
284d353331aSdan    testvfs tv -default 1
285d353331aSdan    tv devchar sequential
286d353331aSdan  }
287d353331aSdan  9  { PRAGMA synchronous = FULL } { }
288d353331aSdan  10 { PRAGMA synchronous = NORMAL } { }
289d353331aSdan  11 { PRAGMA synchronous = OFF } { }
290d353331aSdan  12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
291d353331aSdan  13 { PRAGMA synchronous = FULL } {
292d353331aSdan    testvfs tv -default 1
293d353331aSdan    tv devchar sequential
294d353331aSdan  }
2956b63ab47Sdan  14 { PRAGMA locking_mode = EXCLUSIVE } {
2966b63ab47Sdan  }
297273f3f0dSdan} {
298273f3f0dSdan  do_test pager1-3.$tn.1 {
299273f3f0dSdan    eval $tcl
300dca321aeSdan    faultsim_delete_and_reopen
301dca321aeSdan    db func a_string a_string
302273f3f0dSdan    execsql $sql
303dca321aeSdan    execsql {
304dca321aeSdan      PRAGMA auto_vacuum = 2;
305dca321aeSdan      PRAGMA cache_size = 10;
306dca321aeSdan      CREATE TABLE z(x INTEGER PRIMARY KEY, y);
307dca321aeSdan      BEGIN;
308dca321aeSdan        INSERT INTO z VALUES(NULL, a_string(800));
309dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
310dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
311dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
312dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
313dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
314dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
315dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
316dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
317dca321aeSdan      COMMIT;
318dca321aeSdan    }
319dca321aeSdan    execsql { PRAGMA auto_vacuum }
320dca321aeSdan  } {2}
321273f3f0dSdan  do_execsql_test pager1-3.$tn.2 {
322dca321aeSdan    BEGIN;
323dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
324dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
325dca321aeSdan      SAVEPOINT one;
326273f3f0dSdan        UPDATE z SET y = NULL WHERE x>256;
327dca321aeSdan        PRAGMA incremental_vacuum;
328dca321aeSdan        SELECT count(*) FROM z WHERE x < 100;
329dca321aeSdan      ROLLBACK TO one;
330dca321aeSdan    COMMIT;
331dca321aeSdan  } {99}
332dca321aeSdan
333273f3f0dSdan  do_execsql_test pager1-3.$tn.3 {
334273f3f0dSdan    BEGIN;
335273f3f0dSdan      SAVEPOINT one;
336273f3f0dSdan        UPDATE z SET y = y||x;
337273f3f0dSdan      ROLLBACK TO one;
338273f3f0dSdan    COMMIT;
339273f3f0dSdan    SELECT count(*) FROM z;
340273f3f0dSdan  } {258}
341273f3f0dSdan
342273f3f0dSdan  do_execsql_test pager1-3.$tn.4 {
343273f3f0dSdan    SAVEPOINT one;
344273f3f0dSdan      UPDATE z SET y = y||x;
345273f3f0dSdan    ROLLBACK TO one;
346273f3f0dSdan  } {}
347273f3f0dSdan  do_execsql_test pager1-3.$tn.5 {
348273f3f0dSdan    SELECT count(*) FROM z;
349273f3f0dSdan    RELEASE one;
350273f3f0dSdan    PRAGMA integrity_check;
351273f3f0dSdan  } {258 ok}
352273f3f0dSdan
35378f1e538Sdan  do_execsql_test pager1-3.$tn.6 {
35478f1e538Sdan    SAVEPOINT one;
35578f1e538Sdan    RELEASE one;
35678f1e538Sdan  } {}
35778f1e538Sdan
358273f3f0dSdan  db close
359273f3f0dSdan  catch { tv delete }
360273f3f0dSdan}
361273f3f0dSdan
36253f04f3bSdan#-------------------------------------------------------------------------
36353f04f3bSdan# Hot journal rollback related test cases.
36453f04f3bSdan#
36553f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
36653f04f3bSdan#               journal files.
36753f04f3bSdan#
36853f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
36953f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
37053f04f3bSdan#               compute) the associated journal is rolled back (and no
37153f04f3bSdan#               xAccess() call to check for the presence of any master
37253f04f3bSdan#               journal file is made).
37353f04f3bSdan#
374de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
375de4996e2Sdan#               page-size or sector-size in the journal header appear to
376de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
377de4996e2Sdan#
378e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
379e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
380e08341c6Sdan#               modes.
381e08341c6Sdan#
382e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
383e08341c6Sdan#               journal-record for which the checksum fails.
384e08341c6Sdan#
385ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
386ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
387ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
388ec6ffc1aSdan#
389c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can
390c8ce3972Sdan#               open it for reading only, the database cannot be accessed and
391c8ce3972Sdan#               SQLITE_CANTOPEN is returned.
392c8ce3972Sdan#
39353f04f3bSdando_test pager1.4.1.1 {
39453f04f3bSdan  faultsim_delete_and_reopen
39553f04f3bSdan  execsql {
39653f04f3bSdan    CREATE TABLE x(y, z);
39753f04f3bSdan    INSERT INTO x VALUES(1, 2);
39853f04f3bSdan  }
39953f04f3bSdan  set fd [open test.db-journal w]
40053f04f3bSdan  puts -nonewline $fd "helloworld"
40153f04f3bSdan  close $fd
40253f04f3bSdan  file exists test.db-journal
40353f04f3bSdan} {1}
40453f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
40553f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
40653f04f3bSdan
40753f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
40853f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
40953f04f3bSdan#
41053f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
41153f04f3bSdan# up the file system to contain two databases, two hot-journal files and
41253f04f3bSdan# a master-journal.
41353f04f3bSdan#
41453f04f3bSdando_test pager1.4.2.1 {
41553f04f3bSdan  testvfs tstvfs -default 1
41653f04f3bSdan  tstvfs filter xDelete
41753f04f3bSdan  tstvfs script xDeleteCallback
41853f04f3bSdan  proc xDeleteCallback {method file args} {
41953f04f3bSdan    set file [file tail $file]
42053f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
42153f04f3bSdan  }
42253f04f3bSdan  faultsim_delete_and_reopen
42353f04f3bSdan  db func a_string a_string
42453f04f3bSdan  execsql {
42553f04f3bSdan    ATTACH 'test.db2' AS aux;
42653f04f3bSdan    PRAGMA journal_mode = DELETE;
42753f04f3bSdan    PRAGMA main.cache_size = 10;
42853f04f3bSdan    PRAGMA aux.cache_size = 10;
42953f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
43053f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
43153f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
43253f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43353f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43453f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
43553f04f3bSdan    BEGIN;
43653f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
43753f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
43853f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
43953f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
44053f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
44153f04f3bSdan    COMMIT;
44253f04f3bSdan  }
44353f04f3bSdan  db close
44453f04f3bSdan  tstvfs delete
44553f04f3bSdan} {}
446b2f20bfcSshaneh
447b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
44853f04f3bSdando_test pager1.4.2.2 {
44953f04f3bSdan  faultsim_restore_and_reopen
45053f04f3bSdan  execsql {
45153f04f3bSdan    SELECT count(*) FROM t1;
45253f04f3bSdan    PRAGMA integrity_check;
45353f04f3bSdan  }
45453f04f3bSdan} {4 ok}
45553f04f3bSdando_test pager1.4.2.3 {
45653f04f3bSdan  faultsim_restore_and_reopen
457fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
45853f04f3bSdan  execsql {
45953f04f3bSdan    SELECT count(*) FROM t1;
46053f04f3bSdan    PRAGMA integrity_check;
46153f04f3bSdan  }
46253f04f3bSdan} {64 ok}
46353f04f3bSdando_test pager1.4.2.4 {
46453f04f3bSdan  faultsim_restore_and_reopen
4650971140bSdrh  hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
46653f04f3bSdan  execsql {
46753f04f3bSdan    SELECT count(*) FROM t1;
46853f04f3bSdan    PRAGMA integrity_check;
46953f04f3bSdan  }
47053f04f3bSdan} {4 ok}
47153f04f3bSdando_test pager1.4.2.5 {
47253f04f3bSdan  faultsim_restore_and_reopen
4730971140bSdrh  hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
474fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
47553f04f3bSdan  execsql {
47653f04f3bSdan    SELECT count(*) FROM t1;
47753f04f3bSdan    PRAGMA integrity_check;
47853f04f3bSdan  }
47953f04f3bSdan} {4 ok}
480b2f20bfcSshaneh}
48153f04f3bSdan
482de4996e2Sdando_test pager1.4.3.1 {
483de4996e2Sdan  testvfs tstvfs -default 1
484de4996e2Sdan  tstvfs filter xSync
485de4996e2Sdan  tstvfs script xSyncCallback
486de4996e2Sdan  proc xSyncCallback {method file args} {
487de4996e2Sdan    set file [file tail $file]
488de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
489de4996e2Sdan  }
490de4996e2Sdan  faultsim_delete_and_reopen
491de4996e2Sdan  execsql {
492de4996e2Sdan    PRAGMA journal_mode = DELETE;
493de4996e2Sdan    CREATE TABLE t1(a, b);
494de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
495de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
496de4996e2Sdan  }
497de4996e2Sdan  db close
498de4996e2Sdan  tstvfs delete
499de4996e2Sdan} {}
500de4996e2Sdan
501de4996e2Sdanforeach {tn ofst value result} {
502de4996e2Sdan          2   20    31       {1 2 3 4}
503de4996e2Sdan          3   20    32       {1 2 3 4}
504de4996e2Sdan          4   20    33       {1 2 3 4}
505de4996e2Sdan          5   20    65536    {1 2 3 4}
506de4996e2Sdan          6   20    131072   {1 2 3 4}
507de4996e2Sdan
508de4996e2Sdan          7   24    511      {1 2 3 4}
509de4996e2Sdan          8   24    513      {1 2 3 4}
510b2eced5dSdrh          9   24    131072   {1 2 3 4}
511de4996e2Sdan
512de4996e2Sdan         10   32    65536    {1 2}
513de4996e2Sdan} {
514de4996e2Sdan  do_test pager1.4.3.$tn {
515de4996e2Sdan    faultsim_restore_and_reopen
516de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
517de4996e2Sdan    execsql { SELECT * FROM t1 }
518de4996e2Sdan  } $result
519de4996e2Sdan}
520de4996e2Sdandb close
521de4996e2Sdan
522e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
523e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
524e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
525e08341c6Sdan# master journal file from the file-system.
526e08341c6Sdan#
5276aa18c95Smistachkinset pwd [get_pwd]
528e08341c6Sdantestvfs tv -default 1
529e08341c6Sdantv script copy_on_mj_delete
530e08341c6Sdanset ::mj_filename_length 0
531e08341c6Sdanproc copy_on_mj_delete {method filename args} {
532e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
533c5484654Smistachkin    #
534c5484654Smistachkin    # NOTE: Is the file name relative?  If so, add the length of the current
535c5484654Smistachkin    #       directory.
536c5484654Smistachkin    #
537c5484654Smistachkin    if {[is_relative_file $filename]} {
538c5484654Smistachkin      set ::mj_filename_length \
539c5484654Smistachkin        [expr {[string length $filename] + [string length $::pwd]}]
540c5484654Smistachkin    } else {
541e08341c6Sdan      set ::mj_filename_length [string length $filename]
542c5484654Smistachkin    }
543e08341c6Sdan    faultsim_save
544e08341c6Sdan  }
545e08341c6Sdan  return SQLITE_OK
546e08341c6Sdan}
547e08341c6Sdan
548e08341c6Sdanforeach {tn1 tcl} {
549e08341c6Sdan  1 { set prefix "test.db" }
550e08341c6Sdan  2 {
551e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
552e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
553e08341c6Sdan    # contains a master-journal pointer so large that it could contain
554e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
555e08341c6Sdan    # make sure SQLite doesn't get confused by this.
556e08341c6Sdan    #
557e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
55833d85c9cSshaneh    if {$tcl_platform(platform)=="windows"} {
55933d85c9cSshaneh      # TBD need to figure out how to do this correctly for Windows!!!
56033d85c9cSshaneh      set nPadding [expr 255 - $::mj_filename_length]
56133d85c9cSshaneh    }
562e08341c6Sdan
563e08341c6Sdan    # We cannot just create a really long database file name to open, as
564e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
565e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
566e08341c6Sdan    # hierarchy to work in.
567e08341c6Sdan    #
568e08341c6Sdan    set dirname "d123456789012345678901234567890/"
569e08341c6Sdan    set nDir [expr $nPadding / 32]
570e08341c6Sdan    if { $nDir } {
571e08341c6Sdan      set p [string repeat $dirname $nDir]
572e08341c6Sdan      file mkdir $p
573e08341c6Sdan      cd $p
574e08341c6Sdan    }
575e08341c6Sdan
576e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
577e08341c6Sdan    set prefix "test.db${padding}"
578e08341c6Sdan  }
579e08341c6Sdan} {
580e08341c6Sdan  eval $tcl
581e08341c6Sdan  foreach {tn2 sql} {
582e08341c6Sdan    o {
583e08341c6Sdan      PRAGMA main.synchronous=OFF;
584e08341c6Sdan      PRAGMA aux.synchronous=OFF;
5853f94b609Sdan      PRAGMA journal_mode = DELETE;
586e08341c6Sdan    }
587e08341c6Sdan    o512 {
588e08341c6Sdan      PRAGMA main.synchronous=OFF;
589e08341c6Sdan      PRAGMA aux.synchronous=OFF;
590e08341c6Sdan      PRAGMA main.page_size = 512;
591e08341c6Sdan      PRAGMA aux.page_size = 512;
5923f94b609Sdan      PRAGMA journal_mode = DELETE;
593e08341c6Sdan    }
594e08341c6Sdan    n {
595e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
596e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
5973f94b609Sdan      PRAGMA journal_mode = DELETE;
598e08341c6Sdan    }
599e08341c6Sdan    f {
600e08341c6Sdan      PRAGMA main.synchronous=FULL;
601e08341c6Sdan      PRAGMA aux.synchronous=FULL;
6023f94b609Sdan      PRAGMA journal_mode = DELETE;
603e08341c6Sdan    }
604e08341c6Sdan  } {
605e08341c6Sdan
606e08341c6Sdan    set tn "${tn1}.${tn2}"
607e08341c6Sdan
608e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
609e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
610e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
611e08341c6Sdan    # file is deleted to commit the transaction.
612e08341c6Sdan    #
613e08341c6Sdan    tv filter xDelete
614e08341c6Sdan    do_test pager1-4.4.$tn.1 {
615e08341c6Sdan      faultsim_delete_and_reopen $prefix
616e08341c6Sdan      execsql "
617e08341c6Sdan        ATTACH '${prefix}2' AS aux;
618e08341c6Sdan        $sql
619e08341c6Sdan        CREATE TABLE a(x);
620e08341c6Sdan        CREATE TABLE aux.b(x);
621e08341c6Sdan        INSERT INTO a VALUES('double-you');
622e08341c6Sdan        INSERT INTO a VALUES('why');
623e08341c6Sdan        INSERT INTO a VALUES('zed');
624e08341c6Sdan        INSERT INTO b VALUES('won');
625e08341c6Sdan        INSERT INTO b VALUES('too');
626e08341c6Sdan        INSERT INTO b VALUES('free');
627e08341c6Sdan      "
628e08341c6Sdan      execsql {
629e08341c6Sdan        BEGIN;
630e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
631e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
632e08341c6Sdan        COMMIT;
633e08341c6Sdan      }
634e08341c6Sdan    } {}
635e08341c6Sdan    tv filter {}
636e08341c6Sdan
637e08341c6Sdan    # Check that the transaction was committed successfully.
638e08341c6Sdan    #
639e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
640e08341c6Sdan      SELECT * FROM a
641e08341c6Sdan    } {double-you why zed won too free}
642e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
643e08341c6Sdan      SELECT * FROM b
644e08341c6Sdan    } {won too free double-you why zed}
645e08341c6Sdan
646e08341c6Sdan    # Restore the file-system and reopen the databases. Check that it now
647e08341c6Sdan    # appears that the transaction was not committed (because the file-system
648e08341c6Sdan    # was restored to the state where it had not been).
649e08341c6Sdan    #
650e08341c6Sdan    do_test pager1-4.4.$tn.4 {
651e08341c6Sdan      faultsim_restore_and_reopen $prefix
652e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
653e08341c6Sdan    } {}
654e08341c6Sdan    do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
655e08341c6Sdan    do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
656e08341c6Sdan
657e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
658e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
659e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
660e08341c6Sdan    #
661e08341c6Sdan    do_test pager1-4.4.$tn.7 {
662e08341c6Sdan      faultsim_restore_and_reopen $prefix
663fda06befSmistachkin      foreach f [glob ${prefix}-mj*] { forcedelete $f }
664e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
665e08341c6Sdan    } {}
666e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
667e08341c6Sdan      SELECT * FROM a
668e08341c6Sdan    } {double-you why zed won too free}
669e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
670e08341c6Sdan      SELECT * FROM b
671e08341c6Sdan    } {won too free double-you why zed}
672e08341c6Sdan  }
673e08341c6Sdan
674e08341c6Sdan  cd $pwd
675e08341c6Sdan}
676e08341c6Sdandb close
677e08341c6Sdantv delete
678fda06befSmistachkinforcedelete $dirname
6790e986f51Sdan
6800e986f51Sdan
6810e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
6820e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
6830e986f51Sdan# two database pages (and page 1 - the change counter).
6840e986f51Sdan#
6850e986f51Sdantestvfs tv -default 1
6860e986f51Sdantv sectorsize 512
6870e986f51Sdantv script copy_on_journal_delete
6880e986f51Sdantv filter xDelete
6890e986f51Sdanproc copy_on_journal_delete {method filename args} {
6900e986f51Sdan  if {[string match *journal $filename]} faultsim_save
6910e986f51Sdan  return SQLITE_OK
6920e986f51Sdan}
6930e986f51Sdanfaultsim_delete_and_reopen
6940e986f51Sdando_execsql_test pager1.4.5.1 {
6953f94b609Sdan  PRAGMA journal_mode = DELETE;
6960e986f51Sdan  PRAGMA page_size = 1024;
6970e986f51Sdan  CREATE TABLE t1(a, b);
6980e986f51Sdan  CREATE TABLE t2(a, b);
6990e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
7000e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
7010e986f51Sdan  BEGIN;
7020e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
7030e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
7040e986f51Sdan  COMMIT;
7053f94b609Sdan} {delete}
7060e986f51Sdantv filter {}
7070e986f51Sdan
7080e986f51Sdan# Check the transaction was committed:
7090e986f51Sdan#
7100e986f51Sdando_execsql_test pager1.4.5.2 {
7110e986f51Sdan  SELECT * FROM t1;
7120e986f51Sdan  SELECT * FROM t2;
7130e986f51Sdan} {I II 1 2 III IV 3 4}
7140e986f51Sdan
715ec6ffc1aSdan# Now try four tests:
7160e986f51Sdan#
7170e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
7180e986f51Sdan#                is rolled back.
7190e986f51Sdan#
7200e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
7210e986f51Sdan#                journal. Check the transaction is not rolled back.
7220e986f51Sdan#
7230e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
7240e986f51Sdan#                journal. Check that the first record in the transaction is
7250e986f51Sdan#                played back, but not the second.
7260e986f51Sdan#
72710f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
72810f5a50eSdan#                readonly connection. This should fail, as a read-only
72910f5a50eSdan#                connection cannot roll back the database file.
73010f5a50eSdan#
7310e986f51Sdanfaultsim_restore_and_reopen
7320e986f51Sdando_execsql_test pager1.4.5.3 {
7330e986f51Sdan  SELECT * FROM t1;
7340e986f51Sdan  SELECT * FROM t2;
7350e986f51Sdan} {I II III IV}
7360e986f51Sdanfaultsim_restore_and_reopen
7370e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
7380e986f51Sdando_execsql_test pager1.4.5.4 {
7390e986f51Sdan  SELECT * FROM t1;
7400e986f51Sdan  SELECT * FROM t2;
7410e986f51Sdan} {I II 1 2 III IV 3 4}
7420e986f51Sdanfaultsim_restore_and_reopen
7430e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
7440e986f51Sdando_execsql_test pager1.4.5.5 {
7450e986f51Sdan  SELECT * FROM t1;
7460e986f51Sdan  SELECT * FROM t2;
7470e986f51Sdan} {I II III IV 3 4}
7480e986f51Sdan
74910f5a50eSdanfaultsim_restore_and_reopen
75010f5a50eSdandb close
75110f5a50eSdansqlite3 db test.db -readonly 1
75210f5a50eSdando_catchsql_test pager1.4.5.6 {
75310f5a50eSdan  SELECT * FROM t1;
75410f5a50eSdan  SELECT * FROM t2;
75510f5a50eSdan} {1 {disk I/O error}}
756ec6ffc1aSdandb close
757ec6ffc1aSdan
758ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
759ec6ffc1aSdan# of the master journal file in $::mj_filename.
760ec6ffc1aSdan#
761ec6ffc1aSdantv script copy_on_mj_delete
762ec6ffc1aSdantv filter xDelete
763ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
764ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
765ec6ffc1aSdan    set ::mj_filename $filename
766ec6ffc1aSdan    faultsim_save
767ec6ffc1aSdan  }
768ec6ffc1aSdan  return SQLITE_OK
769ec6ffc1aSdan}
770ec6ffc1aSdando_test pager1.4.6.1 {
771ec6ffc1aSdan  faultsim_delete_and_reopen
772ec6ffc1aSdan  execsql {
7733f94b609Sdan    PRAGMA journal_mode = DELETE;
774ec6ffc1aSdan    ATTACH 'test.db2' AS two;
775ec6ffc1aSdan    CREATE TABLE t1(a, b);
776ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
777ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
778ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
779ec6ffc1aSdan    BEGIN;
780ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
781ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
782ec6ffc1aSdan    COMMIT;
783ec6ffc1aSdan  }
784ec6ffc1aSdan  tv filter {}
785ec6ffc1aSdan  db close
786ec6ffc1aSdan} {}
787ec6ffc1aSdan
788ec6ffc1aSdanfaultsim_restore_and_reopen
789ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
790ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
791ec6ffc1aSdando_execsql_test pager1.4.6.4 {
792ec6ffc1aSdan  ATTACH 'test.db2' AS two;
793ec6ffc1aSdan  SELECT * FROM t2;
794ec6ffc1aSdan} {1 t2.1}
795ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
796ec6ffc1aSdan
797ec6ffc1aSdanfaultsim_restore_and_reopen
798ec6ffc1aSdandb close
799ec6ffc1aSdando_test pager1.4.6.8 {
800ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
801ec6ffc1aSdan  tv filter xDelete
802ec6ffc1aSdan  sqlite3 db test.db2
803ec6ffc1aSdan  execsql {
8043f94b609Sdan    PRAGMA journal_mode = DELETE;
805ec6ffc1aSdan    ATTACH 'test.db3' AS three;
806ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
807ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
808ec6ffc1aSdan    BEGIN;
809ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
810ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
811ec6ffc1aSdan    COMMIT;
812ec6ffc1aSdan  }
813ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
814ec6ffc1aSdan} {1}
815ec6ffc1aSdanfaultsim_restore_and_reopen
816ec6ffc1aSdantv filter {}
817ec6ffc1aSdan
818ec6ffc1aSdan# The file-system now contains:
819ec6ffc1aSdan#
820ec6ffc1aSdan#   * three databases
821ec6ffc1aSdan#   * three hot-journal files
822ec6ffc1aSdan#   * two master-journal files.
823ec6ffc1aSdan#
824ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
825ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
826ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
827ec6ffc1aSdan# test.db should delete $::mj_filename1.
828ec6ffc1aSdan#
829ec6ffc1aSdando_test pager1.4.6.9 {
830ec6ffc1aSdan  lsort [glob test.db*]
831ec6ffc1aSdan} [lsort [list                                           \
832ec6ffc1aSdan  test.db test.db2 test.db3                              \
833ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
834ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
835ec6ffc1aSdan]]
836ec6ffc1aSdan
837ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
838ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
839ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
840ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
841ec6ffc1aSdan#
842ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
843ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
844ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
845ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
846ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
847ec6ffc1aSdan
848ec6ffc1aSdando_execsql_test pager1.4.6.12 {
849ec6ffc1aSdan  ATTACH 'test.db2' AS two;
850ec6ffc1aSdan  SELECT * FROM t2;
851ec6ffc1aSdan} {1 t2.1}
852ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
853ec6ffc1aSdando_execsql_test pager1.4.6.14 {
854ec6ffc1aSdan  ATTACH 'test.db3' AS three;
855ec6ffc1aSdan  SELECT * FROM t3;
856ec6ffc1aSdan} {1 t3.1}
857ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
85810f5a50eSdan
8590e986f51Sdandb close
8600e986f51Sdantv delete
861e08341c6Sdan
862c8ce3972Sdantestvfs tv -default 1
863c8ce3972Sdantv sectorsize 512
864c8ce3972Sdantv script copy_on_journal_delete
865c8ce3972Sdantv filter xDelete
866c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
867c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
868c8ce3972Sdan  return SQLITE_OK
869c8ce3972Sdan}
870c8ce3972Sdanfaultsim_delete_and_reopen
871c8ce3972Sdando_execsql_test pager1.4.7.1 {
8723f94b609Sdan  PRAGMA journal_mode = DELETE;
873c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
874c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
875c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
876c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
877c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
878c8ce3972Sdan  BEGIN;
879c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
880c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
881c8ce3972Sdan  COMMIT;
8823f94b609Sdan} {delete}
883c8ce3972Sdantv filter {}
884c8ce3972Sdandb close
885c8ce3972Sdantv delete
886c8ce3972Sdando_test pager1.4.7.2 {
887c8ce3972Sdan  faultsim_restore_and_reopen
888c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
889c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
890c8ce3972Sdan  catchsql { SELECT * FROM t1 }
891c8ce3972Sdan} {1 {unable to open database file}}
892c8ce3972Sdando_test pager1.4.7.3 {
893c8ce3972Sdan  db close
894c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
895c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
896fda06befSmistachkin  delete_file test.db-journal
897c8ce3972Sdan  file exists test.db-journal
898c8ce3972Sdan} {0}
899421377e6Sdrhdo_test pager1.4.8.1 {
900421377e6Sdrh  catch {file attributes test.db -permissions r--------}
901421377e6Sdrh  catch {file attributes test.db -readonly 1}
902421377e6Sdrh  sqlite3 db test.db
903421377e6Sdrh  db eval { SELECT * FROM t1 }
904421377e6Sdrh  sqlite3_db_readonly db main
905421377e6Sdrh} {1}
906421377e6Sdrhdo_test pager1.4.8.2 {
907421377e6Sdrh  sqlite3_db_readonly db xyz
908421377e6Sdrh} {-1}
909421377e6Sdrhdo_test pager1.4.8.3 {
910421377e6Sdrh  db close
911421377e6Sdrh  catch {file attributes test.db -readonly 0}
912db0ad5f2Sdan  catch {file attributes test.db -permissions rw-rw-rw-} msg
913421377e6Sdrh  sqlite3 db test.db
914421377e6Sdrh  db eval { SELECT * FROM t1 }
915421377e6Sdrh  sqlite3_db_readonly db main
916421377e6Sdrh} {0}
917c8ce3972Sdan
918de4996e2Sdan#-------------------------------------------------------------------------
919146ed78bSdan# The following tests deal with multi-file commits.
920de4996e2Sdan#
921146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
922146ed78bSdan#               another connection is holding a SHARED lock on one of the
923146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
924146ed78bSdan#
925146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
926146ed78bSdan#
927146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
928146ed78bSdan#
929146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
930146ed78bSdan#               name is added to a journal file immediately after the last
931146ed78bSdan#               journal record. But with synchronous=full, extra unused space
932146ed78bSdan#               is allocated between the last journal record and the
933146ed78bSdan#               master-journal file name so that the master-journal file
934146ed78bSdan#               name does not lie on the same sector as the last journal file
935146ed78bSdan#               record.
936146ed78bSdan#
937e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
938e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
939e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
940e08341c6Sdan#
941146ed78bSdan#
942146ed78bSdando_test pager1-5.1.1 {
943146ed78bSdan  faultsim_delete_and_reopen
944146ed78bSdan  execsql {
945146ed78bSdan    ATTACH 'test.db2' AS aux;
946146ed78bSdan    CREATE TABLE t1(a, b);
947146ed78bSdan    CREATE TABLE aux.t2(a, b);
948146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
949146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
950146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
951146ed78bSdan  }
952146ed78bSdan} {}
953146ed78bSdando_test pager1-5.1.2 {
954146ed78bSdan  execsql {
955146ed78bSdan    BEGIN;
956146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
957146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
958146ed78bSdan  }
959146ed78bSdan  sqlite3 db2 test.db2
960146ed78bSdan  execsql {
961146ed78bSdan    BEGIN;
962146ed78bSdan      SELECT * FROM t2;
963146ed78bSdan  } db2
964146ed78bSdan} {}
965146ed78bSdando_test pager1-5.1.3 {
966146ed78bSdan  catchsql COMMIT
967146ed78bSdan} {1 {database is locked}}
968146ed78bSdando_test pager1-5.1.4 {
969146ed78bSdan  execsql COMMIT db2
970146ed78bSdan  execsql COMMIT
971146ed78bSdan  execsql { SELECT * FROM t2 } db2
972146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
973146ed78bSdando_test pager1-5.1.5 {
974146ed78bSdan  db2 close
975146ed78bSdan} {}
976146ed78bSdan
977146ed78bSdando_test pager1-5.2.1 {
978146ed78bSdan  execsql {
979146ed78bSdan    PRAGMA journal_mode = memory;
980146ed78bSdan    BEGIN;
981146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
982146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
983146ed78bSdan    COMMIT;
984146ed78bSdan  }
985146ed78bSdan} {memory}
986146ed78bSdando_test pager1-5.3.1 {
987146ed78bSdan  execsql {
988146ed78bSdan    PRAGMA journal_mode = off;
989146ed78bSdan    BEGIN;
990146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
991146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
992146ed78bSdan    COMMIT;
993146ed78bSdan  }
994146ed78bSdan} {off}
995146ed78bSdan
996146ed78bSdando_test pager1-5.4.1 {
997146ed78bSdan  db close
998146ed78bSdan  testvfs tv
999146ed78bSdan  sqlite3 db test.db -vfs tv
1000146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
1001146ed78bSdan
1002146ed78bSdan  tv filter xDelete
1003146ed78bSdan  tv script max_journal_size
1004146ed78bSdan  tv sectorsize 512
1005146ed78bSdan  set ::max_journal 0
1006146ed78bSdan  proc max_journal_size {method args} {
1007146ed78bSdan    set sz 0
1008146ed78bSdan    catch { set sz [file size test.db-journal] }
1009146ed78bSdan    if {$sz > $::max_journal} {
1010146ed78bSdan      set ::max_journal $sz
1011146ed78bSdan    }
1012146ed78bSdan    return SQLITE_OK
1013146ed78bSdan  }
1014146ed78bSdan  execsql {
1015146ed78bSdan    PRAGMA journal_mode = DELETE;
1016146ed78bSdan    PRAGMA synchronous = NORMAL;
1017146ed78bSdan    BEGIN;
1018146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1019146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1020146ed78bSdan    COMMIT;
1021146ed78bSdan  }
10227f9026ddSdan
10237f9026ddSdan  # The size of the journal file is now:
10247f9026ddSdan  #
10257f9026ddSdan  #   1) 512 byte header +
10267f9026ddSdan  #   2) 2 * (1024+8) byte records +
10277f9026ddSdan  #   3) 20+N bytes of master-journal pointer, where N is the size of
10287f9026ddSdan  #      the master-journal name encoded as utf-8 with no nul term.
10297f9026ddSdan  #
10307f9026ddSdan  set mj_pointer [expr {
1031c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
10327f9026ddSdan  }]
1033c5484654Smistachkin  #
1034c5484654Smistachkin  #   NOTE: For item 3 above, if the current SQLite VFS lacks the concept of a
1035c5484654Smistachkin  #         current directory, the length of the current directory name plus 1
1036c5484654Smistachkin  #         character for the directory separator character are NOT counted as
1037c5484654Smistachkin  #         part of the total size; otherwise, they are.
1038c5484654Smistachkin  #
1039c5484654Smistachkin  ifcapable curdir {
10406aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1041c5484654Smistachkin  }
10427f9026ddSdan  expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
10437f9026ddSdan} 1
1044146ed78bSdando_test pager1-5.4.2 {
1045146ed78bSdan  set ::max_journal 0
1046146ed78bSdan  execsql {
1047146ed78bSdan    PRAGMA synchronous = full;
1048146ed78bSdan    BEGIN;
1049146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
1050146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
1051146ed78bSdan    COMMIT;
1052146ed78bSdan  }
10537f9026ddSdan
10547f9026ddSdan  # In synchronous=full mode, the master-journal pointer is not written
10557f9026ddSdan  # directly after the last record in the journal file. Instead, it is
10567f9026ddSdan  # written starting at the next (in this case 512 byte) sector boundary.
10577f9026ddSdan  #
10587f9026ddSdan  set mj_pointer [expr {
1059c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
10607f9026ddSdan  }]
1061c5484654Smistachkin  #
1062c5484654Smistachkin  #   NOTE: If the current SQLite VFS lacks the concept of a current directory,
1063c5484654Smistachkin  #         the length of the current directory name plus 1 character for the
1064c5484654Smistachkin  #         directory separator character are NOT counted as part of the total
1065c5484654Smistachkin  #         size; otherwise, they are.
1066c5484654Smistachkin  #
1067c5484654Smistachkin  ifcapable curdir {
10686aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1069c5484654Smistachkin  }
10707f9026ddSdan  expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
10717f9026ddSdan} 1
1072146ed78bSdandb close
1073146ed78bSdantv delete
1074146ed78bSdan
1075146ed78bSdando_test pager1-5.5.1 {
1076146ed78bSdan  sqlite3 db test.db
1077146ed78bSdan  execsql {
1078146ed78bSdan    ATTACH 'test.db2' AS aux;
1079146ed78bSdan    PRAGMA journal_mode = PERSIST;
1080146ed78bSdan    CREATE TABLE t3(a, b);
1081146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
1082146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
1083146ed78bSdan  }
1084146ed78bSdan  expr [file size test.db-journal] > 15000
1085146ed78bSdan} {1}
1086146ed78bSdando_test pager1-5.5.2 {
1087146ed78bSdan  execsql {
1088146ed78bSdan    PRAGMA synchronous = full;
1089146ed78bSdan    BEGIN;
1090146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
1091146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
1092146ed78bSdan    COMMIT;
1093146ed78bSdan  }
1094146ed78bSdan  file size test.db-journal
1095146ed78bSdan} {0}
1096146ed78bSdan
1097146ed78bSdan
1098146ed78bSdan#-------------------------------------------------------------------------
1099146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1100146ed78bSdan#
1101146ed78bSdando_test pager1-6.1 {
1102146ed78bSdan  faultsim_delete_and_reopen
1103146ed78bSdan  execsql {
1104f43d7fceSdan    PRAGMA auto_vacuum = none;
1105146ed78bSdan    PRAGMA max_page_count = 10;
1106146ed78bSdan    CREATE TABLE t2(a, b);
1107146ed78bSdan    CREATE TABLE t3(a, b);
1108146ed78bSdan    CREATE TABLE t4(a, b);
1109146ed78bSdan    CREATE TABLE t5(a, b);
1110146ed78bSdan    CREATE TABLE t6(a, b);
1111146ed78bSdan    CREATE TABLE t7(a, b);
1112146ed78bSdan    CREATE TABLE t8(a, b);
1113146ed78bSdan    CREATE TABLE t9(a, b);
1114146ed78bSdan    CREATE TABLE t10(a, b);
1115146ed78bSdan  }
1116146ed78bSdan} {10}
1117d353331aSdando_catchsql_test pager1-6.2 {
1118d353331aSdan  CREATE TABLE t11(a, b)
1119146ed78bSdan} {1 {database or disk is full}}
1120d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1121d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1122d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1123d353331aSdando_execsql_test pager1-6.7 {
1124d353331aSdan  BEGIN;
1125d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1126d353331aSdan    PRAGMA max_page_count = 13;
1127d353331aSdan} {13}
1128d353331aSdando_execsql_test pager1-6.8 {
1129d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1130d353331aSdan    PRAGMA max_page_count = 10;
1131d353331aSdan} {11}
1132d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1133de4996e2Sdan
113460ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
113522b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
113622b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
113722b328b2Sdan
1138153eda0aSdan
1139153eda0aSdan#-------------------------------------------------------------------------
1140153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1141153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1142153eda0aSdan#
1143153eda0aSdan# Each test is specified with 5 variables. As follows:
1144153eda0aSdan#
1145153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1146153eda0aSdan#   $sql: SQL to execute.
1147153eda0aSdan#   $res: Expected result of executing $sql.
1148153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1149153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1150153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1151153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1152153eda0aSdan#
115338e1a279Sdanifcapable wal {
1154153eda0aSdan  faultsim_delete_and_reopen
1155153eda0aSdan  foreach {tn sql res js ws} [subst {
1156153eda0aSdan
1157153eda0aSdan    1  {
1158153eda0aSdan      CREATE TABLE t1(a, b);
1159153eda0aSdan      PRAGMA auto_vacuum=OFF;
1160153eda0aSdan      PRAGMA synchronous=NORMAL;
1161153eda0aSdan      PRAGMA page_size=1024;
1162153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1163153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1164153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1165153eda0aSdan    } {exclusive truncate} 0 -1
1166153eda0aSdan
1167153eda0aSdan    2  {
1168153eda0aSdan      BEGIN IMMEDIATE;
1169153eda0aSdan        SELECT * FROM t1;
1170153eda0aSdan      COMMIT;
1171153eda0aSdan    } {1 2} 0 -1
1172153eda0aSdan
1173153eda0aSdan    3  {
1174153eda0aSdan      BEGIN;
1175153eda0aSdan        SELECT * FROM t1;
1176153eda0aSdan      COMMIT;
1177153eda0aSdan    } {1 2} 0 -1
1178153eda0aSdan
1179153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal       -1 -1
1180153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}        -1 [wal_file_size 1 1024]
11818c408004Sdan    6  { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
1182153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
1183153eda0aSdan
1184153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1185153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1186153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1187153eda0aSdan
1188153eda0aSdan  }] {
1189153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1190153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1191153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1192153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1193153eda0aSdan  }
119438e1a279Sdan}
1195153eda0aSdan
119689ccf448Sdando_test pager1-7.2.1 {
119789ccf448Sdan  faultsim_delete_and_reopen
119889ccf448Sdan  execsql {
119989ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
120089ccf448Sdan    CREATE TABLE t1(a, b);
120189ccf448Sdan    BEGIN;
120289ccf448Sdan      PRAGMA journal_mode = delete;
120389ccf448Sdan      PRAGMA journal_mode = truncate;
120489ccf448Sdan  }
120589ccf448Sdan} {exclusive delete truncate}
120689ccf448Sdando_test pager1-7.2.2 {
120789ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
120889ccf448Sdan  execsql { PRAGMA journal_mode = persist }
120989ccf448Sdan} {truncate}
121089ccf448Sdando_test pager1-7.2.3 {
121189ccf448Sdan  execsql { COMMIT }
121289ccf448Sdan  execsql {
121389ccf448Sdan    PRAGMA journal_mode = persist;
121489ccf448Sdan    PRAGMA journal_size_limit;
121589ccf448Sdan  }
121689ccf448Sdan} {persist -1}
121789ccf448Sdan
1218d353331aSdan#-------------------------------------------------------------------------
1219d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1220d353331aSdan# ":memory:" and "" open temporary databases.
1221d353331aSdan#
12220e986f51Sdanforeach {tn filename} {
12230e986f51Sdan  1 :memory:
12240e986f51Sdan  2 ""
12250e986f51Sdan} {
12260e986f51Sdan  do_test pager1-8.$tn.1 {
1227153eda0aSdan    faultsim_delete_and_reopen
1228153eda0aSdan    db close
12290e986f51Sdan    sqlite3 db $filename
1230153eda0aSdan    execsql {
1231c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1232153eda0aSdan      CREATE TABLE x1(x);
1233153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1234153eda0aSdan      INSERT INTO x1 VALUES('James');
1235153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1236153eda0aSdan      SELECT * FROM x1;
1237153eda0aSdan    }
1238153eda0aSdan  } {Charles James Mary}
12390e986f51Sdan
12400e986f51Sdan  do_test pager1-8.$tn.2 {
12410e986f51Sdan    sqlite3 db2 $filename
12420e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1243153eda0aSdan  } {1 {no such table: x1}}
1244153eda0aSdan
12450e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
12460e986f51Sdan    BEGIN;
12470e986f51Sdan      INSERT INTO x1 VALUES('William');
12480e986f51Sdan      INSERT INTO x1 VALUES('Anne');
12490e986f51Sdan    ROLLBACK;
12500e986f51Sdan  } {}
12510e986f51Sdan}
12520e986f51Sdan
1253dca321aeSdan#-------------------------------------------------------------------------
1254dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1255dca321aeSdan# the pager and the backup API. Test cases:
1256dca321aeSdan#
1257dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1258dca321aeSdan#                 source db is written to during the backup op.
1259dca321aeSdan#
1260dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1261dca321aeSdan#                 source db is written to and then rolled back during a
1262dca321aeSdan#                 backup operation.
1263dca321aeSdan#
1264dca321aeSdando_test pager1-9.0.1 {
1265dca321aeSdan  faultsim_delete_and_reopen
1266dca321aeSdan  db func a_string a_string
1267dca321aeSdan  execsql {
1268dca321aeSdan    PRAGMA cache_size = 10;
1269dca321aeSdan    BEGIN;
1270dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1271dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1272dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1273dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1274dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1275dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1276dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1277dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1278dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1279dca321aeSdan    COMMIT;
1280dca321aeSdan  }
1281dca321aeSdan} {}
1282dca321aeSdando_test pager1-9.0.2 {
1283dca321aeSdan  sqlite3 db2 test.db2
1284dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1285dca321aeSdan  sqlite3_backup B db2 main db main
1286dca321aeSdan  list [B step 10000] [B finish]
1287dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1288dca321aeSdando_test pager1-9.0.3 {
1289dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1290dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1291dca321aeSdan
1292dca321aeSdando_test pager1-9.1.1 {
1293dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1294dca321aeSdan  sqlite3_backup B db2 main db main
1295dca321aeSdan  B step 30
1296dca321aeSdan} {SQLITE_OK}
1297dca321aeSdando_test pager1-9.1.2 {
1298dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1299dca321aeSdan  list [B step 10000] [B finish]
1300dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1301dca321aeSdando_test pager1-9.1.3 {
1302dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1303dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1304dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1305dca321aeSdan
1306dca321aeSdando_test pager1-9.2.1 {
1307dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1308dca321aeSdan  sqlite3_backup B db2 main db main
1309dca321aeSdan  B step 30
1310dca321aeSdan} {SQLITE_OK}
1311dca321aeSdando_test pager1-9.2.2 {
1312dca321aeSdan  execsql {
1313dca321aeSdan    BEGIN;
1314dca321aeSdan      UPDATE ab SET b = a_string(301);
1315dca321aeSdan    ROLLBACK;
1316dca321aeSdan  }
1317dca321aeSdan  list [B step 10000] [B finish]
1318dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1319dca321aeSdando_test pager1-9.2.3 {
1320dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1321dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1322dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1323ec6ffc1aSdandb close
1324ec6ffc1aSdandb2 close
1325ec6ffc1aSdan
1326c396d4afSdando_test pager1-9.3.1 {
1327c396d4afSdan  testvfs tv -default 1
1328c396d4afSdan  tv sectorsize 4096
1329c396d4afSdan  faultsim_delete_and_reopen
1330c396d4afSdan
1331c396d4afSdan  execsql { PRAGMA page_size = 1024 }
1332c396d4afSdan  for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
1333c396d4afSdan} {}
1334c396d4afSdando_test pager1-9.3.2 {
1335c396d4afSdan  sqlite3 db2 test.db2
1336f412ee2eSdan
1337c396d4afSdan  execsql {
1338c396d4afSdan    PRAGMA page_size = 4096;
1339c396d4afSdan    PRAGMA synchronous = OFF;
1340c396d4afSdan    CREATE TABLE t1(a, b);
1341c396d4afSdan    CREATE TABLE t2(a, b);
1342c396d4afSdan  } db2
1343c396d4afSdan
1344c396d4afSdan  sqlite3_backup B db2 main db main
1345c396d4afSdan  B step 30
1346c396d4afSdan  list [B step 10000] [B finish]
1347c396d4afSdan} {SQLITE_DONE SQLITE_OK}
1348c396d4afSdando_test pager1-9.3.3 {
1349c396d4afSdan  db2 close
1350c396d4afSdan  db close
1351c396d4afSdan  tv delete
1352c396d4afSdan  file size test.db2
1353c396d4afSdan} [file size test.db]
1354c396d4afSdan
1355f412ee2eSdando_test pager1-9.4.1 {
1356f412ee2eSdan  faultsim_delete_and_reopen
1357f412ee2eSdan  sqlite3 db2 test.db2
1358f412ee2eSdan  execsql {
1359f412ee2eSdan    PRAGMA page_size = 4096;
1360f412ee2eSdan    CREATE TABLE t1(a, b);
1361f412ee2eSdan    CREATE TABLE t2(a, b);
1362f412ee2eSdan  } db2
1363f412ee2eSdan  sqlite3_backup B db2 main db main
1364f412ee2eSdan  list [B step 10000] [B finish]
1365f412ee2eSdan} {SQLITE_DONE SQLITE_OK}
1366f412ee2eSdando_test pager1-9.4.2 {
1367f412ee2eSdan  list [file size test.db2] [file size test.db]
1368b483eba0Sdan} {1024 0}
136933d85c9cSshanehdb2 close
1370d0b0d4dcSdan
1371ec6ffc1aSdan#-------------------------------------------------------------------------
1372ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1373ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1374ec6ffc1aSdan#
1375ec6ffc1aSdantestvfs tv -default 1
1376ec6ffc1aSdanforeach sectorsize {
1377ec6ffc1aSdan    32   64   128   256   512   1024   2048
1378ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1379ec6ffc1aSdan} {
1380ec6ffc1aSdan  tv sectorsize $sectorsize
13811eaaf93aSdrh  tv devchar {}
1382ec6ffc1aSdan  set eff $sectorsize
1383ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1384ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1385ec6ffc1aSdan
1386d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1387ec6ffc1aSdan    faultsim_delete_and_reopen
1388d0b0d4dcSdan    db func a_string a_string
1389ec6ffc1aSdan    execsql {
1390ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1391ec6ffc1aSdan      PRAGMA page_size = 1024;
1392d0b0d4dcSdan      BEGIN;
1393ec6ffc1aSdan        CREATE TABLE t1(a, b);
1394d0b0d4dcSdan        CREATE TABLE t2(a, b);
1395d0b0d4dcSdan        CREATE TABLE t3(a, b);
1396d0b0d4dcSdan      COMMIT;
1397ec6ffc1aSdan    }
1398ec6ffc1aSdan    file size test.db-journal
1399ec6ffc1aSdan  } [expr $sectorsize > 65536 ? 65536 : $sectorsize]
1400d0b0d4dcSdan
1401d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1402d0b0d4dcSdan    execsql {
1403d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1404d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1405d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1406d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1407d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1408d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1409ec6ffc1aSdan    }
1410d0b0d4dcSdan  } {}
1411d0b0d4dcSdan
1412d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1413d0b0d4dcSdan    db close
1414d0b0d4dcSdan    sqlite3 db test.db
1415d0b0d4dcSdan    execsql {
1416d0b0d4dcSdan      PRAGMA cache_size = 10;
1417d0b0d4dcSdan      BEGIN;
1418d0b0d4dcSdan    }
1419d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1420d0b0d4dcSdan    execsql {
1421d0b0d4dcSdan      COMMIT;
1422d0b0d4dcSdan      SELECT * FROM t2;
1423d0b0d4dcSdan    }
1424d0b0d4dcSdan  } {1 2}
1425d0b0d4dcSdan
1426d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1427d0b0d4dcSdan    execsql {
1428d0b0d4dcSdan      CREATE TABLE t6(a, b);
1429d0b0d4dcSdan      CREATE TABLE t7(a, b);
1430d0b0d4dcSdan      CREATE TABLE t5(a, b);
1431d0b0d4dcSdan      DROP TABLE t6;
1432d0b0d4dcSdan      DROP TABLE t7;
1433d0b0d4dcSdan    }
1434d0b0d4dcSdan    execsql {
1435d0b0d4dcSdan      BEGIN;
1436d0b0d4dcSdan        CREATE TABLE t6(a, b);
1437d0b0d4dcSdan    }
1438d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1439d0b0d4dcSdan    execsql {
1440d0b0d4dcSdan      COMMIT;
1441d0b0d4dcSdan      SELECT * FROM t5;
1442d0b0d4dcSdan    }
1443d0b0d4dcSdan  } {1 2}
1444d0b0d4dcSdan
1445d0b0d4dcSdan}
1446d0b0d4dcSdandb close
1447d0b0d4dcSdan
1448d0b0d4dcSdantv sectorsize 4096
1449d0b0d4dcSdando_test pager1.10.x.1 {
1450d0b0d4dcSdan  faultsim_delete_and_reopen
1451d0b0d4dcSdan  execsql {
1452f43d7fceSdan    PRAGMA auto_vacuum = none;
1453d0b0d4dcSdan    PRAGMA page_size = 1024;
1454d0b0d4dcSdan    CREATE TABLE t1(x);
1455d0b0d4dcSdan  }
1456d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1457d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1458d0b0d4dcSdan  }
1459d0b0d4dcSdan  file size test.db
1460d0b0d4dcSdan} {32768}
1461d0b0d4dcSdando_test pager1.10.x.2 {
1462d0b0d4dcSdan  execsql {
1463d0b0d4dcSdan    CREATE TABLE t2(x);
1464d0b0d4dcSdan    DROP TABLE t2;
1465d0b0d4dcSdan  }
1466d0b0d4dcSdan  file size test.db
1467d0b0d4dcSdan} {33792}
1468d0b0d4dcSdando_test pager1.10.x.3 {
1469d0b0d4dcSdan  execsql {
1470d0b0d4dcSdan    BEGIN;
1471d0b0d4dcSdan    CREATE TABLE t2(x);
1472d0b0d4dcSdan  }
1473d0b0d4dcSdan  recursive_select 30 t1
1474d0b0d4dcSdan  execsql {
1475d0b0d4dcSdan    CREATE TABLE t3(x);
1476d0b0d4dcSdan    COMMIT;
1477d0b0d4dcSdan  }
1478d0b0d4dcSdan} {}
1479d0b0d4dcSdan
1480ec6ffc1aSdandb close
1481ec6ffc1aSdantv delete
1482ec6ffc1aSdan
1483ec6ffc1aSdantestvfs tv -default 1
1484ec6ffc1aSdanfaultsim_delete_and_reopen
1485ec6ffc1aSdandb func a_string a_string
1486ec6ffc1aSdando_execsql_test pager1-11.1 {
14873f94b609Sdan  PRAGMA journal_mode = DELETE;
1488ec6ffc1aSdan  PRAGMA cache_size = 10;
1489ec6ffc1aSdan  BEGIN;
1490ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1491ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1492ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1493ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1494ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1495ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1496ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1497ec6ffc1aSdan  COMMIT;
1498ec6ffc1aSdan  BEGIN;
1499ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
15003f94b609Sdan} {delete}
1501ec6ffc1aSdan
1502ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1503ec6ffc1aSdantv script lockout
1504ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1505ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1506ec6ffc1aSdan
1507ec6ffc1aSdantv script {}
1508ec6ffc1aSdando_test pager1-11.3 {
1509ec6ffc1aSdan  sqlite3 db2 test.db
1510ec6ffc1aSdan  execsql {
1511ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1512ec6ffc1aSdan    PRAGMA integrity_check;
1513ec6ffc1aSdan  } db2
1514ec6ffc1aSdan} {truncate ok}
1515ec6ffc1aSdando_test pager1-11.4 {
1516ec6ffc1aSdan  db2 close
1517f6c61471Sdan  file exists test.db-journal
1518ec6ffc1aSdan} {0}
1519ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1520f9b4419dSdandb close
1521f9b4419dSdantv delete
1522ec6ffc1aSdan
1523f9b4419dSdan#-------------------------------------------------------------------------
1524f9b4419dSdan# Test "PRAGMA page_size"
1525f9b4419dSdan#
1526f43d7fceSdantestvfs tv -default 1
1527f43d7fceSdantv sectorsize 1024
1528f9b4419dSdanforeach pagesize {
1529f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1530f9b4419dSdan} {
1531f9b4419dSdan  faultsim_delete_and_reopen
1532f9b4419dSdan
1533f43d7fceSdan  # The sector-size (according to the VFS) is 1024 bytes. So if the
1534f43d7fceSdan  # page-size requested using "PRAGMA page_size" is greater than the
1535f43d7fceSdan  # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
1536f43d7fceSdan  # page-size remains 1024 bytes.
1537f43d7fceSdan  #
1538f43d7fceSdan  set eff $pagesize
1539f43d7fceSdan  if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
1540f43d7fceSdan
1541f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1542f9b4419dSdan    sqlite3 db2 test.db
1543f9b4419dSdan    execsql "
1544f9b4419dSdan      PRAGMA page_size = $pagesize;
1545f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1546f9b4419dSdan    " db2
1547f9b4419dSdan    file size test.db
1548f43d7fceSdan  } $eff
1549f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1550f9b4419dSdan    sqlite3 db2 test.db
1551f9b4419dSdan    execsql {
1552f9b4419dSdan      SELECT count(*) FROM v;
1553f9b4419dSdan      PRAGMA main.page_size;
1554f9b4419dSdan    } db2
1555f43d7fceSdan  } [list 1 $eff]
1556f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1557f9b4419dSdan    execsql {
1558f9b4419dSdan      SELECT count(*) FROM v;
1559f9b4419dSdan      PRAGMA main.page_size;
1560f9b4419dSdan    }
1561f43d7fceSdan  } [list 1 $eff]
1562f9b4419dSdan  db2 close
1563f9b4419dSdan}
1564f43d7fceSdandb close
1565f43d7fceSdantv delete
1566dca321aeSdan
1567d353331aSdan#-------------------------------------------------------------------------
1568d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1569d353331aSdan#
1570d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1571d353331aSdan#                journal mode: If the journal associated with a transaction
1572d353331aSdan#                is smaller than the journal file (because a previous
1573d353331aSdan#                transaction left a very large non-hot journal file in the
1574d353331aSdan#                file-system), then SQLite has to be careful that there is
1575d353331aSdan#                not a journal-header left over from a previous transaction
1576d353331aSdan#                immediately following the journal content just written.
1577d353331aSdan#                If there is, and the process crashes so that the journal
1578d353331aSdan#                becomes a hot-journal and must be rolled back by another
1579d353331aSdan#                process, there is a danger that the other process may roll
1580d353331aSdan#                back the aborted transaction, then continue copying data
1581d353331aSdan#                from an older transaction from the remainder of the journal.
1582d353331aSdan#                See the syncJournal() function for details.
1583d353331aSdan#
1584d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1585d353331aSdan#                the mix to make the integrity-check more likely to catch
1586d353331aSdan#                errors.
1587d353331aSdan#
1588d353331aSdantestvfs tv -default 1
1589d353331aSdantv script xSyncCb
1590d353331aSdantv filter xSync
1591d353331aSdanproc xSyncCb {method filename args} {
1592d353331aSdan  set t [file tail $filename]
1593d353331aSdan  if {$t == "test.db"} faultsim_save
1594d353331aSdan  return SQLITE_OK
1595d353331aSdan}
1596d353331aSdanfaultsim_delete_and_reopen
1597d353331aSdandb func a_string a_string
1598e91a54e1Sdan
1599d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1600d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1601d353331aSdan# frequent journal headers.
1602d353331aSdan#
1603d353331aSdando_execsql_test pager1-13.1.1 {
1604d353331aSdan  PRAGMA page_size = 1024;
1605d353331aSdan  PRAGMA journal_mode = PERSIST;
1606d353331aSdan  PRAGMA cache_size = 10;
1607d353331aSdan  BEGIN;
1608d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1609d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1610d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1611d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1612d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1613d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1614d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1615d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1616d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1617d353331aSdan  COMMIT;
1618d353331aSdan  UPDATE t1 SET b = a_string(400);
1619d353331aSdan} {persist}
1620d353331aSdan
1621b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1622d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1623d353331aSdan# of these will write just enough content that one of the old headers created
1624d353331aSdan# by the transaction in the block above lies immediately after the content
1625d353331aSdan# journalled by the current transaction.
1626d353331aSdan#
1627d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1628d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1629d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1630d353331aSdan  } {}
1631d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1632d353331aSdan
1633d353331aSdan  # Try to access the snapshot of the file-system.
1634d353331aSdan  #
1635d353331aSdan  sqlite3 db2 sv_test.db
1636d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1637d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1638d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1639d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1640d353331aSdan    execsql { PRAGMA integrity_check } db2
1641d353331aSdan  } {ok}
1642d353331aSdan  db2 close
1643d353331aSdan}
1644b2f20bfcSshaneh}
1645d353331aSdan
1646b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1647d353331aSdan# Same test as above. But this time with an index on the table.
1648d353331aSdan#
1649d353331aSdando_execsql_test pager1-13.2.1 {
1650d353331aSdan  CREATE INDEX i1 ON t1(b);
1651d353331aSdan  UPDATE t1 SET b = a_string(400);
1652d353331aSdan} {}
1653d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1654d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1655d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1656d353331aSdan  } {}
1657d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1658d353331aSdan  sqlite3 db2 sv_test.db
1659d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1660d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1661d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1662d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1663d353331aSdan    execsql { PRAGMA integrity_check } db2
1664d353331aSdan  } {ok}
1665d353331aSdan  db2 close
1666d353331aSdan}
1667b2f20bfcSshaneh}
1668d353331aSdan
1669d353331aSdandb close
1670d353331aSdantv delete
1671d353331aSdan
1672d353331aSdan#-------------------------------------------------------------------------
1673d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1674d353331aSdan#
1675d353331aSdanfaultsim_delete_and_reopen
1676d353331aSdando_execsql_test pager1-14.1.1 {
1677d353331aSdan  PRAGMA journal_mode = OFF;
1678d353331aSdan  CREATE TABLE t1(a, b);
1679d353331aSdan  BEGIN;
1680d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1681d353331aSdan  COMMIT;
1682d353331aSdan  SELECT * FROM t1;
1683d353331aSdan} {off 1 2}
1684d353331aSdando_catchsql_test pager1-14.1.2 {
1685d353331aSdan  BEGIN;
1686d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1687d353331aSdan  ROLLBACK;
1688d353331aSdan} {0 {}}
1689d353331aSdando_execsql_test pager1-14.1.3 {
1690d353331aSdan  SELECT * FROM t1;
1691354bfe03Sdan} {1 2}
1692d353331aSdando_catchsql_test pager1-14.1.4 {
1693d353331aSdan  BEGIN;
1694d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1695d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1696d353331aSdan} {1 {PRIMARY KEY must be unique}}
1697d353331aSdando_execsql_test pager1-14.1.5 {
1698d353331aSdan  COMMIT;
1699d353331aSdan  SELECT * FROM t1;
1700354bfe03Sdan} {1 2 2 2}
1701d353331aSdan
1702c8ce3972Sdan#-------------------------------------------------------------------------
1703c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1704c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1705c8ce3972Sdan#
1706c8ce3972Sdanfaultsim_delete_and_reopen
1707c8ce3972Sdando_execsql_test pager1-15.0 {
1708c8ce3972Sdan  CREATE TABLE tx(y, z);
1709c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1710c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1711c8ce3972Sdan} {}
1712c8ce3972Sdandb close
1713c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1714c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1715c8ce3972Sdan  sqlite3 db test.db
1716c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1717c8ce3972Sdan    SELECT * FROM tx;
1718c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1719c8ce3972Sdan  db close
1720c8ce3972Sdan  tv delete
1721c8ce3972Sdan}
1722c8ce3972Sdan
1723c8ce3972Sdan#-------------------------------------------------------------------------
1724c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1725c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1726c8ce3972Sdan#
1727c8ce3972Sdantestvfs tv -default 1
1728c8ce3972Sdantv script xOpenCb
1729c8ce3972Sdantv filter xOpen
173033f5379cSdanproc xOpenCb {method filename args} {
1731c8ce3972Sdan  set ::file_len [string length $filename]
1732c8ce3972Sdan}
1733c8ce3972Sdansqlite3 db test.db
1734c8ce3972Sdandb close
1735c8ce3972Sdantv delete
1736c8ce3972Sdan
1737c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1738c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1739c8ce3972Sdan
1740c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1741c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1742c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1743c8ce3972Sdan  #
1744c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1745c8ce3972Sdan    set res {0 {}}
1746c8ce3972Sdan  } else {
1747c8ce3972Sdan    set res {1 {unable to open database file}}
1748c8ce3972Sdan  }
1749c8ce3972Sdan
1750c8ce3972Sdan  do_test pager1-16.1.$ii {
1751c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1752c8ce3972Sdan  } $res
1753c8ce3972Sdan
1754c8ce3972Sdan  catch {db close}
1755c8ce3972Sdan  tv delete
1756c8ce3972Sdan}
1757c8ce3972Sdan
1758c8ce3972Sdan
1759c8ce3972Sdan#-------------------------------------------------------------------------
1760c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1761c8ce3972Sdan# numbers:
1762c8ce3972Sdan#
1763c8ce3972Sdan#   + The locking page,
1764c8ce3972Sdan#   + Page 0,
1765c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1766c8ce3972Sdan#
1767f4ba1093Sdan# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
1768f4ba1093Sdan# that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
1769f4ba1093Sdan#
1770f4ba1093Sdanifcapable !direct_read {
1771c8ce3972Sdando_test pager1-18.1 {
1772c8ce3972Sdan  faultsim_delete_and_reopen
1773c8ce3972Sdan  db func a_string a_string
1774c8ce3972Sdan  execsql {
1775c8ce3972Sdan    PRAGMA page_size = 1024;
1776c8ce3972Sdan    CREATE TABLE t1(a, b);
1777c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1778c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1779c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1780c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1781c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1782c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1783c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1784c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1785c8ce3972Sdan  }
1786c8ce3972Sdan} {}
1787c8ce3972Sdando_test pager1-18.2 {
1788c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1789c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1790c8ce3972Sdan  execsql {
1791c8ce3972Sdan    PRAGMA writable_schema = 1;
1792c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1793c8ce3972Sdan  }
1794c8ce3972Sdan  sqlite3 db2 test.db
1795c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1796c8ce3972Sdan} {1 {database disk image is malformed}}
1797c8ce3972Sdandb2 close
1798a748fdccSdrhdo_test pager1-18.3.1 {
1799c8ce3972Sdan  execsql {
1800c8ce3972Sdan    CREATE TABLE t2(x);
1801c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1802c8ce3972Sdan  }
1803c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1804c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1805c8ce3972Sdan  sqlite3 db2 test.db
1806a748fdccSdrh  # even though x is malformed, because typeof() does
1807a748fdccSdrh  # not load the content of x, the error is not noticed.
1808a748fdccSdrh  catchsql { SELECT typeof(x) FROM t2 } db2
1809a748fdccSdrh} {0 text}
1810a748fdccSdrhdo_test pager1-18.3.2 {
1811a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1812a748fdccSdrh  # detected
1813a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1814a748fdccSdrh} {1 {database disk image is malformed}}
1815a748fdccSdrhdb2 close
1816a748fdccSdrhdo_test pager1-18.3.3 {
1817a748fdccSdrh  execsql {
1818a748fdccSdrh    DELETE FROM t2;
1819a748fdccSdrh    INSERT INTO t2 VALUES(randomblob(5000));
1820a748fdccSdrh  }
1821a748fdccSdrh  set pgno [expr ([file size test.db] / 1024)-2]
1822a748fdccSdrh  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1823a748fdccSdrh  sqlite3 db2 test.db
1824a748fdccSdrh  # even though x is malformed, because length() and typeof() do
1825a748fdccSdrh  # not load the content of x, the error is not noticed.
1826a748fdccSdrh  catchsql { SELECT length(x), typeof(x) FROM t2 } db2
1827a748fdccSdrh} {0 {5000 blob}}
1828a748fdccSdrhdo_test pager1-18.3.4 {
1829a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1830a748fdccSdrh  # detected
1831a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1832c8ce3972Sdan} {1 {database disk image is malformed}}
1833c8ce3972Sdandb2 close
1834c8ce3972Sdando_test pager1-18.4 {
1835c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1836c8ce3972Sdan  sqlite3 db2 test.db
1837a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1838c8ce3972Sdan} {1 {database disk image is malformed}}
1839c8ce3972Sdandb2 close
1840c8ce3972Sdando_test pager1-18.5 {
1841c8ce3972Sdan  sqlite3 db ""
1842c8ce3972Sdan  execsql {
1843c8ce3972Sdan    CREATE TABLE t1(a, b);
1844c8ce3972Sdan    CREATE TABLE t2(a, b);
1845c8ce3972Sdan    PRAGMA writable_schema = 1;
1846c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1847c8ce3972Sdan    PRAGMA writable_schema = 0;
1848c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1849c8ce3972Sdan  }
1850c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1851ba3cbf3dSdan} {1 {database disk image is malformed}}
1852c8ce3972Sdandb close
1853c8ce3972Sdan
1854ba3cbf3dSdando_test pager1-18.6 {
1855ba3cbf3dSdan  faultsim_delete_and_reopen
1856ba3cbf3dSdan  db func a_string a_string
1857ba3cbf3dSdan  execsql {
1858ba3cbf3dSdan    PRAGMA page_size = 1024;
1859ba3cbf3dSdan    CREATE TABLE t1(x);
1860ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1861ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1862ba3cbf3dSdan  }
1863ba3cbf3dSdan
1864ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1865ba3cbf3dSdan  db close
1866ba3cbf3dSdan
1867ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1868ba3cbf3dSdan  sqlite3 db test.db
1869ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1870ba3cbf3dSdan} {1 {database disk image is malformed}}
1871f4ba1093Sdan}
1872ba3cbf3dSdan
1873ba3cbf3dSdando_test pager1-19.1 {
1874ba3cbf3dSdan  sqlite3 db ""
1875ba3cbf3dSdan  db func a_string a_string
1876ba3cbf3dSdan  execsql {
1877ba3cbf3dSdan    PRAGMA page_size = 512;
1878ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1879ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1880ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1881ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1882ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1883ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1884ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1885ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1886ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1887ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1888ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1889ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1890ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1891ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1892ba3cbf3dSdan    );
1893ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1894ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1895ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1896ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1897ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1898ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1899ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1900ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1901ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1902ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1903ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1904ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1905ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1906ba3cbf3dSdan    );
1907ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
1908ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
1909ba3cbf3dSdan    VACUUM;
1910ba3cbf3dSdan  }
1911ba3cbf3dSdan} {}
1912ba3cbf3dSdan
19136b63ab47Sdan#-------------------------------------------------------------------------
19146b63ab47Sdan# Test a couple of special cases that come up while committing
19156b63ab47Sdan# transactions:
19166b63ab47Sdan#
19176b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
19186b63ab47Sdan#                  database has not been modified at all.
19196b63ab47Sdan#
19206b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
19216b63ab47Sdan#
19226b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
19236b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
19246b63ab47Sdan#                  disk before the commit.
19256b63ab47Sdan#
19266b63ab47Sdando_test pager1-20.1.1 {
19276b63ab47Sdan  catch {db close}
19286b63ab47Sdan  sqlite3 db :memory:
19296b63ab47Sdan  execsql {
19306b63ab47Sdan    CREATE TABLE one(two, three);
19316b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19326b63ab47Sdan  }
19336b63ab47Sdan} {}
19346b63ab47Sdando_test pager1-20.1.2 {
19356b63ab47Sdan  execsql {
19366b63ab47Sdan    BEGIN EXCLUSIVE;
19376b63ab47Sdan    COMMIT;
19386b63ab47Sdan  }
19396b63ab47Sdan} {}
19406b63ab47Sdan
19416b63ab47Sdando_test pager1-20.2.1 {
19426b63ab47Sdan  faultsim_delete_and_reopen
19436b63ab47Sdan  execsql {
19446b63ab47Sdan    PRAGMA locking_mode = exclusive;
19456b63ab47Sdan    PRAGMA journal_mode = persist;
19466b63ab47Sdan    CREATE TABLE one(two, three);
19476b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19486b63ab47Sdan  }
19496b63ab47Sdan} {exclusive persist}
19506b63ab47Sdando_test pager1-20.2.2 {
19516b63ab47Sdan  execsql {
19526b63ab47Sdan    BEGIN EXCLUSIVE;
19536b63ab47Sdan    COMMIT;
19546b63ab47Sdan  }
19556b63ab47Sdan} {}
19566b63ab47Sdan
19579091f775Sshanehifcapable wal {
19586b63ab47Sdan  do_test pager1-20.3.1 {
19596b63ab47Sdan    faultsim_delete_and_reopen
19606b63ab47Sdan    db func a_string a_string
19616b63ab47Sdan    execsql {
19626b63ab47Sdan      PRAGMA cache_size = 10;
19636b63ab47Sdan      PRAGMA journal_mode = wal;
19646b63ab47Sdan      BEGIN;
19656b63ab47Sdan        CREATE TABLE t1(x);
19666b63ab47Sdan        CREATE TABLE t2(y);
19676b63ab47Sdan        INSERT INTO t1 VALUES(a_string(800));
19686b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
19696b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
19706b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
19716b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
19726b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
19736b63ab47Sdan      COMMIT;
19746b63ab47Sdan    }
19756b63ab47Sdan  } {wal}
19766b63ab47Sdan  do_test pager1-20.3.2 {
19776b63ab47Sdan    execsql {
19786b63ab47Sdan      BEGIN;
19796b63ab47Sdan      INSERT INTO t2 VALUES('xxxx');
19806b63ab47Sdan    }
1981c396d4afSdan    recursive_select 32 t1
19826b63ab47Sdan    execsql COMMIT
19836b63ab47Sdan  } {}
19849091f775Sshaneh}
19856b63ab47Sdan
198689ccf448Sdan#-------------------------------------------------------------------------
198789ccf448Sdan# Test that a WAL database may not be opened if:
198889ccf448Sdan#
198989ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
199089ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
199189ccf448Sdan#
19929091f775Sshanehifcapable wal {
199389ccf448Sdan  do_test pager1-21.0 {
199489ccf448Sdan    faultsim_delete_and_reopen
199589ccf448Sdan    execsql {
199689ccf448Sdan      PRAGMA journal_mode = WAL;
199789ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
199889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
199989ccf448Sdan    }
200089ccf448Sdan  } {wal}
200189ccf448Sdan  do_test pager1-21.1 {
200289ccf448Sdan    testvfs tv -noshm 1
200389ccf448Sdan    sqlite3 db2 test.db -vfs tv
200489ccf448Sdan    catchsql { SELECT * FROM ko } db2
200589ccf448Sdan  } {1 {unable to open database file}}
200689ccf448Sdan  db2 close
200789ccf448Sdan  tv delete
200889ccf448Sdan  do_test pager1-21.2 {
200989ccf448Sdan    testvfs tv -iversion 1
201089ccf448Sdan    sqlite3 db2 test.db -vfs tv
201189ccf448Sdan    catchsql { SELECT * FROM ko } db2
201289ccf448Sdan  } {1 {unable to open database file}}
201389ccf448Sdan  db2 close
201489ccf448Sdan  tv delete
20159091f775Sshaneh}
201689ccf448Sdan
201789ccf448Sdan#-------------------------------------------------------------------------
201889ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
201989ccf448Sdan#
202089ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
202189ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
202289ccf448Sdan#
20235209132aSdanifcapable wal {
202489ccf448Sdan  do_test pager1-22.1.1 {
202589ccf448Sdan    faultsim_delete_and_reopen
202689ccf448Sdan    execsql {
202789ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
202889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
202989ccf448Sdan    }
203089ccf448Sdan    execsql { PRAGMA wal_checkpoint }
2031bdd9af0fSdan  } {0 -1 -1}
203289ccf448Sdan  do_test pager1-22.2.1 {
203389ccf448Sdan    testvfs tv -default 1
203489ccf448Sdan    tv filter xSync
203589ccf448Sdan    tv script xSyncCb
203689ccf448Sdan    proc xSyncCb {args} {incr ::synccount}
203789ccf448Sdan    set ::synccount 0
203889ccf448Sdan    sqlite3 db test.db
203989ccf448Sdan    execsql {
204089ccf448Sdan      PRAGMA synchronous = off;
204189ccf448Sdan      PRAGMA journal_mode = WAL;
204289ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
204389ccf448Sdan    }
204489ccf448Sdan    execsql { PRAGMA wal_checkpoint }
204589ccf448Sdan    set synccount
204689ccf448Sdan  } {0}
204789ccf448Sdan  db close
204889ccf448Sdan  tv delete
20495209132aSdan}
205089ccf448Sdan
205189ccf448Sdan#-------------------------------------------------------------------------
205289ccf448Sdan# Tests for changing journal mode.
205389ccf448Sdan#
205489ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
205589ccf448Sdan#                  the journal file is deleted.
205689ccf448Sdan#
205789ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
205889ccf448Sdan#                  on the database file.
205989ccf448Sdan#
206089ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
206189ccf448Sdan#                  on the database file.
206289ccf448Sdan#
206389ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
206489ccf448Sdan#
206589ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
206689ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
206789ccf448Sdan#
2068d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
2069d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
2070d0b0d4dcSdan#                  locking_mode=exclusive).
2071d0b0d4dcSdan#
207289ccf448Sdando_test pager1-23.1.1 {
207389ccf448Sdan  faultsim_delete_and_reopen
207489ccf448Sdan  execsql {
207589ccf448Sdan    PRAGMA journal_mode = PERSIST;
207689ccf448Sdan    CREATE TABLE t1(a, b);
207789ccf448Sdan  }
207889ccf448Sdan  file exists test.db-journal
207989ccf448Sdan} {1}
208089ccf448Sdando_test pager1-23.1.2 {
208189ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
208289ccf448Sdan  file exists test.db-journal
208389ccf448Sdan} {0}
208489ccf448Sdan
208589ccf448Sdando_test pager1-23.2.1 {
208689ccf448Sdan  execsql {
208789ccf448Sdan    PRAGMA journal_mode = PERSIST;
208889ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
208989ccf448Sdan  }
209089ccf448Sdan  db eval { SELECT * FROM t1 } {
209189ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
209289ccf448Sdan  }
209389ccf448Sdan  execsql { PRAGMA journal_mode }
209489ccf448Sdan} {delete}
209589ccf448Sdando_test pager1-23.2.2 {
209689ccf448Sdan  file exists test.db-journal
209789ccf448Sdan} {0}
209889ccf448Sdan
209989ccf448Sdando_test pager1-23.3.1 {
210089ccf448Sdan  execsql {
210189ccf448Sdan    PRAGMA journal_mode = PERSIST;
210289ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
210389ccf448Sdan    BEGIN IMMEDIATE;
210489ccf448Sdan  }
210589ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
210689ccf448Sdan  execsql { PRAGMA journal_mode }
210789ccf448Sdan} {delete}
210889ccf448Sdando_test pager1-23.3.2 {
210989ccf448Sdan  file exists test.db-journal
211089ccf448Sdan} {0}
211189ccf448Sdando_test pager1-23.3.3 {
211289ccf448Sdan  execsql COMMIT
211389ccf448Sdan} {}
211489ccf448Sdan
211589ccf448Sdando_test pager1-23.4.1 {
211689ccf448Sdan  execsql {
211789ccf448Sdan    PRAGMA journal_mode = PERSIST;
211889ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
211989ccf448Sdan    BEGIN EXCLUSIVE;
212089ccf448Sdan  }
212189ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
212289ccf448Sdan  execsql { PRAGMA journal_mode }
212389ccf448Sdan} {delete}
212489ccf448Sdando_test pager1-23.4.2 {
212589ccf448Sdan  file exists test.db-journal
212689ccf448Sdan} {0}
212789ccf448Sdando_test pager1-23.4.3 {
212889ccf448Sdan  execsql COMMIT
212989ccf448Sdan} {}
213089ccf448Sdan
213189ccf448Sdando_test pager1-23.5.1 {
213289ccf448Sdan  faultsim_delete_and_reopen
213389ccf448Sdan  sqlite3 db :memory:
213489ccf448Sdan} {}
213589ccf448Sdanforeach {tn mode possible} {
213689ccf448Sdan  2  off      1
213789ccf448Sdan  3  memory   1
213889ccf448Sdan  4  persist  0
213989ccf448Sdan  5  delete   0
214089ccf448Sdan  6  wal      0
214189ccf448Sdan  7  truncate 0
214289ccf448Sdan} {
214389ccf448Sdan  do_test pager1-23.5.$tn.1 {
214489ccf448Sdan    execsql "PRAGMA journal_mode = off"
214589ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
214689ccf448Sdan  } [if $possible {list $mode} {list off}]
214789ccf448Sdan  do_test pager1-23.5.$tn.2 {
214889ccf448Sdan    execsql "PRAGMA journal_mode = memory"
214989ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
215089ccf448Sdan  } [if $possible {list $mode} {list memory}]
215189ccf448Sdan}
2152d0b0d4dcSdando_test pager1-23.6.1 {
215389ccf448Sdan  execsql {PRAGMA locking_mode = normal}
215489ccf448Sdan} {exclusive}
2155d0b0d4dcSdando_test pager1-23.6.2 {
215689ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
215789ccf448Sdan} {exclusive}
2158d0b0d4dcSdando_test pager1-23.6.3 {
215989ccf448Sdan  execsql {PRAGMA locking_mode}
216089ccf448Sdan} {exclusive}
2161d0b0d4dcSdando_test pager1-23.6.4 {
216289ccf448Sdan  execsql {PRAGMA main.locking_mode}
216389ccf448Sdan} {exclusive}
21646b63ab47Sdan
2165d0b0d4dcSdan#-------------------------------------------------------------------------
2166d0b0d4dcSdan#
2167d0b0d4dcSdando_test pager1-24.1.1 {
2168d0b0d4dcSdan  faultsim_delete_and_reopen
2169d0b0d4dcSdan  db func a_string a_string
2170d0b0d4dcSdan  execsql {
2171d0b0d4dcSdan    PRAGMA cache_size = 10;
2172d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2173d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2174d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2175d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2176d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2177d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2178d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2179d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2180d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2181d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2182d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2183d0b0d4dcSdan  }
2184d0b0d4dcSdan} {}
2185d0b0d4dcSdando_test pager1-24.1.2 {
2186d0b0d4dcSdan  execsql {
2187d0b0d4dcSdan    BEGIN;
2188d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2189d0b0d4dcSdan  }
2190c396d4afSdan  recursive_select 64 x2
2191d0b0d4dcSdan} {}
2192d0b0d4dcSdando_test pager1-24.1.3 {
2193d0b0d4dcSdan  execsql {
2194d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2195d0b0d4dcSdan    COMMIT;
2196d0b0d4dcSdan    PRAGMA integrity_check;
2197d0b0d4dcSdan    SELECT count(*) FROM x1;
2198d0b0d4dcSdan  }
2199d0b0d4dcSdan} {ok 33}
2200d0b0d4dcSdan
2201d0b0d4dcSdando_test pager1-24.1.4 {
2202d0b0d4dcSdan  execsql {
2203d0b0d4dcSdan    DELETE FROM x1;
2204d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2205d0b0d4dcSdan    BEGIN;
2206d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2207d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2208d0b0d4dcSdan  }
2209c396d4afSdan  recursive_select 64 x2 {db eval COMMIT}
2210d0b0d4dcSdan  execsql {
2211d0b0d4dcSdan    PRAGMA integrity_check;
2212d0b0d4dcSdan    SELECT count(*) FROM x1;
2213d0b0d4dcSdan  }
2214d0b0d4dcSdan} {ok 33}
2215d0b0d4dcSdan
2216d0b0d4dcSdando_test pager1-24.1.5 {
2217d0b0d4dcSdan  execsql {
2218d0b0d4dcSdan    DELETE FROM x1;
2219d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2220d0b0d4dcSdan  }
2221c396d4afSdan  recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
2222d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2223d0b0d4dcSdan} {}
2224d0b0d4dcSdan
2225d0b0d4dcSdan#-------------------------------------------------------------------------
2226d0b0d4dcSdan#
2227d0b0d4dcSdando_test pager1-25-1 {
2228d0b0d4dcSdan  faultsim_delete_and_reopen
2229d0b0d4dcSdan  execsql {
2230d0b0d4dcSdan    BEGIN;
2231d0b0d4dcSdan      SAVEPOINT abc;
2232d0b0d4dcSdan        CREATE TABLE t1(a, b);
2233d0b0d4dcSdan      ROLLBACK TO abc;
2234d0b0d4dcSdan    COMMIT;
2235d0b0d4dcSdan  }
2236d0b0d4dcSdan  db close
2237d0b0d4dcSdan} {}
2238d0b0d4dcSdanbreakpoint
2239d0b0d4dcSdando_test pager1-25-2 {
2240d0b0d4dcSdan  faultsim_delete_and_reopen
2241d0b0d4dcSdan  execsql {
2242d0b0d4dcSdan    SAVEPOINT abc;
2243d0b0d4dcSdan      CREATE TABLE t1(a, b);
2244d0b0d4dcSdan    ROLLBACK TO abc;
2245d0b0d4dcSdan    COMMIT;
2246d0b0d4dcSdan  }
2247d0b0d4dcSdan  db close
2248d0b0d4dcSdan} {}
22496b63ab47Sdan
2250c396d4afSdan#-------------------------------------------------------------------------
2251c396d4afSdan# Sector-size tests.
2252c396d4afSdan#
2253c396d4afSdando_test pager1-26.1 {
2254c396d4afSdan  testvfs tv -default 1
2255c396d4afSdan  tv sectorsize 4096
2256c396d4afSdan  faultsim_delete_and_reopen
2257c396d4afSdan  db func a_string a_string
2258c396d4afSdan  execsql {
2259c396d4afSdan    PRAGMA page_size = 512;
2260c396d4afSdan    CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
2261c396d4afSdan    BEGIN;
2262c396d4afSdan      INSERT INTO tbl VALUES(a_string(25), a_string(600));
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      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2267c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2268c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2269c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2270c396d4afSdan    COMMIT;
2271c396d4afSdan  }
2272c396d4afSdan} {}
2273c396d4afSdando_execsql_test pager1-26.1 {
2274c396d4afSdan  UPDATE tbl SET b = a_string(550);
2275c396d4afSdan} {}
2276c396d4afSdandb close
2277c396d4afSdantv delete
2278c396d4afSdan
2279c396d4afSdan#-------------------------------------------------------------------------
228022b328b2Sdan#
2281c396d4afSdando_test pager1.27.1 {
2282c396d4afSdan  faultsim_delete_and_reopen
2283c396d4afSdan  sqlite3_pager_refcounts db
2284c396d4afSdan  execsql {
2285c396d4afSdan    BEGIN;
2286c396d4afSdan      CREATE TABLE t1(a, b);
2287c396d4afSdan  }
2288c396d4afSdan  sqlite3_pager_refcounts db
2289c396d4afSdan  execsql COMMIT
2290c396d4afSdan} {}
2291c396d4afSdan
229222b328b2Sdan#-------------------------------------------------------------------------
229322b328b2Sdan# Test that attempting to open a write-transaction with
229422b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on
229522b328b2Sdan# the same database.
229622b328b2Sdan#
229722b328b2Sdancatch { db close }
22989091f775Sshanehifcapable wal {
229922b328b2Sdan  do_multiclient_test tn {
230022b328b2Sdan    do_test pager1-28.$tn.1 {
230122b328b2Sdan      sql1 {
230222b328b2Sdan        PRAGMA journal_mode = WAL;
230322b328b2Sdan        CREATE TABLE t1(a, b);
230422b328b2Sdan        INSERT INTO t1 VALUES('a', 'b');
230522b328b2Sdan      }
230622b328b2Sdan    } {wal}
230722b328b2Sdan    do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
230822b328b2Sdan
230922b328b2Sdan    do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
231022b328b2Sdan    do_test pager1-28.$tn.4 {
231122b328b2Sdan      csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
231222b328b2Sdan    } {1 {database is locked}}
231322b328b2Sdan    code2 { db2 close ; sqlite3 db2 test.db }
231422b328b2Sdan    do_test pager1-28.$tn.4 {
231522b328b2Sdan      sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
231622b328b2Sdan    } {}
231722b328b2Sdan  }
23189091f775Sshaneh}
23195653e4daSdan
23205653e4daSdan#-------------------------------------------------------------------------
23215653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager
23225653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a
23235653e4daSdan# RESERVED lock on the database file, this step is skipped.
23245653e4daSdan#
23255653e4daSdando_multiclient_test tn {
23265653e4daSdan  do_test pager1-28.$tn.1 {
23275653e4daSdan    sql1 {
23285653e4daSdan      PRAGMA journal_mode = PERSIST;
23295653e4daSdan      CREATE TABLE t1(a, b);
23305653e4daSdan      INSERT INTO t1 VALUES('a', 'b');
23315653e4daSdan    }
23325653e4daSdan  } {persist}
23335653e4daSdan  do_test pager1-28.$tn.2 { file exists test.db-journal } 1
23345653e4daSdan  do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
23355653e4daSdan  do_test pager1-28.$tn.4 { file exists test.db-journal } 0
23365653e4daSdan
23375653e4daSdan  do_test pager1-28.$tn.5 {
23385653e4daSdan    sql1 {
23395653e4daSdan      PRAGMA journal_mode = PERSIST;
23405653e4daSdan      INSERT INTO t1 VALUES('c', 'd');
23415653e4daSdan    }
23425653e4daSdan  } {persist}
23435653e4daSdan  do_test pager1-28.$tn.6 { file exists test.db-journal } 1
23445653e4daSdan  do_test pager1-28.$tn.7 {
23455653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
23465653e4daSdan  } {}
23475653e4daSdan  do_test pager1-28.$tn.8  { file exists test.db-journal } 1
23485653e4daSdan  do_test pager1-28.$tn.9  { sql1 { PRAGMA journal_mode = DELETE } } delete
23495653e4daSdan  do_test pager1-28.$tn.10 { file exists test.db-journal } 1
23505653e4daSdan
23515653e4daSdan  do_test pager1-28.$tn.11 { sql2 COMMIT } {}
23525653e4daSdan  do_test pager1-28.$tn.12 { file exists test.db-journal } 0
23535653e4daSdan
23545653e4daSdan  do_test pager1-28-$tn.13 {
23555653e4daSdan    code1 { set channel [db incrblob -readonly t1 a 2] }
23565653e4daSdan    sql1 {
23575653e4daSdan      PRAGMA journal_mode = PERSIST;
23585653e4daSdan      INSERT INTO t1 VALUES('g', 'h');
23595653e4daSdan    }
23605653e4daSdan  } {persist}
23615653e4daSdan  do_test pager1-28.$tn.14 { file exists test.db-journal } 1
23625653e4daSdan  do_test pager1-28.$tn.15 {
23635653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
23645653e4daSdan  } {}
23655653e4daSdan  do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
23665653e4daSdan  do_test pager1-28.$tn.17 { file exists test.db-journal } 1
23675653e4daSdan
23685653e4daSdan  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
23695653e4daSdan  do_test pager1-28-$tn.18 { code1 { read $channel } } c
23705653e4daSdan  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
23715653e4daSdan  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
23725653e4daSdan}
23735653e4daSdan
23741879b088Sdando_test pager1-29.1 {
23751879b088Sdan  faultsim_delete_and_reopen
23761879b088Sdan  execsql {
23771879b088Sdan    PRAGMA page_size = 1024;
23781879b088Sdan    PRAGMA auto_vacuum = full;
23791879b088Sdan    PRAGMA locking_mode=exclusive;
23801879b088Sdan    CREATE TABLE t1(a, b);
23811879b088Sdan    INSERT INTO t1 VALUES(1, 2);
23821879b088Sdan  }
23831879b088Sdan  file size test.db
23841879b088Sdan} [expr 1024*3]
23851879b088Sdando_test pager1-29.2 {
23861879b088Sdan  execsql {
23871879b088Sdan    PRAGMA page_size = 4096;
23881879b088Sdan    VACUUM;
23891879b088Sdan  }
23901879b088Sdan  file size test.db
23911879b088Sdan} [expr 4096*3]
23921879b088Sdan
2393e08c2066Sdan#-------------------------------------------------------------------------
2394e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in
2395e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system
2396e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while
2397e08c2066Sdan# doing this is not released.
2398e08c2066Sdan#
2399e08c2066Sdando_test pager1-30.1 {
2400e08c2066Sdan  db close
2401fda06befSmistachkin  delete_file test.db
2402fda06befSmistachkin  delete_file test.db-journal
2403e08c2066Sdan  set fd [open test.db-journal w]
2404e08c2066Sdan  seek $fd [expr 512+1032*2]
2405e08c2066Sdan  puts -nonewline $fd x
2406e08c2066Sdan  close $fd
2407e08c2066Sdan
2408e08c2066Sdan  sqlite3 db test.db
2409e08c2066Sdan  execsql {
2410e08c2066Sdan    PRAGMA locking_mode=EXCLUSIVE;
2411e08c2066Sdan    SELECT count(*) FROM sqlite_master;
2412e08c2066Sdan    PRAGMA lock_status;
2413e08c2066Sdan  }
2414e08c2066Sdan} {exclusive 0 main reserved temp closed}
2415e08c2066Sdan
2416e08c2066Sdan#-------------------------------------------------------------------------
2417e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal
2418e08c2066Sdan# file can still be rolled back. This is required for backward compatibility -
2419e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero.
2420e08c2066Sdan#
242133f5379cSdanif {$tcl_platform(platform)=="unix"} {
2422e08c2066Sdando_test pager1-31.1 {
2423e08c2066Sdan  faultsim_delete_and_reopen
2424e08c2066Sdan  execsql {
2425e08c2066Sdan    PRAGMA cache_size = 10;
2426e08c2066Sdan    PRAGMA page_size = 1024;
2427e08c2066Sdan    CREATE TABLE t1(x, y, UNIQUE(x, y));
2428e08c2066Sdan    INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
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    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2436e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2437e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2438e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2439e08c2066Sdan    BEGIN;
2440e08c2066Sdan      UPDATE t1 SET y = randomblob(1499);
2441e08c2066Sdan  }
2442fda06befSmistachkin  copy_file test.db test.db2
2443fda06befSmistachkin  copy_file test.db-journal test.db2-journal
2444e08c2066Sdan
2445e08c2066Sdan  hexio_write test.db2-journal 24 00000000
2446e08c2066Sdan  sqlite3 db2 test.db2
2447e08c2066Sdan  execsql { PRAGMA integrity_check } db2
2448e08c2066Sdan} {ok}
244933f5379cSdan}
2450e08c2066Sdan
245131e80976Sdrh#-------------------------------------------------------------------------
245231e80976Sdrh# Test that a database file can be "pre-hinted" to a certain size and that
245331e80976Sdrh# subsequent spilling of the pager cache does not result in the database
245431e80976Sdrh# file being shrunk.
245531e80976Sdrh#
245631e80976Sdrhcatch {db close}
245731e80976Sdrhforcedelete test.db
245831e80976Sdrh
245931e80976Sdrhdo_test pager1-32.1 {
246031e80976Sdrh  sqlite3 db test.db
246131e80976Sdrh  execsql {
246231e80976Sdrh    CREATE TABLE t1(x, y);
246331e80976Sdrh  }
246431e80976Sdrh  db close
246531e80976Sdrh  sqlite3 db test.db
246631e80976Sdrh  execsql {
246731e80976Sdrh    BEGIN;
246831e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
246931e80976Sdrh  }
24702f7820d8Sdrh  file_control_chunksize_test db main 1024
247131e80976Sdrh  file_control_sizehint_test db main 20971520; # 20MB
247231e80976Sdrh  execsql {
247331e80976Sdrh    PRAGMA cache_size = 10;
247431e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
247531e80976Sdrh    INSERT INTO t1 VALUES(2, randomblob(10000));
247631e80976Sdrh    INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
247731e80976Sdrh    INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
247831e80976Sdrh    INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
247931e80976Sdrh    INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
248031e80976Sdrh    SELECT count(*) FROM t1;
248131e80976Sdrh    COMMIT;
248231e80976Sdrh  }
248331e80976Sdrh  db close
248431e80976Sdrh  file size test.db
248531e80976Sdrh} {20971520}
248631e80976Sdrh
248731e80976Sdrh# Cleanup 20MB file left by the previous test.
248831e80976Sdrhforcedelete test.db
24895653e4daSdan
2490*9fc5b4a5Sdan#-------------------------------------------------------------------------
2491*9fc5b4a5Sdan# Test that if a transaction is committed in journal_mode=DELETE mode,
2492*9fc5b4a5Sdan# and the call to unlink() returns an ENOENT error, the COMMIT does not
2493*9fc5b4a5Sdan# succeed.
2494*9fc5b4a5Sdan#
2495*9fc5b4a5Sdanif {$::tcl_platform(platform)=="unix"} {
2496*9fc5b4a5Sdan  do_test pager1-33.1 {
2497*9fc5b4a5Sdan    sqlite3 db test.db
2498*9fc5b4a5Sdan    execsql {
2499*9fc5b4a5Sdan      CREATE TABLE t1(x);
2500*9fc5b4a5Sdan      INSERT INTO t1 VALUES('one');
2501*9fc5b4a5Sdan      INSERT INTO t1 VALUES('two');
2502*9fc5b4a5Sdan      BEGIN;
2503*9fc5b4a5Sdan        INSERT INTO t1 VALUES('three');
2504*9fc5b4a5Sdan        INSERT INTO t1 VALUES('four');
2505*9fc5b4a5Sdan    }
2506*9fc5b4a5Sdan    forcedelete bak-journal
2507*9fc5b4a5Sdan    file rename test.db-journal bak-journal
2508*9fc5b4a5Sdan
2509*9fc5b4a5Sdan    catchsql COMMIT
2510*9fc5b4a5Sdan  } {1 {disk I/O error}}
2511*9fc5b4a5Sdan
2512*9fc5b4a5Sdan  do_test pager1-33.2 {
2513*9fc5b4a5Sdan    file rename bak-journal test.db-journal
2514*9fc5b4a5Sdan    execsql { SELECT * FROM t1 }
2515*9fc5b4a5Sdan  } {one two}
2516*9fc5b4a5Sdan}
2517*9fc5b4a5Sdan
2518d353331aSdanfinish_test
2519