xref: /sqlite-3.40.0/test/pager1.test (revision abd6d84a)
1e91a54e1Sdan# 2010 June 15
2e91a54e1Sdan#
3e91a54e1Sdan# The author disclaims copyright to this source code.  In place of
4e91a54e1Sdan# a legal notice, here is a blessing:
5e91a54e1Sdan#
6e91a54e1Sdan#    May you do good and not evil.
7e91a54e1Sdan#    May you find forgiveness for yourself and forgive others.
8e91a54e1Sdan#    May you share freely, never taking more than you give.
9e91a54e1Sdan#
10e91a54e1Sdan#***********************************************************************
11e91a54e1Sdan#
12e91a54e1Sdan
13e91a54e1Sdanset testdir [file dirname $argv0]
14e91a54e1Sdansource $testdir/tester.tcl
15e91a54e1Sdansource $testdir/lock_common.tcl
16e91a54e1Sdansource $testdir/malloc_common.tcl
17153eda0aSdansource $testdir/wal_common.tcl
18d7a558a9Sdanset testprefix pager1
1968928b6cSdan
2068928b6cSdan# Do not use a codec for tests in this file, as the database file is
2168928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command).
2268928b6cSdan#
2368928b6cSdando_not_use_codec
24e91a54e1Sdan
25b0ac3e3aSdan#
26b0ac3e3aSdan# pager1-1.*: Test inter-process locking (clients in multiple processes).
27b0ac3e3aSdan#
28b0ac3e3aSdan# pager1-2.*: Test intra-process locking (multiple clients in this process).
29b0ac3e3aSdan#
30b0ac3e3aSdan# pager1-3.*: Savepoint related tests.
31b0ac3e3aSdan#
321f4cb65aSdan# pager1-4.*: Hot-journal related tests.
331f4cb65aSdan#
34de4996e2Sdan# pager1-5.*: Cases related to multi-file commits.
35de4996e2Sdan#
36146ed78bSdan# pager1-6.*: Cases related to "PRAGMA max_page_count"
37146ed78bSdan#
38153eda0aSdan# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
39153eda0aSdan#
400e986f51Sdan# pager1-8.*: Cases using temporary and in-memory databases.
410e986f51Sdan#
42dca321aeSdan# pager1-9.*: Tests related to the backup API.
43dca321aeSdan#
44ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to
45ec6ffc1aSdan#              64KB.
46ec6ffc1aSdan#
47d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size"
48d353331aSdan#
49d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST"
50d353331aSdan#
51d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF"
52ec6ffc1aSdan#
53c8ce3972Sdan# pager1-15.*: Varying sqlite3_vfs.szOsFile
54c8ce3972Sdan#
55c8ce3972Sdan# pager1-16.*: Varying sqlite3_vfs.mxPathname
56c8ce3972Sdan#
57c8ce3972Sdan# pager1-17.*: Tests related to "PRAGMA omit_readlock"
5833f111dcSdrh#              (The omit_readlock pragma has been removed and so have
5933f111dcSdrh#              these tests.)
60c8ce3972Sdan#
61c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree
62c8ce3972Sdan#              requests an invalid page number (due to db corruption).
63c8ce3972Sdan#
64b0ac3e3aSdan
65c396d4afSdanproc recursive_select {id table {script {}}} {
66c396d4afSdan  set cnt 0
67c396d4afSdan  db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
68c396d4afSdan    recursive_select $rowid $table $script
69c396d4afSdan    incr cnt
70c396d4afSdan  }
71c396d4afSdan  if {$cnt==0} { eval $script }
72c396d4afSdan}
73c396d4afSdan
7453f04f3bSdanset a_string_counter 1
7553f04f3bSdanproc a_string {n} {
7653f04f3bSdan  global a_string_counter
7753f04f3bSdan  incr a_string_counter
7853f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
7953f04f3bSdan}
8053f04f3bSdandb func a_string a_string
8153f04f3bSdan
82a4a9095eSdando_multiclient_test tn {
83e91a54e1Sdan
84e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
85e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
86e91a54e1Sdan  #
87e91a54e1Sdan  do_test pager1-$tn.1 {
88e91a54e1Sdan    sql1 {
89e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
90e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
91d353331aSdan      INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
92e91a54e1Sdan    }
93e91a54e1Sdan  } {}
94e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
95e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
96e91a54e1Sdan
97e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
98e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
99e91a54e1Sdan  # read the database content as it was before the transaction was
100e91a54e1Sdan  # opened. [db] should see the inserted row.
101e91a54e1Sdan  #
102e91a54e1Sdan  do_test pager1-$tn.4 {
103e91a54e1Sdan    sql1 {
104e91a54e1Sdan      BEGIN;
105e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
106e91a54e1Sdan    }
107e91a54e1Sdan  } {}
108e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
109e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
110e91a54e1Sdan
111e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
112e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
113e91a54e1Sdan  #
114e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
115e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
116e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
117e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
118e91a54e1Sdan  #
119e91a54e1Sdan  do_test pager1-$tn.8 {
120e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
121e91a54e1Sdan  } {1 {database is locked}}
122e91a54e1Sdan  do_test pager1-$tn.9 {
123e91a54e1Sdan    csql2 {
124e91a54e1Sdan      BEGIN;
125e91a54e1Sdan      UPDATE t1 SET a = a + 10;
126e91a54e1Sdan    }
127e91a54e1Sdan  } {1 {database is locked}}
128e91a54e1Sdan
129e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
130e91a54e1Sdan  # now see the new database content.
131e91a54e1Sdan  #
132e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
133e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
134e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
135e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
136e91a54e1Sdan
137e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
138e91a54e1Sdan  # after the attempt to write the database failed.
139e91a54e1Sdan  #
140e91a54e1Sdan  do_test pager1-$tn.14 {
141e91a54e1Sdan    csql2 { BEGIN }
142e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
143e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
144e91a54e1Sdan
145e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
146e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
147e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
148e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
149e91a54e1Sdan  #
150e91a54e1Sdan  do_test pager1-$tn.15 {
151e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
152e91a54e1Sdan  } {1 one 2 two 3 three}
153e91a54e1Sdan  do_test pager1-$tn.16 {
154e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
155e91a54e1Sdan  } {1 {database is locked}}
156e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
157e91a54e1Sdan
158e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
159e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
160e91a54e1Sdan  # the SHARED lock [db2] is holding.
161e91a54e1Sdan  #
162e91a54e1Sdan  do_test pager1-$tn.18 {
163e91a54e1Sdan    sql1 {
164e91a54e1Sdan      BEGIN;
165e91a54e1Sdan      UPDATE t1 SET a = a + 10;
166e91a54e1Sdan    }
167e91a54e1Sdan  } {}
168e91a54e1Sdan  do_test pager1-$tn-19 {
169e91a54e1Sdan    sql1 { PRAGMA lock_status }
170e91a54e1Sdan  } {main reserved temp closed}
171e91a54e1Sdan  do_test pager1-$tn-20 {
172e91a54e1Sdan    sql2 { PRAGMA lock_status }
173e91a54e1Sdan  } {main shared temp closed}
174e91a54e1Sdan
175e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
176e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
177e91a54e1Sdan  #
178e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
179e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
180e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
181e91a54e1Sdan
182e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
183e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
184e91a54e1Sdan  # upgrades to a PENDING lock.
185e91a54e1Sdan  #
186e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
187e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
188e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
189e91a54e1Sdan  # the database.
190e91a54e1Sdan  #
191e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
192e91a54e1Sdan  do_test pager1-$tn-25 {
193e91a54e1Sdan    sql1 { PRAGMA lock_status }
194e91a54e1Sdan  } {main pending temp closed}
195e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
196e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
197e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
198e91a54e1Sdan
199e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
200e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
201e91a54e1Sdan  # is still holding a PENDING).
202e91a54e1Sdan  #
203e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
204e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
205e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
206e91a54e1Sdan
207e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
208e91a54e1Sdan  # committed, all three connections can read the new content.
209e91a54e1Sdan  #
210e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
211e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
212e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
213e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
214e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
215d353331aSdan
216d353331aSdan  # Install a busy-handler for connection [db].
217d353331aSdan  #
218d353331aSdan  set ::nbusy [list]
219d353331aSdan  proc busy {n} {
220d353331aSdan    lappend ::nbusy $n
221d353331aSdan    if {$n>5} { sql2 COMMIT }
222d353331aSdan    return 0
223d353331aSdan  }
224d353331aSdan  db busy busy
225d353331aSdan
226d353331aSdan  do_test pager1-$tn.29 {
227d353331aSdan    sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
228d353331aSdan  } {}
229d353331aSdan  do_test pager1-$tn.30 {
230d353331aSdan    sql2 { BEGIN ; SELECT * FROM t1 }
231d353331aSdan  } {21 one 22 two 23 three}
232d353331aSdan  do_test pager1-$tn.31 { sql1 COMMIT } {}
233d353331aSdan  do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
234e91a54e1Sdan}
235e91a54e1Sdan
23653f04f3bSdan#-------------------------------------------------------------------------
23753f04f3bSdan# Savepoint related test cases.
23853f04f3bSdan#
239dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
240dca321aeSdan#                 to grow.
241dca321aeSdan#
242273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
243273f3f0dSdan#                 of a savepoint rollback.
244273f3f0dSdan#
2450e986f51Sdando_test pager1-3.1.1 {
246b0ac3e3aSdan  faultsim_delete_and_reopen
247b0ac3e3aSdan  execsql {
248b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
249b0ac3e3aSdan    CREATE TABLE counter(
250b0ac3e3aSdan      i CHECK (i<5),
251b0ac3e3aSdan      u CHECK (u<10)
252b0ac3e3aSdan    );
253b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
254b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
255b0ac3e3aSdan      UPDATE counter SET i = i+1;
256b0ac3e3aSdan    END;
257b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
258b0ac3e3aSdan      UPDATE counter SET u = u+1;
259b0ac3e3aSdan    END;
260b0ac3e3aSdan  }
261b0ac3e3aSdan  execsql { SELECT * FROM counter }
262b0ac3e3aSdan} {0 0}
263b0ac3e3aSdan
2640e986f51Sdando_execsql_test pager1-3.1.2 {
265d353331aSdan  PRAGMA cache_size = 10;
266b0ac3e3aSdan  BEGIN;
267b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
268b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
269b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
270b0ac3e3aSdan    SELECT * FROM counter;
271b0ac3e3aSdan} {3 0}
2720e986f51Sdando_catchsql_test pager1-3.1.3 {
273b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
274b0ac3e3aSdan} {1 {constraint failed}}
275b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
276b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
277b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
278b0ac3e3aSdan
279273f3f0dSdanforeach {tn sql tcl} {
280d353331aSdan  7  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
281273f3f0dSdan    testvfs tv -default 1
282273f3f0dSdan    tv devchar safe_append
283273f3f0dSdan  }
284d353331aSdan  8  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
285d353331aSdan    testvfs tv -default 1
286d353331aSdan    tv devchar sequential
287d353331aSdan  }
288d353331aSdan  9  { PRAGMA synchronous = FULL } { }
289d353331aSdan  10 { PRAGMA synchronous = NORMAL } { }
290d353331aSdan  11 { PRAGMA synchronous = OFF } { }
291d353331aSdan  12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
292d353331aSdan  13 { PRAGMA synchronous = FULL } {
293d353331aSdan    testvfs tv -default 1
294d353331aSdan    tv devchar sequential
295d353331aSdan  }
2966b63ab47Sdan  14 { PRAGMA locking_mode = EXCLUSIVE } {
2976b63ab47Sdan  }
298273f3f0dSdan} {
299273f3f0dSdan  do_test pager1-3.$tn.1 {
300273f3f0dSdan    eval $tcl
301dca321aeSdan    faultsim_delete_and_reopen
302dca321aeSdan    db func a_string a_string
303273f3f0dSdan    execsql $sql
304dca321aeSdan    execsql {
305dca321aeSdan      PRAGMA auto_vacuum = 2;
306dca321aeSdan      PRAGMA cache_size = 10;
307dca321aeSdan      CREATE TABLE z(x INTEGER PRIMARY KEY, y);
308dca321aeSdan      BEGIN;
309dca321aeSdan        INSERT INTO z VALUES(NULL, a_string(800));
310dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
311dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
312dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
313dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
314dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
315dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
316dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
317dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
318dca321aeSdan      COMMIT;
319dca321aeSdan    }
320dca321aeSdan    execsql { PRAGMA auto_vacuum }
321dca321aeSdan  } {2}
322273f3f0dSdan  do_execsql_test pager1-3.$tn.2 {
323dca321aeSdan    BEGIN;
324dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
325dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
326dca321aeSdan      SAVEPOINT one;
327273f3f0dSdan        UPDATE z SET y = NULL WHERE x>256;
328dca321aeSdan        PRAGMA incremental_vacuum;
329dca321aeSdan        SELECT count(*) FROM z WHERE x < 100;
330dca321aeSdan      ROLLBACK TO one;
331dca321aeSdan    COMMIT;
332dca321aeSdan  } {99}
333dca321aeSdan
334273f3f0dSdan  do_execsql_test pager1-3.$tn.3 {
335273f3f0dSdan    BEGIN;
336273f3f0dSdan      SAVEPOINT one;
337273f3f0dSdan        UPDATE z SET y = y||x;
338273f3f0dSdan      ROLLBACK TO one;
339273f3f0dSdan    COMMIT;
340273f3f0dSdan    SELECT count(*) FROM z;
341273f3f0dSdan  } {258}
342273f3f0dSdan
343273f3f0dSdan  do_execsql_test pager1-3.$tn.4 {
344273f3f0dSdan    SAVEPOINT one;
345273f3f0dSdan      UPDATE z SET y = y||x;
346273f3f0dSdan    ROLLBACK TO one;
347273f3f0dSdan  } {}
348273f3f0dSdan  do_execsql_test pager1-3.$tn.5 {
349273f3f0dSdan    SELECT count(*) FROM z;
350273f3f0dSdan    RELEASE one;
351273f3f0dSdan    PRAGMA integrity_check;
352273f3f0dSdan  } {258 ok}
353273f3f0dSdan
35478f1e538Sdan  do_execsql_test pager1-3.$tn.6 {
35578f1e538Sdan    SAVEPOINT one;
35678f1e538Sdan    RELEASE one;
35778f1e538Sdan  } {}
35878f1e538Sdan
359273f3f0dSdan  db close
360273f3f0dSdan  catch { tv delete }
361273f3f0dSdan}
362273f3f0dSdan
36353f04f3bSdan#-------------------------------------------------------------------------
36453f04f3bSdan# Hot journal rollback related test cases.
36553f04f3bSdan#
36653f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
36753f04f3bSdan#               journal files.
36853f04f3bSdan#
36953f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
37053f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
37153f04f3bSdan#               compute) the associated journal is rolled back (and no
37253f04f3bSdan#               xAccess() call to check for the presence of any master
37353f04f3bSdan#               journal file is made).
37453f04f3bSdan#
375de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
376de4996e2Sdan#               page-size or sector-size in the journal header appear to
377de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
378de4996e2Sdan#
379e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
380e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
381e08341c6Sdan#               modes.
382e08341c6Sdan#
383e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
384e08341c6Sdan#               journal-record for which the checksum fails.
385e08341c6Sdan#
386ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
387ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
388ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
389ec6ffc1aSdan#
390c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can
391c8ce3972Sdan#               open it for reading only, the database cannot be accessed and
392c8ce3972Sdan#               SQLITE_CANTOPEN is returned.
393c8ce3972Sdan#
39453f04f3bSdando_test pager1.4.1.1 {
39553f04f3bSdan  faultsim_delete_and_reopen
39653f04f3bSdan  execsql {
39753f04f3bSdan    CREATE TABLE x(y, z);
39853f04f3bSdan    INSERT INTO x VALUES(1, 2);
39953f04f3bSdan  }
40053f04f3bSdan  set fd [open test.db-journal w]
40153f04f3bSdan  puts -nonewline $fd "helloworld"
40253f04f3bSdan  close $fd
40353f04f3bSdan  file exists test.db-journal
40453f04f3bSdan} {1}
40553f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
40653f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
40753f04f3bSdan
40853f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
40953f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
41053f04f3bSdan#
41153f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
41253f04f3bSdan# up the file system to contain two databases, two hot-journal files and
41353f04f3bSdan# a master-journal.
41453f04f3bSdan#
41553f04f3bSdando_test pager1.4.2.1 {
41653f04f3bSdan  testvfs tstvfs -default 1
41753f04f3bSdan  tstvfs filter xDelete
41853f04f3bSdan  tstvfs script xDeleteCallback
41953f04f3bSdan  proc xDeleteCallback {method file args} {
42053f04f3bSdan    set file [file tail $file]
42153f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
42253f04f3bSdan  }
42353f04f3bSdan  faultsim_delete_and_reopen
42453f04f3bSdan  db func a_string a_string
42553f04f3bSdan  execsql {
42653f04f3bSdan    ATTACH 'test.db2' AS aux;
42753f04f3bSdan    PRAGMA journal_mode = DELETE;
42853f04f3bSdan    PRAGMA main.cache_size = 10;
42953f04f3bSdan    PRAGMA aux.cache_size = 10;
43053f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
43153f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
43253f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
43353f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43453f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43553f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
43653f04f3bSdan    BEGIN;
43753f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
43853f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
43953f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
44053f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
44153f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
44253f04f3bSdan    COMMIT;
44353f04f3bSdan  }
44453f04f3bSdan  db close
44553f04f3bSdan  tstvfs delete
44653f04f3bSdan} {}
447b2f20bfcSshaneh
448b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
44953f04f3bSdando_test pager1.4.2.2 {
45053f04f3bSdan  faultsim_restore_and_reopen
45153f04f3bSdan  execsql {
45253f04f3bSdan    SELECT count(*) FROM t1;
45353f04f3bSdan    PRAGMA integrity_check;
45453f04f3bSdan  }
45553f04f3bSdan} {4 ok}
45653f04f3bSdando_test pager1.4.2.3 {
45753f04f3bSdan  faultsim_restore_and_reopen
458fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
45953f04f3bSdan  execsql {
46053f04f3bSdan    SELECT count(*) FROM t1;
46153f04f3bSdan    PRAGMA integrity_check;
46253f04f3bSdan  }
46353f04f3bSdan} {64 ok}
46453f04f3bSdando_test pager1.4.2.4 {
46553f04f3bSdan  faultsim_restore_and_reopen
4660971140bSdrh  hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
46753f04f3bSdan  execsql {
46853f04f3bSdan    SELECT count(*) FROM t1;
46953f04f3bSdan    PRAGMA integrity_check;
47053f04f3bSdan  }
47153f04f3bSdan} {4 ok}
47253f04f3bSdando_test pager1.4.2.5 {
47353f04f3bSdan  faultsim_restore_and_reopen
4740971140bSdrh  hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
475fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
47653f04f3bSdan  execsql {
47753f04f3bSdan    SELECT count(*) FROM t1;
47853f04f3bSdan    PRAGMA integrity_check;
47953f04f3bSdan  }
48053f04f3bSdan} {4 ok}
481b2f20bfcSshaneh}
48253f04f3bSdan
483de4996e2Sdando_test pager1.4.3.1 {
484de4996e2Sdan  testvfs tstvfs -default 1
485de4996e2Sdan  tstvfs filter xSync
486de4996e2Sdan  tstvfs script xSyncCallback
487de4996e2Sdan  proc xSyncCallback {method file args} {
488de4996e2Sdan    set file [file tail $file]
489de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
490de4996e2Sdan  }
491de4996e2Sdan  faultsim_delete_and_reopen
492de4996e2Sdan  execsql {
493de4996e2Sdan    PRAGMA journal_mode = DELETE;
494de4996e2Sdan    CREATE TABLE t1(a, b);
495de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
496de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
497de4996e2Sdan  }
498de4996e2Sdan  db close
499de4996e2Sdan  tstvfs delete
500de4996e2Sdan} {}
501de4996e2Sdan
502de4996e2Sdanforeach {tn ofst value result} {
503de4996e2Sdan          2   20    31       {1 2 3 4}
504de4996e2Sdan          3   20    32       {1 2 3 4}
505de4996e2Sdan          4   20    33       {1 2 3 4}
506de4996e2Sdan          5   20    65536    {1 2 3 4}
507de4996e2Sdan          6   20    131072   {1 2 3 4}
508de4996e2Sdan
509de4996e2Sdan          7   24    511      {1 2 3 4}
510de4996e2Sdan          8   24    513      {1 2 3 4}
511b2eced5dSdrh          9   24    131072   {1 2 3 4}
512de4996e2Sdan
513de4996e2Sdan         10   32    65536    {1 2}
514de4996e2Sdan} {
515de4996e2Sdan  do_test pager1.4.3.$tn {
516de4996e2Sdan    faultsim_restore_and_reopen
517de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
518de4996e2Sdan    execsql { SELECT * FROM t1 }
519de4996e2Sdan  } $result
520de4996e2Sdan}
521de4996e2Sdandb close
522de4996e2Sdan
523e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
524e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
525e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
526e08341c6Sdan# master journal file from the file-system.
527e08341c6Sdan#
5286aa18c95Smistachkinset pwd [get_pwd]
529e08341c6Sdantestvfs tv -default 1
530e08341c6Sdantv script copy_on_mj_delete
531e08341c6Sdanset ::mj_filename_length 0
532e08341c6Sdanproc copy_on_mj_delete {method filename args} {
533e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
534c5484654Smistachkin    #
535c5484654Smistachkin    # NOTE: Is the file name relative?  If so, add the length of the current
536c5484654Smistachkin    #       directory.
537c5484654Smistachkin    #
538c5484654Smistachkin    if {[is_relative_file $filename]} {
539c5484654Smistachkin      set ::mj_filename_length \
540c5484654Smistachkin        [expr {[string length $filename] + [string length $::pwd]}]
541c5484654Smistachkin    } else {
542e08341c6Sdan      set ::mj_filename_length [string length $filename]
543c5484654Smistachkin    }
544e08341c6Sdan    faultsim_save
545e08341c6Sdan  }
546e08341c6Sdan  return SQLITE_OK
547e08341c6Sdan}
548e08341c6Sdan
549e08341c6Sdanforeach {tn1 tcl} {
550e08341c6Sdan  1 { set prefix "test.db" }
551e08341c6Sdan  2 {
552e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
553e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
554e08341c6Sdan    # contains a master-journal pointer so large that it could contain
555e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
556e08341c6Sdan    # make sure SQLite doesn't get confused by this.
557e08341c6Sdan    #
558e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
55933d85c9cSshaneh    if {$tcl_platform(platform)=="windows"} {
56033d85c9cSshaneh      # TBD need to figure out how to do this correctly for Windows!!!
56133d85c9cSshaneh      set nPadding [expr 255 - $::mj_filename_length]
56233d85c9cSshaneh    }
563e08341c6Sdan
564e08341c6Sdan    # We cannot just create a really long database file name to open, as
565e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
566e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
567e08341c6Sdan    # hierarchy to work in.
568e08341c6Sdan    #
569e08341c6Sdan    set dirname "d123456789012345678901234567890/"
570e08341c6Sdan    set nDir [expr $nPadding / 32]
571e08341c6Sdan    if { $nDir } {
572e08341c6Sdan      set p [string repeat $dirname $nDir]
573e08341c6Sdan      file mkdir $p
574e08341c6Sdan      cd $p
575e08341c6Sdan    }
576e08341c6Sdan
577e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
578e08341c6Sdan    set prefix "test.db${padding}"
579e08341c6Sdan  }
580e08341c6Sdan} {
581e08341c6Sdan  eval $tcl
582e08341c6Sdan  foreach {tn2 sql} {
583e08341c6Sdan    o {
584e08341c6Sdan      PRAGMA main.synchronous=OFF;
585e08341c6Sdan      PRAGMA aux.synchronous=OFF;
5863f94b609Sdan      PRAGMA journal_mode = DELETE;
587e08341c6Sdan    }
588e08341c6Sdan    o512 {
589e08341c6Sdan      PRAGMA main.synchronous=OFF;
590e08341c6Sdan      PRAGMA aux.synchronous=OFF;
591e08341c6Sdan      PRAGMA main.page_size = 512;
592e08341c6Sdan      PRAGMA aux.page_size = 512;
5933f94b609Sdan      PRAGMA journal_mode = DELETE;
594e08341c6Sdan    }
595e08341c6Sdan    n {
596e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
597e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
5983f94b609Sdan      PRAGMA journal_mode = DELETE;
599e08341c6Sdan    }
600e08341c6Sdan    f {
601e08341c6Sdan      PRAGMA main.synchronous=FULL;
602e08341c6Sdan      PRAGMA aux.synchronous=FULL;
6033f94b609Sdan      PRAGMA journal_mode = DELETE;
604e08341c6Sdan    }
605e08341c6Sdan  } {
606e08341c6Sdan
607e08341c6Sdan    set tn "${tn1}.${tn2}"
608e08341c6Sdan
609e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
610e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
611e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
612e08341c6Sdan    # file is deleted to commit the transaction.
613e08341c6Sdan    #
614e08341c6Sdan    tv filter xDelete
615e08341c6Sdan    do_test pager1-4.4.$tn.1 {
616e08341c6Sdan      faultsim_delete_and_reopen $prefix
617e08341c6Sdan      execsql "
618e08341c6Sdan        ATTACH '${prefix}2' AS aux;
619e08341c6Sdan        $sql
620e08341c6Sdan        CREATE TABLE a(x);
621e08341c6Sdan        CREATE TABLE aux.b(x);
622e08341c6Sdan        INSERT INTO a VALUES('double-you');
623e08341c6Sdan        INSERT INTO a VALUES('why');
624e08341c6Sdan        INSERT INTO a VALUES('zed');
625e08341c6Sdan        INSERT INTO b VALUES('won');
626e08341c6Sdan        INSERT INTO b VALUES('too');
627e08341c6Sdan        INSERT INTO b VALUES('free');
628e08341c6Sdan      "
629e08341c6Sdan      execsql {
630e08341c6Sdan        BEGIN;
631e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
632e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
633e08341c6Sdan        COMMIT;
634e08341c6Sdan      }
635e08341c6Sdan    } {}
636e08341c6Sdan    tv filter {}
637e08341c6Sdan
638e08341c6Sdan    # Check that the transaction was committed successfully.
639e08341c6Sdan    #
640e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
641e08341c6Sdan      SELECT * FROM a
642e08341c6Sdan    } {double-you why zed won too free}
643e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
644e08341c6Sdan      SELECT * FROM b
645e08341c6Sdan    } {won too free double-you why zed}
646e08341c6Sdan
647e08341c6Sdan    # Restore the file-system and reopen the databases. Check that it now
648e08341c6Sdan    # appears that the transaction was not committed (because the file-system
649e08341c6Sdan    # was restored to the state where it had not been).
650e08341c6Sdan    #
651e08341c6Sdan    do_test pager1-4.4.$tn.4 {
652e08341c6Sdan      faultsim_restore_and_reopen $prefix
653e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
654e08341c6Sdan    } {}
655e08341c6Sdan    do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
656e08341c6Sdan    do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
657e08341c6Sdan
658e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
659e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
660e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
661e08341c6Sdan    #
662e08341c6Sdan    do_test pager1-4.4.$tn.7 {
663e08341c6Sdan      faultsim_restore_and_reopen $prefix
664fda06befSmistachkin      foreach f [glob ${prefix}-mj*] { forcedelete $f }
665e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
666e08341c6Sdan    } {}
667e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
668e08341c6Sdan      SELECT * FROM a
669e08341c6Sdan    } {double-you why zed won too free}
670e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
671e08341c6Sdan      SELECT * FROM b
672e08341c6Sdan    } {won too free double-you why zed}
673e08341c6Sdan  }
674e08341c6Sdan
675e08341c6Sdan  cd $pwd
676e08341c6Sdan}
677e08341c6Sdandb close
678e08341c6Sdantv delete
679fda06befSmistachkinforcedelete $dirname
6800e986f51Sdan
6810e986f51Sdan
6820e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
6830e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
6840e986f51Sdan# two database pages (and page 1 - the change counter).
6850e986f51Sdan#
6860e986f51Sdantestvfs tv -default 1
6870e986f51Sdantv sectorsize 512
6880e986f51Sdantv script copy_on_journal_delete
6890e986f51Sdantv filter xDelete
6900e986f51Sdanproc copy_on_journal_delete {method filename args} {
6910e986f51Sdan  if {[string match *journal $filename]} faultsim_save
6920e986f51Sdan  return SQLITE_OK
6930e986f51Sdan}
6940e986f51Sdanfaultsim_delete_and_reopen
6950e986f51Sdando_execsql_test pager1.4.5.1 {
6963f94b609Sdan  PRAGMA journal_mode = DELETE;
6970e986f51Sdan  PRAGMA page_size = 1024;
6980e986f51Sdan  CREATE TABLE t1(a, b);
6990e986f51Sdan  CREATE TABLE t2(a, b);
7000e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
7010e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
7020e986f51Sdan  BEGIN;
7030e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
7040e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
7050e986f51Sdan  COMMIT;
7063f94b609Sdan} {delete}
7070e986f51Sdantv filter {}
7080e986f51Sdan
7090e986f51Sdan# Check the transaction was committed:
7100e986f51Sdan#
7110e986f51Sdando_execsql_test pager1.4.5.2 {
7120e986f51Sdan  SELECT * FROM t1;
7130e986f51Sdan  SELECT * FROM t2;
7140e986f51Sdan} {I II 1 2 III IV 3 4}
7150e986f51Sdan
716ec6ffc1aSdan# Now try four tests:
7170e986f51Sdan#
7180e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
7190e986f51Sdan#                is rolled back.
7200e986f51Sdan#
7210e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
7220e986f51Sdan#                journal. Check the transaction is not rolled back.
7230e986f51Sdan#
7240e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
7250e986f51Sdan#                journal. Check that the first record in the transaction is
7260e986f51Sdan#                played back, but not the second.
7270e986f51Sdan#
72810f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
72910f5a50eSdan#                readonly connection. This should fail, as a read-only
73010f5a50eSdan#                connection cannot roll back the database file.
73110f5a50eSdan#
7320e986f51Sdanfaultsim_restore_and_reopen
7330e986f51Sdando_execsql_test pager1.4.5.3 {
7340e986f51Sdan  SELECT * FROM t1;
7350e986f51Sdan  SELECT * FROM t2;
7360e986f51Sdan} {I II III IV}
7370e986f51Sdanfaultsim_restore_and_reopen
7380e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
7390e986f51Sdando_execsql_test pager1.4.5.4 {
7400e986f51Sdan  SELECT * FROM t1;
7410e986f51Sdan  SELECT * FROM t2;
7420e986f51Sdan} {I II 1 2 III IV 3 4}
7430e986f51Sdanfaultsim_restore_and_reopen
7440e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
7450e986f51Sdando_execsql_test pager1.4.5.5 {
7460e986f51Sdan  SELECT * FROM t1;
7470e986f51Sdan  SELECT * FROM t2;
7480e986f51Sdan} {I II III IV 3 4}
7490e986f51Sdan
75010f5a50eSdanfaultsim_restore_and_reopen
75110f5a50eSdandb close
75210f5a50eSdansqlite3 db test.db -readonly 1
75310f5a50eSdando_catchsql_test pager1.4.5.6 {
75410f5a50eSdan  SELECT * FROM t1;
75510f5a50eSdan  SELECT * FROM t2;
756b83c21e6Sdan} {1 {attempt to write a readonly database}}
757ec6ffc1aSdandb close
758ec6ffc1aSdan
759ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
760ec6ffc1aSdan# of the master journal file in $::mj_filename.
761ec6ffc1aSdan#
762ec6ffc1aSdantv script copy_on_mj_delete
763ec6ffc1aSdantv filter xDelete
764ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
765ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
766ec6ffc1aSdan    set ::mj_filename $filename
767ec6ffc1aSdan    faultsim_save
768ec6ffc1aSdan  }
769ec6ffc1aSdan  return SQLITE_OK
770ec6ffc1aSdan}
771ec6ffc1aSdando_test pager1.4.6.1 {
772ec6ffc1aSdan  faultsim_delete_and_reopen
773ec6ffc1aSdan  execsql {
7743f94b609Sdan    PRAGMA journal_mode = DELETE;
775ec6ffc1aSdan    ATTACH 'test.db2' AS two;
776ec6ffc1aSdan    CREATE TABLE t1(a, b);
777ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
778ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
779ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
780ec6ffc1aSdan    BEGIN;
781ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
782ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
783ec6ffc1aSdan    COMMIT;
784ec6ffc1aSdan  }
785ec6ffc1aSdan  tv filter {}
786ec6ffc1aSdan  db close
787ec6ffc1aSdan} {}
788ec6ffc1aSdan
789ec6ffc1aSdanfaultsim_restore_and_reopen
790ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
791ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
792ec6ffc1aSdando_execsql_test pager1.4.6.4 {
793ec6ffc1aSdan  ATTACH 'test.db2' AS two;
794ec6ffc1aSdan  SELECT * FROM t2;
795ec6ffc1aSdan} {1 t2.1}
796ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
797ec6ffc1aSdan
798ec6ffc1aSdanfaultsim_restore_and_reopen
799ec6ffc1aSdandb close
800ec6ffc1aSdando_test pager1.4.6.8 {
801ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
802ec6ffc1aSdan  tv filter xDelete
803ec6ffc1aSdan  sqlite3 db test.db2
804ec6ffc1aSdan  execsql {
8053f94b609Sdan    PRAGMA journal_mode = DELETE;
806ec6ffc1aSdan    ATTACH 'test.db3' AS three;
807ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
808ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
809ec6ffc1aSdan    BEGIN;
810ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
811ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
812ec6ffc1aSdan    COMMIT;
813ec6ffc1aSdan  }
814ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
815ec6ffc1aSdan} {1}
816ec6ffc1aSdanfaultsim_restore_and_reopen
817ec6ffc1aSdantv filter {}
818ec6ffc1aSdan
819ec6ffc1aSdan# The file-system now contains:
820ec6ffc1aSdan#
821ec6ffc1aSdan#   * three databases
822ec6ffc1aSdan#   * three hot-journal files
823ec6ffc1aSdan#   * two master-journal files.
824ec6ffc1aSdan#
825ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
826ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
827ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
828ec6ffc1aSdan# test.db should delete $::mj_filename1.
829ec6ffc1aSdan#
830ec6ffc1aSdando_test pager1.4.6.9 {
831ec6ffc1aSdan  lsort [glob test.db*]
832ec6ffc1aSdan} [lsort [list                                           \
833ec6ffc1aSdan  test.db test.db2 test.db3                              \
834ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
835ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
836ec6ffc1aSdan]]
837ec6ffc1aSdan
838ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
839ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
840ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
841ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
842ec6ffc1aSdan#
843ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
844ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
845ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
846ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
847ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
848ec6ffc1aSdan
849ec6ffc1aSdando_execsql_test pager1.4.6.12 {
850ec6ffc1aSdan  ATTACH 'test.db2' AS two;
851ec6ffc1aSdan  SELECT * FROM t2;
852ec6ffc1aSdan} {1 t2.1}
853ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
854ec6ffc1aSdando_execsql_test pager1.4.6.14 {
855ec6ffc1aSdan  ATTACH 'test.db3' AS three;
856ec6ffc1aSdan  SELECT * FROM t3;
857ec6ffc1aSdan} {1 t3.1}
858ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
85910f5a50eSdan
8600e986f51Sdandb close
8610e986f51Sdantv delete
862e08341c6Sdan
863c8ce3972Sdantestvfs tv -default 1
864c8ce3972Sdantv sectorsize 512
865c8ce3972Sdantv script copy_on_journal_delete
866c8ce3972Sdantv filter xDelete
867c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
868c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
869c8ce3972Sdan  return SQLITE_OK
870c8ce3972Sdan}
871c8ce3972Sdanfaultsim_delete_and_reopen
872c8ce3972Sdando_execsql_test pager1.4.7.1 {
8733f94b609Sdan  PRAGMA journal_mode = DELETE;
874c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
875c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
876c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
877c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
878c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
879c8ce3972Sdan  BEGIN;
880c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
881c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
882c8ce3972Sdan  COMMIT;
8833f94b609Sdan} {delete}
884c8ce3972Sdantv filter {}
885c8ce3972Sdandb close
886c8ce3972Sdantv delete
887e1186ab2Sdrhcatch {
888e1186ab2Sdrh  test_syscall install fchmod
889e1186ab2Sdrh  test_syscall fault 1 1
890e1186ab2Sdrh}
891c8ce3972Sdando_test pager1.4.7.2 {
892c8ce3972Sdan  faultsim_restore_and_reopen
893c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
894c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
895c8ce3972Sdan  catchsql { SELECT * FROM t1 }
896c8ce3972Sdan} {1 {unable to open database file}}
897e1186ab2Sdrhcatch {
898e1186ab2Sdrh  test_syscall reset
899e1186ab2Sdrh  test_syscall fault 0 0
900e1186ab2Sdrh}
901c8ce3972Sdando_test pager1.4.7.3 {
902c8ce3972Sdan  db close
903c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
904c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
905fda06befSmistachkin  delete_file test.db-journal
906c8ce3972Sdan  file exists test.db-journal
907c8ce3972Sdan} {0}
908421377e6Sdrhdo_test pager1.4.8.1 {
909421377e6Sdrh  catch {file attributes test.db -permissions r--------}
910421377e6Sdrh  catch {file attributes test.db -readonly 1}
911421377e6Sdrh  sqlite3 db test.db
912421377e6Sdrh  db eval { SELECT * FROM t1 }
913421377e6Sdrh  sqlite3_db_readonly db main
914421377e6Sdrh} {1}
915421377e6Sdrhdo_test pager1.4.8.2 {
916421377e6Sdrh  sqlite3_db_readonly db xyz
917421377e6Sdrh} {-1}
918421377e6Sdrhdo_test pager1.4.8.3 {
919421377e6Sdrh  db close
920421377e6Sdrh  catch {file attributes test.db -readonly 0}
921db0ad5f2Sdan  catch {file attributes test.db -permissions rw-rw-rw-} msg
922421377e6Sdrh  sqlite3 db test.db
923421377e6Sdrh  db eval { SELECT * FROM t1 }
924421377e6Sdrh  sqlite3_db_readonly db main
925421377e6Sdrh} {0}
926c8ce3972Sdan
927de4996e2Sdan#-------------------------------------------------------------------------
928146ed78bSdan# The following tests deal with multi-file commits.
929de4996e2Sdan#
930146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
931146ed78bSdan#               another connection is holding a SHARED lock on one of the
932146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
933146ed78bSdan#
934146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
935146ed78bSdan#
936146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
937146ed78bSdan#
938146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
939146ed78bSdan#               name is added to a journal file immediately after the last
940146ed78bSdan#               journal record. But with synchronous=full, extra unused space
941146ed78bSdan#               is allocated between the last journal record and the
942146ed78bSdan#               master-journal file name so that the master-journal file
943146ed78bSdan#               name does not lie on the same sector as the last journal file
944146ed78bSdan#               record.
945146ed78bSdan#
946e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
947e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
948e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
949e08341c6Sdan#
950146ed78bSdan#
951146ed78bSdando_test pager1-5.1.1 {
952146ed78bSdan  faultsim_delete_and_reopen
953146ed78bSdan  execsql {
954146ed78bSdan    ATTACH 'test.db2' AS aux;
955146ed78bSdan    CREATE TABLE t1(a, b);
956146ed78bSdan    CREATE TABLE aux.t2(a, b);
957146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
958146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
959146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
960146ed78bSdan  }
961146ed78bSdan} {}
962146ed78bSdando_test pager1-5.1.2 {
963146ed78bSdan  execsql {
964146ed78bSdan    BEGIN;
965146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
966146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
967146ed78bSdan  }
968146ed78bSdan  sqlite3 db2 test.db2
969146ed78bSdan  execsql {
970146ed78bSdan    BEGIN;
971146ed78bSdan      SELECT * FROM t2;
972146ed78bSdan  } db2
973146ed78bSdan} {}
974146ed78bSdando_test pager1-5.1.3 {
975146ed78bSdan  catchsql COMMIT
976146ed78bSdan} {1 {database is locked}}
977146ed78bSdando_test pager1-5.1.4 {
978146ed78bSdan  execsql COMMIT db2
979146ed78bSdan  execsql COMMIT
980146ed78bSdan  execsql { SELECT * FROM t2 } db2
981146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
982146ed78bSdando_test pager1-5.1.5 {
983146ed78bSdan  db2 close
984146ed78bSdan} {}
985146ed78bSdan
986146ed78bSdando_test pager1-5.2.1 {
987146ed78bSdan  execsql {
988146ed78bSdan    PRAGMA journal_mode = memory;
989146ed78bSdan    BEGIN;
990146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
991146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
992146ed78bSdan    COMMIT;
993146ed78bSdan  }
994146ed78bSdan} {memory}
995146ed78bSdando_test pager1-5.3.1 {
996146ed78bSdan  execsql {
997146ed78bSdan    PRAGMA journal_mode = off;
998146ed78bSdan    BEGIN;
999146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1000146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1001146ed78bSdan    COMMIT;
1002146ed78bSdan  }
1003146ed78bSdan} {off}
1004146ed78bSdan
1005146ed78bSdando_test pager1-5.4.1 {
1006146ed78bSdan  db close
1007146ed78bSdan  testvfs tv
1008146ed78bSdan  sqlite3 db test.db -vfs tv
1009146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
1010146ed78bSdan
1011146ed78bSdan  tv filter xDelete
1012146ed78bSdan  tv script max_journal_size
1013146ed78bSdan  tv sectorsize 512
1014146ed78bSdan  set ::max_journal 0
1015146ed78bSdan  proc max_journal_size {method args} {
1016146ed78bSdan    set sz 0
1017146ed78bSdan    catch { set sz [file size test.db-journal] }
1018146ed78bSdan    if {$sz > $::max_journal} {
1019146ed78bSdan      set ::max_journal $sz
1020146ed78bSdan    }
1021146ed78bSdan    return SQLITE_OK
1022146ed78bSdan  }
1023146ed78bSdan  execsql {
1024146ed78bSdan    PRAGMA journal_mode = DELETE;
1025146ed78bSdan    PRAGMA synchronous = NORMAL;
1026146ed78bSdan    BEGIN;
1027146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1028146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1029146ed78bSdan    COMMIT;
1030146ed78bSdan  }
10317f9026ddSdan
10327f9026ddSdan  # The size of the journal file is now:
10337f9026ddSdan  #
10347f9026ddSdan  #   1) 512 byte header +
10357f9026ddSdan  #   2) 2 * (1024+8) byte records +
10367f9026ddSdan  #   3) 20+N bytes of master-journal pointer, where N is the size of
10377f9026ddSdan  #      the master-journal name encoded as utf-8 with no nul term.
10387f9026ddSdan  #
10397f9026ddSdan  set mj_pointer [expr {
1040c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
10417f9026ddSdan  }]
1042c5484654Smistachkin  #
1043c5484654Smistachkin  #   NOTE: For item 3 above, if the current SQLite VFS lacks the concept of a
1044c5484654Smistachkin  #         current directory, the length of the current directory name plus 1
1045c5484654Smistachkin  #         character for the directory separator character are NOT counted as
1046c5484654Smistachkin  #         part of the total size; otherwise, they are.
1047c5484654Smistachkin  #
1048c5484654Smistachkin  ifcapable curdir {
10496aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1050c5484654Smistachkin  }
10517f9026ddSdan  expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
10527f9026ddSdan} 1
1053146ed78bSdando_test pager1-5.4.2 {
1054146ed78bSdan  set ::max_journal 0
1055146ed78bSdan  execsql {
1056146ed78bSdan    PRAGMA synchronous = full;
1057146ed78bSdan    BEGIN;
1058146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
1059146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
1060146ed78bSdan    COMMIT;
1061146ed78bSdan  }
10627f9026ddSdan
10637f9026ddSdan  # In synchronous=full mode, the master-journal pointer is not written
10647f9026ddSdan  # directly after the last record in the journal file. Instead, it is
10657f9026ddSdan  # written starting at the next (in this case 512 byte) sector boundary.
10667f9026ddSdan  #
10677f9026ddSdan  set mj_pointer [expr {
1068c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
10697f9026ddSdan  }]
1070c5484654Smistachkin  #
1071c5484654Smistachkin  #   NOTE: If the current SQLite VFS lacks the concept of a current directory,
1072c5484654Smistachkin  #         the length of the current directory name plus 1 character for the
1073c5484654Smistachkin  #         directory separator character are NOT counted as part of the total
1074c5484654Smistachkin  #         size; otherwise, they are.
1075c5484654Smistachkin  #
1076c5484654Smistachkin  ifcapable curdir {
10776aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1078c5484654Smistachkin  }
10797f9026ddSdan  expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
10807f9026ddSdan} 1
1081146ed78bSdandb close
1082146ed78bSdantv delete
1083146ed78bSdan
1084146ed78bSdando_test pager1-5.5.1 {
1085146ed78bSdan  sqlite3 db test.db
1086146ed78bSdan  execsql {
1087146ed78bSdan    ATTACH 'test.db2' AS aux;
1088146ed78bSdan    PRAGMA journal_mode = PERSIST;
1089146ed78bSdan    CREATE TABLE t3(a, b);
1090146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
1091146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
1092146ed78bSdan  }
1093146ed78bSdan  expr [file size test.db-journal] > 15000
1094146ed78bSdan} {1}
1095146ed78bSdando_test pager1-5.5.2 {
1096146ed78bSdan  execsql {
1097146ed78bSdan    PRAGMA synchronous = full;
1098146ed78bSdan    BEGIN;
1099146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
1100146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
1101146ed78bSdan    COMMIT;
1102146ed78bSdan  }
1103146ed78bSdan  file size test.db-journal
1104146ed78bSdan} {0}
1105146ed78bSdan
1106146ed78bSdan
1107146ed78bSdan#-------------------------------------------------------------------------
1108146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1109146ed78bSdan#
1110146ed78bSdando_test pager1-6.1 {
1111146ed78bSdan  faultsim_delete_and_reopen
1112146ed78bSdan  execsql {
1113f43d7fceSdan    PRAGMA auto_vacuum = none;
1114146ed78bSdan    PRAGMA max_page_count = 10;
1115146ed78bSdan    CREATE TABLE t2(a, b);
1116146ed78bSdan    CREATE TABLE t3(a, b);
1117146ed78bSdan    CREATE TABLE t4(a, b);
1118146ed78bSdan    CREATE TABLE t5(a, b);
1119146ed78bSdan    CREATE TABLE t6(a, b);
1120146ed78bSdan    CREATE TABLE t7(a, b);
1121146ed78bSdan    CREATE TABLE t8(a, b);
1122146ed78bSdan    CREATE TABLE t9(a, b);
1123146ed78bSdan    CREATE TABLE t10(a, b);
1124146ed78bSdan  }
1125146ed78bSdan} {10}
1126d353331aSdando_catchsql_test pager1-6.2 {
1127d353331aSdan  CREATE TABLE t11(a, b)
1128146ed78bSdan} {1 {database or disk is full}}
1129d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1130d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1131d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1132d353331aSdando_execsql_test pager1-6.7 {
1133d353331aSdan  BEGIN;
1134d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1135d353331aSdan    PRAGMA max_page_count = 13;
1136d353331aSdan} {13}
1137d353331aSdando_execsql_test pager1-6.8 {
1138d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1139d353331aSdan    PRAGMA max_page_count = 10;
1140d353331aSdan} {11}
1141d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1142de4996e2Sdan
114360ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
114422b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
114522b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
114622b328b2Sdan
1147153eda0aSdan
1148153eda0aSdan#-------------------------------------------------------------------------
1149153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1150153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1151153eda0aSdan#
1152153eda0aSdan# Each test is specified with 5 variables. As follows:
1153153eda0aSdan#
1154153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1155153eda0aSdan#   $sql: SQL to execute.
1156153eda0aSdan#   $res: Expected result of executing $sql.
1157153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1158153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1159153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1160153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1161153eda0aSdan#
116238e1a279Sdanifcapable wal {
1163153eda0aSdan  faultsim_delete_and_reopen
1164153eda0aSdan  foreach {tn sql res js ws} [subst {
1165153eda0aSdan
1166153eda0aSdan    1  {
1167153eda0aSdan      CREATE TABLE t1(a, b);
1168153eda0aSdan      PRAGMA auto_vacuum=OFF;
1169153eda0aSdan      PRAGMA synchronous=NORMAL;
1170153eda0aSdan      PRAGMA page_size=1024;
1171153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1172153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1173153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1174153eda0aSdan    } {exclusive truncate} 0 -1
1175153eda0aSdan
1176153eda0aSdan    2  {
1177153eda0aSdan      BEGIN IMMEDIATE;
1178153eda0aSdan        SELECT * FROM t1;
1179153eda0aSdan      COMMIT;
1180153eda0aSdan    } {1 2} 0 -1
1181153eda0aSdan
1182153eda0aSdan    3  {
1183153eda0aSdan      BEGIN;
1184153eda0aSdan        SELECT * FROM t1;
1185153eda0aSdan      COMMIT;
1186153eda0aSdan    } {1 2} 0 -1
1187153eda0aSdan
1188153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal       -1 -1
1189153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}        -1 [wal_file_size 1 1024]
11908c408004Sdan    6  { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
1191153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
1192153eda0aSdan
1193153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1194153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1195153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1196153eda0aSdan
1197153eda0aSdan  }] {
1198153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1199153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1200153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1201153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1202153eda0aSdan  }
120338e1a279Sdan}
1204153eda0aSdan
120589ccf448Sdando_test pager1-7.2.1 {
120689ccf448Sdan  faultsim_delete_and_reopen
120789ccf448Sdan  execsql {
120889ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
120989ccf448Sdan    CREATE TABLE t1(a, b);
121089ccf448Sdan    BEGIN;
121189ccf448Sdan      PRAGMA journal_mode = delete;
121289ccf448Sdan      PRAGMA journal_mode = truncate;
121389ccf448Sdan  }
121489ccf448Sdan} {exclusive delete truncate}
121589ccf448Sdando_test pager1-7.2.2 {
121689ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
121789ccf448Sdan  execsql { PRAGMA journal_mode = persist }
121889ccf448Sdan} {truncate}
121989ccf448Sdando_test pager1-7.2.3 {
122089ccf448Sdan  execsql { COMMIT }
122189ccf448Sdan  execsql {
122289ccf448Sdan    PRAGMA journal_mode = persist;
122389ccf448Sdan    PRAGMA journal_size_limit;
122489ccf448Sdan  }
122589ccf448Sdan} {persist -1}
122689ccf448Sdan
1227d353331aSdan#-------------------------------------------------------------------------
1228d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1229d353331aSdan# ":memory:" and "" open temporary databases.
1230d353331aSdan#
12310e986f51Sdanforeach {tn filename} {
12320e986f51Sdan  1 :memory:
12330e986f51Sdan  2 ""
12340e986f51Sdan} {
12350e986f51Sdan  do_test pager1-8.$tn.1 {
1236153eda0aSdan    faultsim_delete_and_reopen
1237153eda0aSdan    db close
12380e986f51Sdan    sqlite3 db $filename
1239153eda0aSdan    execsql {
1240c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1241153eda0aSdan      CREATE TABLE x1(x);
1242153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1243153eda0aSdan      INSERT INTO x1 VALUES('James');
1244153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1245153eda0aSdan      SELECT * FROM x1;
1246153eda0aSdan    }
1247153eda0aSdan  } {Charles James Mary}
12480e986f51Sdan
12490e986f51Sdan  do_test pager1-8.$tn.2 {
12500e986f51Sdan    sqlite3 db2 $filename
12510e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1252153eda0aSdan  } {1 {no such table: x1}}
1253153eda0aSdan
12540e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
12550e986f51Sdan    BEGIN;
12560e986f51Sdan      INSERT INTO x1 VALUES('William');
12570e986f51Sdan      INSERT INTO x1 VALUES('Anne');
12580e986f51Sdan    ROLLBACK;
12590e986f51Sdan  } {}
12600e986f51Sdan}
12610e986f51Sdan
1262dca321aeSdan#-------------------------------------------------------------------------
1263dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1264dca321aeSdan# the pager and the backup API. Test cases:
1265dca321aeSdan#
1266dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1267dca321aeSdan#                 source db is written to during the backup op.
1268dca321aeSdan#
1269dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1270dca321aeSdan#                 source db is written to and then rolled back during a
1271dca321aeSdan#                 backup operation.
1272dca321aeSdan#
1273dca321aeSdando_test pager1-9.0.1 {
1274dca321aeSdan  faultsim_delete_and_reopen
1275dca321aeSdan  db func a_string a_string
1276dca321aeSdan  execsql {
1277dca321aeSdan    PRAGMA cache_size = 10;
1278dca321aeSdan    BEGIN;
1279dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1280dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1281dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1282dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1283dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1284dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1285dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1286dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1287dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1288dca321aeSdan    COMMIT;
1289dca321aeSdan  }
1290dca321aeSdan} {}
1291dca321aeSdando_test pager1-9.0.2 {
1292dca321aeSdan  sqlite3 db2 test.db2
1293dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1294dca321aeSdan  sqlite3_backup B db2 main db main
1295dca321aeSdan  list [B step 10000] [B finish]
1296dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1297dca321aeSdando_test pager1-9.0.3 {
1298dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1299dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1300dca321aeSdan
1301dca321aeSdando_test pager1-9.1.1 {
1302dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1303dca321aeSdan  sqlite3_backup B db2 main db main
1304dca321aeSdan  B step 30
1305dca321aeSdan} {SQLITE_OK}
1306dca321aeSdando_test pager1-9.1.2 {
1307dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1308dca321aeSdan  list [B step 10000] [B finish]
1309dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1310dca321aeSdando_test pager1-9.1.3 {
1311dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1312dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1313dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1314dca321aeSdan
1315dca321aeSdando_test pager1-9.2.1 {
1316dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1317dca321aeSdan  sqlite3_backup B db2 main db main
1318dca321aeSdan  B step 30
1319dca321aeSdan} {SQLITE_OK}
1320dca321aeSdando_test pager1-9.2.2 {
1321dca321aeSdan  execsql {
1322dca321aeSdan    BEGIN;
1323dca321aeSdan      UPDATE ab SET b = a_string(301);
1324dca321aeSdan    ROLLBACK;
1325dca321aeSdan  }
1326dca321aeSdan  list [B step 10000] [B finish]
1327dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1328dca321aeSdando_test pager1-9.2.3 {
1329dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1330dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1331dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1332ec6ffc1aSdandb close
1333ec6ffc1aSdandb2 close
1334ec6ffc1aSdan
1335c396d4afSdando_test pager1-9.3.1 {
1336c396d4afSdan  testvfs tv -default 1
1337c396d4afSdan  tv sectorsize 4096
1338c396d4afSdan  faultsim_delete_and_reopen
1339c396d4afSdan
1340c396d4afSdan  execsql { PRAGMA page_size = 1024 }
1341c396d4afSdan  for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
1342c396d4afSdan} {}
1343c396d4afSdando_test pager1-9.3.2 {
1344c396d4afSdan  sqlite3 db2 test.db2
1345f412ee2eSdan
1346c396d4afSdan  execsql {
1347c396d4afSdan    PRAGMA page_size = 4096;
1348c396d4afSdan    PRAGMA synchronous = OFF;
1349c396d4afSdan    CREATE TABLE t1(a, b);
1350c396d4afSdan    CREATE TABLE t2(a, b);
1351c396d4afSdan  } db2
1352c396d4afSdan
1353c396d4afSdan  sqlite3_backup B db2 main db main
1354c396d4afSdan  B step 30
1355c396d4afSdan  list [B step 10000] [B finish]
1356c396d4afSdan} {SQLITE_DONE SQLITE_OK}
1357c396d4afSdando_test pager1-9.3.3 {
1358c396d4afSdan  db2 close
1359c396d4afSdan  db close
1360c396d4afSdan  tv delete
1361c396d4afSdan  file size test.db2
1362c396d4afSdan} [file size test.db]
1363c396d4afSdan
1364f412ee2eSdando_test pager1-9.4.1 {
1365f412ee2eSdan  faultsim_delete_and_reopen
1366f412ee2eSdan  sqlite3 db2 test.db2
1367f412ee2eSdan  execsql {
1368f412ee2eSdan    PRAGMA page_size = 4096;
1369f412ee2eSdan    CREATE TABLE t1(a, b);
1370f412ee2eSdan    CREATE TABLE t2(a, b);
1371f412ee2eSdan  } db2
1372f412ee2eSdan  sqlite3_backup B db2 main db main
1373f412ee2eSdan  list [B step 10000] [B finish]
1374f412ee2eSdan} {SQLITE_DONE SQLITE_OK}
1375f412ee2eSdando_test pager1-9.4.2 {
1376f412ee2eSdan  list [file size test.db2] [file size test.db]
1377b483eba0Sdan} {1024 0}
137833d85c9cSshanehdb2 close
1379d0b0d4dcSdan
1380ec6ffc1aSdan#-------------------------------------------------------------------------
1381ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1382ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1383ec6ffc1aSdan#
1384ec6ffc1aSdantestvfs tv -default 1
1385ec6ffc1aSdanforeach sectorsize {
1386d7a558a9Sdan    16
1387ec6ffc1aSdan    32   64   128   256   512   1024   2048
1388ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1389ec6ffc1aSdan} {
1390ec6ffc1aSdan  tv sectorsize $sectorsize
13911eaaf93aSdrh  tv devchar {}
1392ec6ffc1aSdan  set eff $sectorsize
1393ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1394ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1395ec6ffc1aSdan
1396d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1397ec6ffc1aSdan    faultsim_delete_and_reopen
1398d0b0d4dcSdan    db func a_string a_string
1399ec6ffc1aSdan    execsql {
1400ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1401ec6ffc1aSdan      PRAGMA page_size = 1024;
1402d0b0d4dcSdan      BEGIN;
1403ec6ffc1aSdan        CREATE TABLE t1(a, b);
1404d0b0d4dcSdan        CREATE TABLE t2(a, b);
1405d0b0d4dcSdan        CREATE TABLE t3(a, b);
1406d0b0d4dcSdan      COMMIT;
1407ec6ffc1aSdan    }
1408ec6ffc1aSdan    file size test.db-journal
1409d7a558a9Sdan  } [expr $sectorsize > 65536 ? 65536 : ($sectorsize<32 ? 512 : $sectorsize)]
1410d0b0d4dcSdan
1411d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1412d0b0d4dcSdan    execsql {
1413d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1414d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1415d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1416d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1417d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1418d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1419ec6ffc1aSdan    }
1420d0b0d4dcSdan  } {}
1421d0b0d4dcSdan
1422d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1423d0b0d4dcSdan    db close
1424d0b0d4dcSdan    sqlite3 db test.db
1425d0b0d4dcSdan    execsql {
1426d0b0d4dcSdan      PRAGMA cache_size = 10;
1427d0b0d4dcSdan      BEGIN;
1428d0b0d4dcSdan    }
1429d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1430d0b0d4dcSdan    execsql {
1431d0b0d4dcSdan      COMMIT;
1432d0b0d4dcSdan      SELECT * FROM t2;
1433d0b0d4dcSdan    }
1434d0b0d4dcSdan  } {1 2}
1435d0b0d4dcSdan
1436d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1437d0b0d4dcSdan    execsql {
1438d0b0d4dcSdan      CREATE TABLE t6(a, b);
1439d0b0d4dcSdan      CREATE TABLE t7(a, b);
1440d0b0d4dcSdan      CREATE TABLE t5(a, b);
1441d0b0d4dcSdan      DROP TABLE t6;
1442d0b0d4dcSdan      DROP TABLE t7;
1443d0b0d4dcSdan    }
1444d0b0d4dcSdan    execsql {
1445d0b0d4dcSdan      BEGIN;
1446d0b0d4dcSdan        CREATE TABLE t6(a, b);
1447d0b0d4dcSdan    }
1448d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1449d0b0d4dcSdan    execsql {
1450d0b0d4dcSdan      COMMIT;
1451d0b0d4dcSdan      SELECT * FROM t5;
1452d0b0d4dcSdan    }
1453d0b0d4dcSdan  } {1 2}
1454d0b0d4dcSdan
1455d0b0d4dcSdan}
1456d0b0d4dcSdandb close
1457d0b0d4dcSdan
1458d0b0d4dcSdantv sectorsize 4096
1459d0b0d4dcSdando_test pager1.10.x.1 {
1460d0b0d4dcSdan  faultsim_delete_and_reopen
1461d0b0d4dcSdan  execsql {
1462f43d7fceSdan    PRAGMA auto_vacuum = none;
1463d0b0d4dcSdan    PRAGMA page_size = 1024;
1464d0b0d4dcSdan    CREATE TABLE t1(x);
1465d0b0d4dcSdan  }
1466d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1467d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1468d0b0d4dcSdan  }
1469d0b0d4dcSdan  file size test.db
1470d0b0d4dcSdan} {32768}
1471d0b0d4dcSdando_test pager1.10.x.2 {
1472d0b0d4dcSdan  execsql {
1473d0b0d4dcSdan    CREATE TABLE t2(x);
1474d0b0d4dcSdan    DROP TABLE t2;
1475d0b0d4dcSdan  }
1476d0b0d4dcSdan  file size test.db
1477d0b0d4dcSdan} {33792}
1478d0b0d4dcSdando_test pager1.10.x.3 {
1479d0b0d4dcSdan  execsql {
1480d0b0d4dcSdan    BEGIN;
1481d0b0d4dcSdan    CREATE TABLE t2(x);
1482d0b0d4dcSdan  }
1483d0b0d4dcSdan  recursive_select 30 t1
1484d0b0d4dcSdan  execsql {
1485d0b0d4dcSdan    CREATE TABLE t3(x);
1486d0b0d4dcSdan    COMMIT;
1487d0b0d4dcSdan  }
1488d0b0d4dcSdan} {}
1489d0b0d4dcSdan
1490ec6ffc1aSdandb close
1491ec6ffc1aSdantv delete
1492ec6ffc1aSdan
1493ec6ffc1aSdantestvfs tv -default 1
1494ec6ffc1aSdanfaultsim_delete_and_reopen
1495ec6ffc1aSdandb func a_string a_string
1496ec6ffc1aSdando_execsql_test pager1-11.1 {
14973f94b609Sdan  PRAGMA journal_mode = DELETE;
1498ec6ffc1aSdan  PRAGMA cache_size = 10;
1499ec6ffc1aSdan  BEGIN;
1500ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1501ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1502ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1503ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1504ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1505ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1506ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1507ec6ffc1aSdan  COMMIT;
1508ec6ffc1aSdan  BEGIN;
1509ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
15103f94b609Sdan} {delete}
1511ec6ffc1aSdan
1512ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1513ec6ffc1aSdantv script lockout
1514ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1515ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1516ec6ffc1aSdan
1517ec6ffc1aSdantv script {}
1518ec6ffc1aSdando_test pager1-11.3 {
1519ec6ffc1aSdan  sqlite3 db2 test.db
1520ec6ffc1aSdan  execsql {
1521ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1522ec6ffc1aSdan    PRAGMA integrity_check;
1523ec6ffc1aSdan  } db2
1524ec6ffc1aSdan} {truncate ok}
1525ec6ffc1aSdando_test pager1-11.4 {
1526ec6ffc1aSdan  db2 close
1527f6c61471Sdan  file exists test.db-journal
1528ec6ffc1aSdan} {0}
1529ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1530f9b4419dSdandb close
1531f9b4419dSdantv delete
1532ec6ffc1aSdan
1533f9b4419dSdan#-------------------------------------------------------------------------
1534f9b4419dSdan# Test "PRAGMA page_size"
1535f9b4419dSdan#
1536f43d7fceSdantestvfs tv -default 1
1537f43d7fceSdantv sectorsize 1024
1538f9b4419dSdanforeach pagesize {
1539f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1540f9b4419dSdan} {
1541f9b4419dSdan  faultsim_delete_and_reopen
1542f9b4419dSdan
1543f43d7fceSdan  # The sector-size (according to the VFS) is 1024 bytes. So if the
1544f43d7fceSdan  # page-size requested using "PRAGMA page_size" is greater than the
1545f43d7fceSdan  # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
1546f43d7fceSdan  # page-size remains 1024 bytes.
1547f43d7fceSdan  #
1548f43d7fceSdan  set eff $pagesize
1549f43d7fceSdan  if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
1550f43d7fceSdan
1551f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1552f9b4419dSdan    sqlite3 db2 test.db
1553f9b4419dSdan    execsql "
1554f9b4419dSdan      PRAGMA page_size = $pagesize;
1555f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1556f9b4419dSdan    " db2
1557f9b4419dSdan    file size test.db
1558f43d7fceSdan  } $eff
1559f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1560f9b4419dSdan    sqlite3 db2 test.db
1561f9b4419dSdan    execsql {
1562f9b4419dSdan      SELECT count(*) FROM v;
1563f9b4419dSdan      PRAGMA main.page_size;
1564f9b4419dSdan    } db2
1565f43d7fceSdan  } [list 1 $eff]
1566f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1567f9b4419dSdan    execsql {
1568f9b4419dSdan      SELECT count(*) FROM v;
1569f9b4419dSdan      PRAGMA main.page_size;
1570f9b4419dSdan    }
1571f43d7fceSdan  } [list 1 $eff]
1572f9b4419dSdan  db2 close
1573f9b4419dSdan}
1574f43d7fceSdandb close
1575f43d7fceSdantv delete
1576dca321aeSdan
1577d353331aSdan#-------------------------------------------------------------------------
1578d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1579d353331aSdan#
1580d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1581d353331aSdan#                journal mode: If the journal associated with a transaction
1582d353331aSdan#                is smaller than the journal file (because a previous
1583d353331aSdan#                transaction left a very large non-hot journal file in the
1584d353331aSdan#                file-system), then SQLite has to be careful that there is
1585d353331aSdan#                not a journal-header left over from a previous transaction
1586d353331aSdan#                immediately following the journal content just written.
1587d353331aSdan#                If there is, and the process crashes so that the journal
1588d353331aSdan#                becomes a hot-journal and must be rolled back by another
1589d353331aSdan#                process, there is a danger that the other process may roll
1590d353331aSdan#                back the aborted transaction, then continue copying data
1591d353331aSdan#                from an older transaction from the remainder of the journal.
1592d353331aSdan#                See the syncJournal() function for details.
1593d353331aSdan#
1594d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1595d353331aSdan#                the mix to make the integrity-check more likely to catch
1596d353331aSdan#                errors.
1597d353331aSdan#
1598d353331aSdantestvfs tv -default 1
1599d353331aSdantv script xSyncCb
1600d353331aSdantv filter xSync
1601d353331aSdanproc xSyncCb {method filename args} {
1602d353331aSdan  set t [file tail $filename]
1603d353331aSdan  if {$t == "test.db"} faultsim_save
1604d353331aSdan  return SQLITE_OK
1605d353331aSdan}
1606d353331aSdanfaultsim_delete_and_reopen
1607d353331aSdandb func a_string a_string
1608e91a54e1Sdan
1609d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1610d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1611d353331aSdan# frequent journal headers.
1612d353331aSdan#
1613d353331aSdando_execsql_test pager1-13.1.1 {
1614d353331aSdan  PRAGMA page_size = 1024;
1615d353331aSdan  PRAGMA journal_mode = PERSIST;
1616d353331aSdan  PRAGMA cache_size = 10;
1617d353331aSdan  BEGIN;
1618d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1619d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1620d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1621d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1622d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1623d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1624d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1625d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1626d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1627d353331aSdan  COMMIT;
1628d353331aSdan  UPDATE t1 SET b = a_string(400);
1629d353331aSdan} {persist}
1630d353331aSdan
1631b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1632d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1633d353331aSdan# of these will write just enough content that one of the old headers created
1634d353331aSdan# by the transaction in the block above lies immediately after the content
1635d353331aSdan# journalled by the current transaction.
1636d353331aSdan#
1637d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1638d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1639d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1640d353331aSdan  } {}
1641d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1642d353331aSdan
1643d353331aSdan  # Try to access the snapshot of the file-system.
1644d353331aSdan  #
1645d353331aSdan  sqlite3 db2 sv_test.db
1646d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1647d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1648d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1649d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1650d353331aSdan    execsql { PRAGMA integrity_check } db2
1651d353331aSdan  } {ok}
1652d353331aSdan  db2 close
1653d353331aSdan}
1654b2f20bfcSshaneh}
1655d353331aSdan
1656b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1657d353331aSdan# Same test as above. But this time with an index on the table.
1658d353331aSdan#
1659d353331aSdando_execsql_test pager1-13.2.1 {
1660d353331aSdan  CREATE INDEX i1 ON t1(b);
1661d353331aSdan  UPDATE t1 SET b = a_string(400);
1662d353331aSdan} {}
1663d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1664d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1665d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1666d353331aSdan  } {}
1667d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1668d353331aSdan  sqlite3 db2 sv_test.db
1669d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1670d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1671d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1672d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1673d353331aSdan    execsql { PRAGMA integrity_check } db2
1674d353331aSdan  } {ok}
1675d353331aSdan  db2 close
1676d353331aSdan}
1677b2f20bfcSshaneh}
1678d353331aSdan
1679d353331aSdandb close
1680d353331aSdantv delete
1681d353331aSdan
1682d353331aSdan#-------------------------------------------------------------------------
1683d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1684d353331aSdan#
1685d353331aSdanfaultsim_delete_and_reopen
1686d353331aSdando_execsql_test pager1-14.1.1 {
1687d353331aSdan  PRAGMA journal_mode = OFF;
1688d353331aSdan  CREATE TABLE t1(a, b);
1689d353331aSdan  BEGIN;
1690d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1691d353331aSdan  COMMIT;
1692d353331aSdan  SELECT * FROM t1;
1693d353331aSdan} {off 1 2}
1694d353331aSdando_catchsql_test pager1-14.1.2 {
1695d353331aSdan  BEGIN;
1696d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1697d353331aSdan  ROLLBACK;
1698d353331aSdan} {0 {}}
1699d353331aSdando_execsql_test pager1-14.1.3 {
1700d353331aSdan  SELECT * FROM t1;
1701354bfe03Sdan} {1 2}
1702d353331aSdando_catchsql_test pager1-14.1.4 {
1703d353331aSdan  BEGIN;
1704d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1705d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1706d353331aSdan} {1 {PRIMARY KEY must be unique}}
1707d353331aSdando_execsql_test pager1-14.1.5 {
1708d353331aSdan  COMMIT;
1709d353331aSdan  SELECT * FROM t1;
1710354bfe03Sdan} {1 2 2 2}
1711d353331aSdan
1712c8ce3972Sdan#-------------------------------------------------------------------------
1713c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1714c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1715c8ce3972Sdan#
1716c8ce3972Sdanfaultsim_delete_and_reopen
1717c8ce3972Sdando_execsql_test pager1-15.0 {
1718c8ce3972Sdan  CREATE TABLE tx(y, z);
1719c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1720c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1721c8ce3972Sdan} {}
1722c8ce3972Sdandb close
1723c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1724c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1725c8ce3972Sdan  sqlite3 db test.db
1726c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1727c8ce3972Sdan    SELECT * FROM tx;
1728c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1729c8ce3972Sdan  db close
1730c8ce3972Sdan  tv delete
1731c8ce3972Sdan}
1732c8ce3972Sdan
1733c8ce3972Sdan#-------------------------------------------------------------------------
1734c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1735c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1736c8ce3972Sdan#
1737c8ce3972Sdantestvfs tv -default 1
1738c8ce3972Sdantv script xOpenCb
1739c8ce3972Sdantv filter xOpen
174033f5379cSdanproc xOpenCb {method filename args} {
1741c8ce3972Sdan  set ::file_len [string length $filename]
1742c8ce3972Sdan}
1743c8ce3972Sdansqlite3 db test.db
1744c8ce3972Sdandb close
1745c8ce3972Sdantv delete
1746c8ce3972Sdan
1747c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1748c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1749c8ce3972Sdan
1750c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1751c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1752c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1753c8ce3972Sdan  #
1754c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1755c8ce3972Sdan    set res {0 {}}
1756c8ce3972Sdan  } else {
1757c8ce3972Sdan    set res {1 {unable to open database file}}
1758c8ce3972Sdan  }
1759c8ce3972Sdan
1760c8ce3972Sdan  do_test pager1-16.1.$ii {
1761c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1762c8ce3972Sdan  } $res
1763c8ce3972Sdan
1764c8ce3972Sdan  catch {db close}
1765c8ce3972Sdan  tv delete
1766c8ce3972Sdan}
1767c8ce3972Sdan
1768c8ce3972Sdan
1769c8ce3972Sdan#-------------------------------------------------------------------------
1770c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1771c8ce3972Sdan# numbers:
1772c8ce3972Sdan#
1773c8ce3972Sdan#   + The locking page,
1774c8ce3972Sdan#   + Page 0,
1775c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1776c8ce3972Sdan#
1777f4ba1093Sdan# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
1778f4ba1093Sdan# that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
1779f4ba1093Sdan#
1780f4ba1093Sdanifcapable !direct_read {
1781c8ce3972Sdando_test pager1-18.1 {
1782c8ce3972Sdan  faultsim_delete_and_reopen
1783c8ce3972Sdan  db func a_string a_string
1784c8ce3972Sdan  execsql {
1785c8ce3972Sdan    PRAGMA page_size = 1024;
1786c8ce3972Sdan    CREATE TABLE t1(a, b);
1787c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1788c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1789c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1790c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1791c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1792c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1793c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1794c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1795c8ce3972Sdan  }
1796c8ce3972Sdan} {}
1797c8ce3972Sdando_test pager1-18.2 {
1798c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1799c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1800c8ce3972Sdan  execsql {
1801c8ce3972Sdan    PRAGMA writable_schema = 1;
1802c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1803c8ce3972Sdan  }
1804c8ce3972Sdan  sqlite3 db2 test.db
1805c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1806c8ce3972Sdan} {1 {database disk image is malformed}}
1807c8ce3972Sdandb2 close
1808a748fdccSdrhdo_test pager1-18.3.1 {
1809c8ce3972Sdan  execsql {
1810c8ce3972Sdan    CREATE TABLE t2(x);
1811c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1812c8ce3972Sdan  }
1813c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1814c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1815c8ce3972Sdan  sqlite3 db2 test.db
1816a748fdccSdrh  # even though x is malformed, because typeof() does
1817a748fdccSdrh  # not load the content of x, the error is not noticed.
1818a748fdccSdrh  catchsql { SELECT typeof(x) FROM t2 } db2
1819a748fdccSdrh} {0 text}
1820a748fdccSdrhdo_test pager1-18.3.2 {
1821a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1822a748fdccSdrh  # detected
1823a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1824a748fdccSdrh} {1 {database disk image is malformed}}
1825a748fdccSdrhdb2 close
1826a748fdccSdrhdo_test pager1-18.3.3 {
1827a748fdccSdrh  execsql {
1828a748fdccSdrh    DELETE FROM t2;
1829a748fdccSdrh    INSERT INTO t2 VALUES(randomblob(5000));
1830a748fdccSdrh  }
1831a748fdccSdrh  set pgno [expr ([file size test.db] / 1024)-2]
1832a748fdccSdrh  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1833a748fdccSdrh  sqlite3 db2 test.db
1834a748fdccSdrh  # even though x is malformed, because length() and typeof() do
1835a748fdccSdrh  # not load the content of x, the error is not noticed.
1836a748fdccSdrh  catchsql { SELECT length(x), typeof(x) FROM t2 } db2
1837a748fdccSdrh} {0 {5000 blob}}
1838a748fdccSdrhdo_test pager1-18.3.4 {
1839a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1840a748fdccSdrh  # detected
1841a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1842c8ce3972Sdan} {1 {database disk image is malformed}}
1843c8ce3972Sdandb2 close
1844c8ce3972Sdando_test pager1-18.4 {
1845c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1846c8ce3972Sdan  sqlite3 db2 test.db
1847a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1848c8ce3972Sdan} {1 {database disk image is malformed}}
1849c8ce3972Sdandb2 close
1850c8ce3972Sdando_test pager1-18.5 {
1851c8ce3972Sdan  sqlite3 db ""
1852c8ce3972Sdan  execsql {
1853c8ce3972Sdan    CREATE TABLE t1(a, b);
1854c8ce3972Sdan    CREATE TABLE t2(a, b);
1855c8ce3972Sdan    PRAGMA writable_schema = 1;
1856c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1857c8ce3972Sdan    PRAGMA writable_schema = 0;
1858c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1859c8ce3972Sdan  }
1860c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1861ba3cbf3dSdan} {1 {database disk image is malformed}}
1862c8ce3972Sdandb close
1863c8ce3972Sdan
1864ba3cbf3dSdando_test pager1-18.6 {
1865ba3cbf3dSdan  faultsim_delete_and_reopen
1866ba3cbf3dSdan  db func a_string a_string
1867ba3cbf3dSdan  execsql {
1868ba3cbf3dSdan    PRAGMA page_size = 1024;
1869ba3cbf3dSdan    CREATE TABLE t1(x);
1870ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1871ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1872ba3cbf3dSdan  }
1873ba3cbf3dSdan
1874ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1875ba3cbf3dSdan  db close
1876ba3cbf3dSdan
1877ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1878ba3cbf3dSdan  sqlite3 db test.db
1879ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1880ba3cbf3dSdan} {1 {database disk image is malformed}}
1881f4ba1093Sdan}
1882ba3cbf3dSdan
1883ba3cbf3dSdando_test pager1-19.1 {
1884ba3cbf3dSdan  sqlite3 db ""
1885ba3cbf3dSdan  db func a_string a_string
1886ba3cbf3dSdan  execsql {
1887ba3cbf3dSdan    PRAGMA page_size = 512;
1888ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1889ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1890ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1891ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1892ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1893ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1894ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1895ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1896ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1897ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1898ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1899ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1900ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1901ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1902ba3cbf3dSdan    );
1903ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1904ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1905ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1906ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1907ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1908ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1909ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1910ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1911ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1912ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1913ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1914ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1915ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1916ba3cbf3dSdan    );
1917ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
1918ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
1919ba3cbf3dSdan    VACUUM;
1920ba3cbf3dSdan  }
1921ba3cbf3dSdan} {}
1922ba3cbf3dSdan
19236b63ab47Sdan#-------------------------------------------------------------------------
19246b63ab47Sdan# Test a couple of special cases that come up while committing
19256b63ab47Sdan# transactions:
19266b63ab47Sdan#
19276b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
19286b63ab47Sdan#                  database has not been modified at all.
19296b63ab47Sdan#
19306b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
19316b63ab47Sdan#
19326b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
19336b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
19346b63ab47Sdan#                  disk before the commit.
19356b63ab47Sdan#
19366b63ab47Sdando_test pager1-20.1.1 {
19376b63ab47Sdan  catch {db close}
19386b63ab47Sdan  sqlite3 db :memory:
19396b63ab47Sdan  execsql {
19406b63ab47Sdan    CREATE TABLE one(two, three);
19416b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19426b63ab47Sdan  }
19436b63ab47Sdan} {}
19446b63ab47Sdando_test pager1-20.1.2 {
19456b63ab47Sdan  execsql {
19466b63ab47Sdan    BEGIN EXCLUSIVE;
19476b63ab47Sdan    COMMIT;
19486b63ab47Sdan  }
19496b63ab47Sdan} {}
19506b63ab47Sdan
19516b63ab47Sdando_test pager1-20.2.1 {
19526b63ab47Sdan  faultsim_delete_and_reopen
19536b63ab47Sdan  execsql {
19546b63ab47Sdan    PRAGMA locking_mode = exclusive;
19556b63ab47Sdan    PRAGMA journal_mode = persist;
19566b63ab47Sdan    CREATE TABLE one(two, three);
19576b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19586b63ab47Sdan  }
19596b63ab47Sdan} {exclusive persist}
19606b63ab47Sdando_test pager1-20.2.2 {
19616b63ab47Sdan  execsql {
19626b63ab47Sdan    BEGIN EXCLUSIVE;
19636b63ab47Sdan    COMMIT;
19646b63ab47Sdan  }
19656b63ab47Sdan} {}
19666b63ab47Sdan
19679091f775Sshanehifcapable wal {
19686b63ab47Sdan  do_test pager1-20.3.1 {
19696b63ab47Sdan    faultsim_delete_and_reopen
19706b63ab47Sdan    db func a_string a_string
19716b63ab47Sdan    execsql {
19726b63ab47Sdan      PRAGMA cache_size = 10;
19736b63ab47Sdan      PRAGMA journal_mode = wal;
19746b63ab47Sdan      BEGIN;
19756b63ab47Sdan        CREATE TABLE t1(x);
19766b63ab47Sdan        CREATE TABLE t2(y);
19776b63ab47Sdan        INSERT INTO t1 VALUES(a_string(800));
19786b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
19796b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
19806b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
19816b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
19826b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
19836b63ab47Sdan      COMMIT;
19846b63ab47Sdan    }
19856b63ab47Sdan  } {wal}
19866b63ab47Sdan  do_test pager1-20.3.2 {
19876b63ab47Sdan    execsql {
19886b63ab47Sdan      BEGIN;
19896b63ab47Sdan      INSERT INTO t2 VALUES('xxxx');
19906b63ab47Sdan    }
1991c396d4afSdan    recursive_select 32 t1
19926b63ab47Sdan    execsql COMMIT
19936b63ab47Sdan  } {}
19949091f775Sshaneh}
19956b63ab47Sdan
199689ccf448Sdan#-------------------------------------------------------------------------
199789ccf448Sdan# Test that a WAL database may not be opened if:
199889ccf448Sdan#
199989ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
200089ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
200189ccf448Sdan#
20029091f775Sshanehifcapable wal {
200389ccf448Sdan  do_test pager1-21.0 {
200489ccf448Sdan    faultsim_delete_and_reopen
200589ccf448Sdan    execsql {
200689ccf448Sdan      PRAGMA journal_mode = WAL;
200789ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
200889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
200989ccf448Sdan    }
201089ccf448Sdan  } {wal}
201189ccf448Sdan  do_test pager1-21.1 {
201289ccf448Sdan    testvfs tv -noshm 1
201389ccf448Sdan    sqlite3 db2 test.db -vfs tv
201489ccf448Sdan    catchsql { SELECT * FROM ko } db2
201589ccf448Sdan  } {1 {unable to open database file}}
201689ccf448Sdan  db2 close
201789ccf448Sdan  tv delete
201889ccf448Sdan  do_test pager1-21.2 {
201989ccf448Sdan    testvfs tv -iversion 1
202089ccf448Sdan    sqlite3 db2 test.db -vfs tv
202189ccf448Sdan    catchsql { SELECT * FROM ko } db2
202289ccf448Sdan  } {1 {unable to open database file}}
202389ccf448Sdan  db2 close
202489ccf448Sdan  tv delete
20259091f775Sshaneh}
202689ccf448Sdan
202789ccf448Sdan#-------------------------------------------------------------------------
202889ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
202989ccf448Sdan#
203089ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
203189ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
203289ccf448Sdan#
20335209132aSdanifcapable wal {
203489ccf448Sdan  do_test pager1-22.1.1 {
203589ccf448Sdan    faultsim_delete_and_reopen
203689ccf448Sdan    execsql {
203789ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
203889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
203989ccf448Sdan    }
204089ccf448Sdan    execsql { PRAGMA wal_checkpoint }
2041bdd9af0fSdan  } {0 -1 -1}
204289ccf448Sdan  do_test pager1-22.2.1 {
204389ccf448Sdan    testvfs tv -default 1
204489ccf448Sdan    tv filter xSync
204589ccf448Sdan    tv script xSyncCb
204689ccf448Sdan    proc xSyncCb {args} {incr ::synccount}
204789ccf448Sdan    set ::synccount 0
204889ccf448Sdan    sqlite3 db test.db
204989ccf448Sdan    execsql {
205089ccf448Sdan      PRAGMA synchronous = off;
205189ccf448Sdan      PRAGMA journal_mode = WAL;
205289ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
205389ccf448Sdan    }
205489ccf448Sdan    execsql { PRAGMA wal_checkpoint }
205589ccf448Sdan    set synccount
205689ccf448Sdan  } {0}
205789ccf448Sdan  db close
205889ccf448Sdan  tv delete
20595209132aSdan}
206089ccf448Sdan
206189ccf448Sdan#-------------------------------------------------------------------------
206289ccf448Sdan# Tests for changing journal mode.
206389ccf448Sdan#
206489ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
206589ccf448Sdan#                  the journal file is deleted.
206689ccf448Sdan#
206789ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
206889ccf448Sdan#                  on the database file.
206989ccf448Sdan#
207089ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
207189ccf448Sdan#                  on the database file.
207289ccf448Sdan#
207389ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
207489ccf448Sdan#
207589ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
207689ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
207789ccf448Sdan#
2078d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
2079d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
2080d0b0d4dcSdan#                  locking_mode=exclusive).
2081d0b0d4dcSdan#
208289ccf448Sdando_test pager1-23.1.1 {
208389ccf448Sdan  faultsim_delete_and_reopen
208489ccf448Sdan  execsql {
208589ccf448Sdan    PRAGMA journal_mode = PERSIST;
208689ccf448Sdan    CREATE TABLE t1(a, b);
208789ccf448Sdan  }
208889ccf448Sdan  file exists test.db-journal
208989ccf448Sdan} {1}
209089ccf448Sdando_test pager1-23.1.2 {
209189ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
209289ccf448Sdan  file exists test.db-journal
209389ccf448Sdan} {0}
209489ccf448Sdan
209589ccf448Sdando_test pager1-23.2.1 {
209689ccf448Sdan  execsql {
209789ccf448Sdan    PRAGMA journal_mode = PERSIST;
209889ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
209989ccf448Sdan  }
210089ccf448Sdan  db eval { SELECT * FROM t1 } {
210189ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
210289ccf448Sdan  }
210389ccf448Sdan  execsql { PRAGMA journal_mode }
210489ccf448Sdan} {delete}
210589ccf448Sdando_test pager1-23.2.2 {
210689ccf448Sdan  file exists test.db-journal
210789ccf448Sdan} {0}
210889ccf448Sdan
210989ccf448Sdando_test pager1-23.3.1 {
211089ccf448Sdan  execsql {
211189ccf448Sdan    PRAGMA journal_mode = PERSIST;
211289ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
211389ccf448Sdan    BEGIN IMMEDIATE;
211489ccf448Sdan  }
211589ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
211689ccf448Sdan  execsql { PRAGMA journal_mode }
211789ccf448Sdan} {delete}
211889ccf448Sdando_test pager1-23.3.2 {
211989ccf448Sdan  file exists test.db-journal
212089ccf448Sdan} {0}
212189ccf448Sdando_test pager1-23.3.3 {
212289ccf448Sdan  execsql COMMIT
212389ccf448Sdan} {}
212489ccf448Sdan
212589ccf448Sdando_test pager1-23.4.1 {
212689ccf448Sdan  execsql {
212789ccf448Sdan    PRAGMA journal_mode = PERSIST;
212889ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
212989ccf448Sdan    BEGIN EXCLUSIVE;
213089ccf448Sdan  }
213189ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
213289ccf448Sdan  execsql { PRAGMA journal_mode }
213389ccf448Sdan} {delete}
213489ccf448Sdando_test pager1-23.4.2 {
213589ccf448Sdan  file exists test.db-journal
213689ccf448Sdan} {0}
213789ccf448Sdando_test pager1-23.4.3 {
213889ccf448Sdan  execsql COMMIT
213989ccf448Sdan} {}
214089ccf448Sdan
214189ccf448Sdando_test pager1-23.5.1 {
214289ccf448Sdan  faultsim_delete_and_reopen
214389ccf448Sdan  sqlite3 db :memory:
214489ccf448Sdan} {}
214589ccf448Sdanforeach {tn mode possible} {
214689ccf448Sdan  2  off      1
214789ccf448Sdan  3  memory   1
214889ccf448Sdan  4  persist  0
214989ccf448Sdan  5  delete   0
215089ccf448Sdan  6  wal      0
215189ccf448Sdan  7  truncate 0
215289ccf448Sdan} {
215389ccf448Sdan  do_test pager1-23.5.$tn.1 {
215489ccf448Sdan    execsql "PRAGMA journal_mode = off"
215589ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
215689ccf448Sdan  } [if $possible {list $mode} {list off}]
215789ccf448Sdan  do_test pager1-23.5.$tn.2 {
215889ccf448Sdan    execsql "PRAGMA journal_mode = memory"
215989ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
216089ccf448Sdan  } [if $possible {list $mode} {list memory}]
216189ccf448Sdan}
2162d0b0d4dcSdando_test pager1-23.6.1 {
216389ccf448Sdan  execsql {PRAGMA locking_mode = normal}
216489ccf448Sdan} {exclusive}
2165d0b0d4dcSdando_test pager1-23.6.2 {
216689ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
216789ccf448Sdan} {exclusive}
2168d0b0d4dcSdando_test pager1-23.6.3 {
216989ccf448Sdan  execsql {PRAGMA locking_mode}
217089ccf448Sdan} {exclusive}
2171d0b0d4dcSdando_test pager1-23.6.4 {
217289ccf448Sdan  execsql {PRAGMA main.locking_mode}
217389ccf448Sdan} {exclusive}
21746b63ab47Sdan
2175d0b0d4dcSdan#-------------------------------------------------------------------------
2176d0b0d4dcSdan#
2177d0b0d4dcSdando_test pager1-24.1.1 {
2178d0b0d4dcSdan  faultsim_delete_and_reopen
2179d0b0d4dcSdan  db func a_string a_string
2180d0b0d4dcSdan  execsql {
2181d0b0d4dcSdan    PRAGMA cache_size = 10;
2182d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2183d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2184d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2185d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2186d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2187d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2188d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2189d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2190d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2191d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2192d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2193d0b0d4dcSdan  }
2194d0b0d4dcSdan} {}
2195d0b0d4dcSdando_test pager1-24.1.2 {
2196d0b0d4dcSdan  execsql {
2197d0b0d4dcSdan    BEGIN;
2198d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2199d0b0d4dcSdan  }
2200c396d4afSdan  recursive_select 64 x2
2201d0b0d4dcSdan} {}
2202d0b0d4dcSdando_test pager1-24.1.3 {
2203d0b0d4dcSdan  execsql {
2204d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2205d0b0d4dcSdan    COMMIT;
2206d0b0d4dcSdan    PRAGMA integrity_check;
2207d0b0d4dcSdan    SELECT count(*) FROM x1;
2208d0b0d4dcSdan  }
2209d0b0d4dcSdan} {ok 33}
2210d0b0d4dcSdan
2211d0b0d4dcSdando_test pager1-24.1.4 {
2212d0b0d4dcSdan  execsql {
2213d0b0d4dcSdan    DELETE FROM x1;
2214d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2215d0b0d4dcSdan    BEGIN;
2216d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2217d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2218d0b0d4dcSdan  }
2219c396d4afSdan  recursive_select 64 x2 {db eval COMMIT}
2220d0b0d4dcSdan  execsql {
2221d0b0d4dcSdan    PRAGMA integrity_check;
2222d0b0d4dcSdan    SELECT count(*) FROM x1;
2223d0b0d4dcSdan  }
2224d0b0d4dcSdan} {ok 33}
2225d0b0d4dcSdan
2226d0b0d4dcSdando_test pager1-24.1.5 {
2227d0b0d4dcSdan  execsql {
2228d0b0d4dcSdan    DELETE FROM x1;
2229d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2230d0b0d4dcSdan  }
2231c396d4afSdan  recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
2232d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2233d0b0d4dcSdan} {}
2234d0b0d4dcSdan
2235d0b0d4dcSdan#-------------------------------------------------------------------------
2236d0b0d4dcSdan#
2237d0b0d4dcSdando_test pager1-25-1 {
2238d0b0d4dcSdan  faultsim_delete_and_reopen
2239d0b0d4dcSdan  execsql {
2240d0b0d4dcSdan    BEGIN;
2241d0b0d4dcSdan      SAVEPOINT abc;
2242d0b0d4dcSdan        CREATE TABLE t1(a, b);
2243d0b0d4dcSdan      ROLLBACK TO abc;
2244d0b0d4dcSdan    COMMIT;
2245d0b0d4dcSdan  }
2246d0b0d4dcSdan  db close
2247d0b0d4dcSdan} {}
2248d0b0d4dcSdando_test pager1-25-2 {
2249d0b0d4dcSdan  faultsim_delete_and_reopen
2250d0b0d4dcSdan  execsql {
2251d0b0d4dcSdan    SAVEPOINT abc;
2252d0b0d4dcSdan      CREATE TABLE t1(a, b);
2253d0b0d4dcSdan    ROLLBACK TO abc;
2254d0b0d4dcSdan    COMMIT;
2255d0b0d4dcSdan  }
2256d0b0d4dcSdan  db close
2257d0b0d4dcSdan} {}
22586b63ab47Sdan
2259c396d4afSdan#-------------------------------------------------------------------------
2260c396d4afSdan# Sector-size tests.
2261c396d4afSdan#
2262c396d4afSdando_test pager1-26.1 {
2263c396d4afSdan  testvfs tv -default 1
2264c396d4afSdan  tv sectorsize 4096
2265c396d4afSdan  faultsim_delete_and_reopen
2266c396d4afSdan  db func a_string a_string
2267c396d4afSdan  execsql {
2268c396d4afSdan    PRAGMA page_size = 512;
2269c396d4afSdan    CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
2270c396d4afSdan    BEGIN;
2271c396d4afSdan      INSERT INTO tbl VALUES(a_string(25), a_string(600));
2272c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2273c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2274c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2275c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2276c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2277c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2278c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2279c396d4afSdan    COMMIT;
2280c396d4afSdan  }
2281c396d4afSdan} {}
2282c396d4afSdando_execsql_test pager1-26.1 {
2283c396d4afSdan  UPDATE tbl SET b = a_string(550);
2284c396d4afSdan} {}
2285c396d4afSdandb close
2286c396d4afSdantv delete
2287c396d4afSdan
2288c396d4afSdan#-------------------------------------------------------------------------
228922b328b2Sdan#
2290c396d4afSdando_test pager1.27.1 {
2291c396d4afSdan  faultsim_delete_and_reopen
2292c396d4afSdan  sqlite3_pager_refcounts db
2293c396d4afSdan  execsql {
2294c396d4afSdan    BEGIN;
2295c396d4afSdan      CREATE TABLE t1(a, b);
2296c396d4afSdan  }
2297c396d4afSdan  sqlite3_pager_refcounts db
2298c396d4afSdan  execsql COMMIT
2299c396d4afSdan} {}
2300c396d4afSdan
230122b328b2Sdan#-------------------------------------------------------------------------
230222b328b2Sdan# Test that attempting to open a write-transaction with
230322b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on
230422b328b2Sdan# the same database.
230522b328b2Sdan#
230622b328b2Sdancatch { db close }
23079091f775Sshanehifcapable wal {
230822b328b2Sdan  do_multiclient_test tn {
230922b328b2Sdan    do_test pager1-28.$tn.1 {
231022b328b2Sdan      sql1 {
231122b328b2Sdan        PRAGMA journal_mode = WAL;
231222b328b2Sdan        CREATE TABLE t1(a, b);
231322b328b2Sdan        INSERT INTO t1 VALUES('a', 'b');
231422b328b2Sdan      }
231522b328b2Sdan    } {wal}
231622b328b2Sdan    do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
231722b328b2Sdan
231822b328b2Sdan    do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
231922b328b2Sdan    do_test pager1-28.$tn.4 {
232022b328b2Sdan      csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
232122b328b2Sdan    } {1 {database is locked}}
232222b328b2Sdan    code2 { db2 close ; sqlite3 db2 test.db }
232322b328b2Sdan    do_test pager1-28.$tn.4 {
232422b328b2Sdan      sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
232522b328b2Sdan    } {}
232622b328b2Sdan  }
23279091f775Sshaneh}
23285653e4daSdan
23295653e4daSdan#-------------------------------------------------------------------------
23305653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager
23315653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a
23325653e4daSdan# RESERVED lock on the database file, this step is skipped.
23335653e4daSdan#
23345653e4daSdando_multiclient_test tn {
23355653e4daSdan  do_test pager1-28.$tn.1 {
23365653e4daSdan    sql1 {
23375653e4daSdan      PRAGMA journal_mode = PERSIST;
23385653e4daSdan      CREATE TABLE t1(a, b);
23395653e4daSdan      INSERT INTO t1 VALUES('a', 'b');
23405653e4daSdan    }
23415653e4daSdan  } {persist}
23425653e4daSdan  do_test pager1-28.$tn.2 { file exists test.db-journal } 1
23435653e4daSdan  do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
23445653e4daSdan  do_test pager1-28.$tn.4 { file exists test.db-journal } 0
23455653e4daSdan
23465653e4daSdan  do_test pager1-28.$tn.5 {
23475653e4daSdan    sql1 {
23485653e4daSdan      PRAGMA journal_mode = PERSIST;
23495653e4daSdan      INSERT INTO t1 VALUES('c', 'd');
23505653e4daSdan    }
23515653e4daSdan  } {persist}
23525653e4daSdan  do_test pager1-28.$tn.6 { file exists test.db-journal } 1
23535653e4daSdan  do_test pager1-28.$tn.7 {
23545653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
23555653e4daSdan  } {}
23565653e4daSdan  do_test pager1-28.$tn.8  { file exists test.db-journal } 1
23575653e4daSdan  do_test pager1-28.$tn.9  { sql1 { PRAGMA journal_mode = DELETE } } delete
23585653e4daSdan  do_test pager1-28.$tn.10 { file exists test.db-journal } 1
23595653e4daSdan
23605653e4daSdan  do_test pager1-28.$tn.11 { sql2 COMMIT } {}
23615653e4daSdan  do_test pager1-28.$tn.12 { file exists test.db-journal } 0
23625653e4daSdan
23635653e4daSdan  do_test pager1-28-$tn.13 {
23645653e4daSdan    code1 { set channel [db incrblob -readonly t1 a 2] }
23655653e4daSdan    sql1 {
23665653e4daSdan      PRAGMA journal_mode = PERSIST;
23675653e4daSdan      INSERT INTO t1 VALUES('g', 'h');
23685653e4daSdan    }
23695653e4daSdan  } {persist}
23705653e4daSdan  do_test pager1-28.$tn.14 { file exists test.db-journal } 1
23715653e4daSdan  do_test pager1-28.$tn.15 {
23725653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
23735653e4daSdan  } {}
23745653e4daSdan  do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
23755653e4daSdan  do_test pager1-28.$tn.17 { file exists test.db-journal } 1
23765653e4daSdan
23775653e4daSdan  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
23785653e4daSdan  do_test pager1-28-$tn.18 { code1 { read $channel } } c
23795653e4daSdan  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
23805653e4daSdan  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
23815653e4daSdan}
23825653e4daSdan
23831879b088Sdando_test pager1-29.1 {
23841879b088Sdan  faultsim_delete_and_reopen
23851879b088Sdan  execsql {
23861879b088Sdan    PRAGMA page_size = 1024;
23871879b088Sdan    PRAGMA auto_vacuum = full;
23881879b088Sdan    PRAGMA locking_mode=exclusive;
23891879b088Sdan    CREATE TABLE t1(a, b);
23901879b088Sdan    INSERT INTO t1 VALUES(1, 2);
23911879b088Sdan  }
23921879b088Sdan  file size test.db
23931879b088Sdan} [expr 1024*3]
23941879b088Sdando_test pager1-29.2 {
23951879b088Sdan  execsql {
23961879b088Sdan    PRAGMA page_size = 4096;
23971879b088Sdan    VACUUM;
23981879b088Sdan  }
23991879b088Sdan  file size test.db
24001879b088Sdan} [expr 4096*3]
24011879b088Sdan
2402e08c2066Sdan#-------------------------------------------------------------------------
2403e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in
2404e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system
2405e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while
2406e08c2066Sdan# doing this is not released.
2407e08c2066Sdan#
2408e08c2066Sdando_test pager1-30.1 {
2409e08c2066Sdan  db close
2410fda06befSmistachkin  delete_file test.db
2411fda06befSmistachkin  delete_file test.db-journal
2412e08c2066Sdan  set fd [open test.db-journal w]
2413e08c2066Sdan  seek $fd [expr 512+1032*2]
2414e08c2066Sdan  puts -nonewline $fd x
2415e08c2066Sdan  close $fd
2416e08c2066Sdan
2417e08c2066Sdan  sqlite3 db test.db
2418e08c2066Sdan  execsql {
2419e08c2066Sdan    PRAGMA locking_mode=EXCLUSIVE;
2420e08c2066Sdan    SELECT count(*) FROM sqlite_master;
2421e08c2066Sdan    PRAGMA lock_status;
2422e08c2066Sdan  }
2423e08c2066Sdan} {exclusive 0 main reserved temp closed}
2424e08c2066Sdan
2425e08c2066Sdan#-------------------------------------------------------------------------
2426e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal
2427e08c2066Sdan# file can still be rolled back. This is required for backward compatibility -
2428e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero.
2429e08c2066Sdan#
243033f5379cSdanif {$tcl_platform(platform)=="unix"} {
2431e08c2066Sdando_test pager1-31.1 {
2432e08c2066Sdan  faultsim_delete_and_reopen
2433e08c2066Sdan  execsql {
2434e08c2066Sdan    PRAGMA cache_size = 10;
2435e08c2066Sdan    PRAGMA page_size = 1024;
2436e08c2066Sdan    CREATE TABLE t1(x, y, UNIQUE(x, y));
2437e08c2066Sdan    INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
2438e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2439e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2440e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2441e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2442e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2443e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2444e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2445e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2446e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2447e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2448e08c2066Sdan    BEGIN;
2449e08c2066Sdan      UPDATE t1 SET y = randomblob(1499);
2450e08c2066Sdan  }
2451fda06befSmistachkin  copy_file test.db test.db2
2452fda06befSmistachkin  copy_file test.db-journal test.db2-journal
2453e08c2066Sdan
2454e08c2066Sdan  hexio_write test.db2-journal 24 00000000
2455e08c2066Sdan  sqlite3 db2 test.db2
2456e08c2066Sdan  execsql { PRAGMA integrity_check } db2
2457e08c2066Sdan} {ok}
245833f5379cSdan}
2459e08c2066Sdan
246031e80976Sdrh#-------------------------------------------------------------------------
246131e80976Sdrh# Test that a database file can be "pre-hinted" to a certain size and that
246231e80976Sdrh# subsequent spilling of the pager cache does not result in the database
246331e80976Sdrh# file being shrunk.
246431e80976Sdrh#
246531e80976Sdrhcatch {db close}
246631e80976Sdrhforcedelete test.db
246731e80976Sdrh
246831e80976Sdrhdo_test pager1-32.1 {
246931e80976Sdrh  sqlite3 db test.db
247031e80976Sdrh  execsql {
247131e80976Sdrh    CREATE TABLE t1(x, y);
247231e80976Sdrh  }
247331e80976Sdrh  db close
247431e80976Sdrh  sqlite3 db test.db
247531e80976Sdrh  execsql {
247631e80976Sdrh    BEGIN;
247731e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
247831e80976Sdrh  }
24792f7820d8Sdrh  file_control_chunksize_test db main 1024
248031e80976Sdrh  file_control_sizehint_test db main 20971520; # 20MB
248131e80976Sdrh  execsql {
248231e80976Sdrh    PRAGMA cache_size = 10;
248331e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
248431e80976Sdrh    INSERT INTO t1 VALUES(2, randomblob(10000));
248531e80976Sdrh    INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
248631e80976Sdrh    INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
248731e80976Sdrh    INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
248831e80976Sdrh    INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
248931e80976Sdrh    SELECT count(*) FROM t1;
249031e80976Sdrh    COMMIT;
249131e80976Sdrh  }
249231e80976Sdrh  db close
249331e80976Sdrh  file size test.db
249431e80976Sdrh} {20971520}
249531e80976Sdrh
249631e80976Sdrh# Cleanup 20MB file left by the previous test.
249731e80976Sdrhforcedelete test.db
24985653e4daSdan
24999fc5b4a5Sdan#-------------------------------------------------------------------------
25009fc5b4a5Sdan# Test that if a transaction is committed in journal_mode=DELETE mode,
25019fc5b4a5Sdan# and the call to unlink() returns an ENOENT error, the COMMIT does not
25029fc5b4a5Sdan# succeed.
25039fc5b4a5Sdan#
25049fc5b4a5Sdanif {$::tcl_platform(platform)=="unix"} {
25059fc5b4a5Sdan  do_test pager1-33.1 {
25069fc5b4a5Sdan    sqlite3 db test.db
25079fc5b4a5Sdan    execsql {
25089fc5b4a5Sdan      CREATE TABLE t1(x);
25099fc5b4a5Sdan      INSERT INTO t1 VALUES('one');
25109fc5b4a5Sdan      INSERT INTO t1 VALUES('two');
25119fc5b4a5Sdan      BEGIN;
25129fc5b4a5Sdan        INSERT INTO t1 VALUES('three');
25139fc5b4a5Sdan        INSERT INTO t1 VALUES('four');
25149fc5b4a5Sdan    }
25159fc5b4a5Sdan    forcedelete bak-journal
25169fc5b4a5Sdan    file rename test.db-journal bak-journal
25179fc5b4a5Sdan
25189fc5b4a5Sdan    catchsql COMMIT
25199fc5b4a5Sdan  } {1 {disk I/O error}}
25209fc5b4a5Sdan
25219fc5b4a5Sdan  do_test pager1-33.2 {
25229fc5b4a5Sdan    file rename bak-journal test.db-journal
25239fc5b4a5Sdan    execsql { SELECT * FROM t1 }
25249fc5b4a5Sdan  } {one two}
25259fc5b4a5Sdan}
25269fc5b4a5Sdan
2527d7a558a9Sdan#-------------------------------------------------------------------------
2528d7a558a9Sdan# Test that appending pages to the database file then moving those pages
2529d7a558a9Sdan# to the free-list before the transaction is committed does not cause
2530d7a558a9Sdan# an error.
2531d7a558a9Sdan#
2532d7a558a9Sdanforeach {tn pragma strsize} {
2533d7a558a9Sdan  1 { PRAGMA mmap_limit = 0 } 2400
2534d7a558a9Sdan  2 { }                       2400
2535d7a558a9Sdan  3 { PRAGMA mmap_limit = 0 } 4400
2536d7a558a9Sdan  4 { }                       4400
2537d7a558a9Sdan} {
2538d7a558a9Sdan  reset_db
2539d7a558a9Sdan  db func a_string a_string
2540d7a558a9Sdan  db eval $pragma
2541d7a558a9Sdan  do_execsql_test 34.$tn.1 {
2542d7a558a9Sdan    CREATE TABLE t1(a, b);
2543d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2544d7a558a9Sdan  }
2545d7a558a9Sdan  do_execsql_test 34.$tn.2 {
2546d7a558a9Sdan    BEGIN;
2547d7a558a9Sdan    INSERT INTO t1 VALUES(2, a_string($strsize));
2548d7a558a9Sdan    DELETE FROM t1 WHERE oid=2;
2549d7a558a9Sdan    COMMIT;
2550d7a558a9Sdan    PRAGMA integrity_check;
2551d7a558a9Sdan  } {ok}
2552d7a558a9Sdan}
2553d7a558a9Sdan
2554d7a558a9Sdan#-------------------------------------------------------------------------
2555d7a558a9Sdan#
2556d7a558a9Sdanreset_db
2557d7a558a9Sdando_test 35 {
2558d7a558a9Sdan  sqlite3 db test.db
2559d7a558a9Sdan
2560d7a558a9Sdan  execsql {
2561d7a558a9Sdan    CREATE TABLE t1(x, y);
2562d7a558a9Sdan    PRAGMA journal_mode = WAL;
2563d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2564d7a558a9Sdan  }
2565d7a558a9Sdan
2566d7a558a9Sdan  execsql {
2567d7a558a9Sdan    BEGIN;
2568d7a558a9Sdan      CREATE TABLE t2(a, b);
2569d7a558a9Sdan  }
2570d7a558a9Sdan
2571d7a558a9Sdan  hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192]
2572d7a558a9Sdan  catchsql ROLLBACK
2573d7a558a9Sdan} {0 {}}
2574d7a558a9Sdan
2575d7a558a9Sdando_multiclient_test tn {
2576d7a558a9Sdan  sql1 {
2577d7a558a9Sdan    PRAGMA auto_vacuum = 0;
2578d7a558a9Sdan    CREATE TABLE t1(x, y);
2579d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2580d7a558a9Sdan  }
2581d7a558a9Sdan
2582d7a558a9Sdan  do_test 36.$tn.1 {
2583d7a558a9Sdan    sql2 { PRAGMA max_page_count = 2 }
2584d7a558a9Sdan    list [catch { sql2 { CREATE TABLE t2(x) } } msg] $msg
2585d7a558a9Sdan  } {1 {database or disk is full}}
2586d7a558a9Sdan
2587d7a558a9Sdan  sql1 { PRAGMA checkpoint_fullfsync = 1 }
2588d7a558a9Sdan  sql1 { CREATE TABLE t2(x) }
2589d7a558a9Sdan
2590d7a558a9Sdan  do_test 36.$tn.2 {
2591d7a558a9Sdan    sql2 { INSERT INTO t2 VALUES('xyz') }
2592d7a558a9Sdan    list [catch { sql2 { CREATE TABLE t3(x) } } msg] $msg
2593d7a558a9Sdan  } {1 {database or disk is full}}
2594d7a558a9Sdan}
2595d7a558a9Sdan
2596d7a558a9Sdanforcedelete test1 test2
2597d7a558a9Sdanforeach {tn uri} {
2598d7a558a9Sdan  1   {file:?mode=memory&cache=shared}
2599d7a558a9Sdan  2   {file:one?mode=memory&cache=shared}
2600d7a558a9Sdan  3   {file:test1?cache=shared}
2601d7a558a9Sdan  4   {file:test2?another=parameter&yet=anotherone}
2602d7a558a9Sdan} {
2603d7a558a9Sdan  do_test 37.$tn {
2604d7a558a9Sdan    catch { db close }
2605d7a558a9Sdan    sqlite3_shutdown
2606d7a558a9Sdan    sqlite3_config_uri 1
2607d7a558a9Sdan    sqlite3 db $uri
2608*abd6d84aSdan
2609d7a558a9Sdan    db eval {
2610d7a558a9Sdan      CREATE TABLE t1(x);
2611d7a558a9Sdan      INSERT INTO t1 VALUES(1);
2612d7a558a9Sdan      SELECT * FROM t1;
2613d7a558a9Sdan    }
2614d7a558a9Sdan  } {1}
2615*abd6d84aSdan
2616*abd6d84aSdan  do_execsql_test 37.$tn.2 {
2617*abd6d84aSdan    VACUUM;
2618*abd6d84aSdan    SELECT * FROM t1;
2619*abd6d84aSdan  } {1}
2620*abd6d84aSdan
2621d7a558a9Sdan  db close
2622d7a558a9Sdan  sqlite3_shutdown
2623d7a558a9Sdan  sqlite3_config_uri 0
2624d7a558a9Sdan}
2625d7a558a9Sdan
2626d7a558a9Sdando_test 38.1 {
2627d7a558a9Sdan  catch { db close }
2628d7a558a9Sdan  forcedelete test.db
2629d7a558a9Sdan  set fd [open test.db w]
2630d7a558a9Sdan  puts $fd "hello world"
2631d7a558a9Sdan  close $fd
2632d7a558a9Sdan  sqlite3 db test.db
2633d7a558a9Sdan  catchsql { CREATE TABLE t1(x) }
2634d7a558a9Sdan} {1 {file is encrypted or is not a database}}
2635d7a558a9Sdando_test 38.2 {
2636d7a558a9Sdan  catch { db close }
2637d7a558a9Sdan  forcedelete test.db
2638d7a558a9Sdan} {}
2639d7a558a9Sdan
2640d7a558a9Sdando_test 39.1 {
2641d7a558a9Sdan  sqlite3 db test.db
2642d7a558a9Sdan  execsql {
2643d7a558a9Sdan    PRAGMA auto_vacuum = 1;
2644d7a558a9Sdan    CREATE TABLE t1(x);
2645d7a558a9Sdan    INSERT INTO t1 VALUES('xxx');
2646d7a558a9Sdan    INSERT INTO t1 VALUES('two');
2647d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2648d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2649d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2650d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2651d7a558a9Sdan    BEGIN;
2652d7a558a9Sdan    UPDATE t1 SET x = 'one' WHERE rowid=1;
2653d7a558a9Sdan  }
2654d7a558a9Sdan  set ::stmt [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
2655d7a558a9Sdan  sqlite3_step $::stmt
2656d7a558a9Sdan  sqlite3_column_text $::stmt 0
2657d7a558a9Sdan} {one}
2658d7a558a9Sdando_test 39.2 {
2659d7a558a9Sdan  execsql { CREATE TABLE t2(x) }
2660d7a558a9Sdan  sqlite3_step $::stmt
2661d7a558a9Sdan  sqlite3_column_text $::stmt 0
2662d7a558a9Sdan} {two}
2663d7a558a9Sdando_test 39.3 {
2664d7a558a9Sdan  sqlite3_finalize $::stmt
2665d7a558a9Sdan  execsql COMMIT
2666d7a558a9Sdan} {}
2667d7a558a9Sdan
2668d7a558a9Sdando_execsql_test 39.4 {
2669d7a558a9Sdan  PRAGMA auto_vacuum = 2;
2670d7a558a9Sdan  CREATE TABLE t3(x);
2671d7a558a9Sdan  CREATE TABLE t4(x);
2672d7a558a9Sdan
2673d7a558a9Sdan  DROP TABLE t2;
2674d7a558a9Sdan  DROP TABLE t3;
2675d7a558a9Sdan  DROP TABLE t4;
2676d7a558a9Sdan}
2677d7a558a9Sdando_test 39.5 {
2678d7a558a9Sdan  db close
2679d7a558a9Sdan  sqlite3 db test.db
2680d7a558a9Sdan  execsql {
2681d7a558a9Sdan    PRAGMA cache_size = 1;
2682d7a558a9Sdan    PRAGMA incremental_vacuum;
2683d7a558a9Sdan    PRAGMA integrity_check;
2684d7a558a9Sdan  }
2685d7a558a9Sdan} {ok}
2686d7a558a9Sdan
2687d7a558a9Sdando_test 40.1 {
2688d7a558a9Sdan  reset_db
2689d7a558a9Sdan  execsql {
2690d7a558a9Sdan    PRAGMA auto_vacuum = 1;
2691d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
2692d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2693d7a558a9Sdan    PRAGMA page_count;
2694d7a558a9Sdan  }
2695d7a558a9Sdan} {6}
2696d7a558a9Sdando_test 40.2 {
2697d7a558a9Sdan  execsql {
2698d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2699d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2700d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2701d7a558a9Sdan  }
2702d7a558a9Sdan} {}
2703d7a558a9Sdando_test 40.3 {
2704d7a558a9Sdan  db close
2705d7a558a9Sdan  sqlite3 db test.db
2706d7a558a9Sdan  execsql {
2707d7a558a9Sdan    PRAGMA cache_size = 1;
2708d7a558a9Sdan    CREATE TABLE t2(x);
2709d7a558a9Sdan    PRAGMA integrity_check;
2710d7a558a9Sdan  }
2711d7a558a9Sdan} {ok}
2712d7a558a9Sdan
2713d7a558a9Sdando_test 41.1 {
2714d7a558a9Sdan  reset_db
2715d7a558a9Sdan  execsql {
2716d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
2717d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(200));
2718d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2719d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2720d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2721d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2722d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2723d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2724d7a558a9Sdan  }
2725d7a558a9Sdan} {}
2726d7a558a9Sdando_test 41.2 {
2727d7a558a9Sdan  testvfs tv -default 1
2728d7a558a9Sdan  tv sectorsize 16384;
2729d7a558a9Sdan  tv devchar [list]
2730d7a558a9Sdan  db close
2731d7a558a9Sdan  sqlite3 db test.db
2732d7a558a9Sdan  execsql {
2733d7a558a9Sdan    PRAGMA cache_size = 1;
2734d7a558a9Sdan    DELETE FROM t1 WHERE rowid%4;
2735d7a558a9Sdan    PRAGMA integrity_check;
2736d7a558a9Sdan  }
2737d7a558a9Sdan} {ok}
2738*abd6d84aSdandb close
2739*abd6d84aSdantv delete
2740d7a558a9Sdan
2741*abd6d84aSdanset pending_prev [sqlite3_test_control_pending_byte 0x1000000]
2742*abd6d84aSdando_test 42.1 {
2743*abd6d84aSdan  reset_db
2744*abd6d84aSdan  execsql {
2745*abd6d84aSdan    CREATE TABLE t1(x, y);
2746*abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
2747*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2748*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2749*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2750*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2751*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2752*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2753*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2754*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2755*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2756*abd6d84aSdan  }
2757*abd6d84aSdan  db close
2758*abd6d84aSdan  sqlite3_test_control_pending_byte 0x0010000
2759*abd6d84aSdan  sqlite3 db test.db
2760*abd6d84aSdan  db eval { PRAGMA mmap_limit = 0 }
2761*abd6d84aSdan  catchsql { SELECT sum(length(y)) FROM t1 }
2762*abd6d84aSdan} {1 {database disk image is malformed}}
2763*abd6d84aSdando_test 42.2 {
2764*abd6d84aSdan  reset_db
2765*abd6d84aSdan  execsql {
2766*abd6d84aSdan    CREATE TABLE t1(x, y);
2767*abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
2768*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2769*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2770*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2771*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2772*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2773*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2774*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2775*abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2776*abd6d84aSdan  }
2777*abd6d84aSdan  db close
2778*abd6d84aSdan
2779*abd6d84aSdan  testvfs tv -default 1
2780*abd6d84aSdan  tv sectorsize 16384;
2781*abd6d84aSdan  tv devchar [list]
2782*abd6d84aSdan  sqlite3 db test.db -vfs tv
2783*abd6d84aSdan  execsql { UPDATE t1 SET x = randomblob(200) }
2784*abd6d84aSdan} {}
2785*abd6d84aSdandb close
2786*abd6d84aSdantv delete
2787*abd6d84aSdansqlite3_test_control_pending_byte $pending_prev
2788*abd6d84aSdan
2789*abd6d84aSdando_test 43.1 {
2790*abd6d84aSdan  reset_db
2791*abd6d84aSdan  execsql {
2792*abd6d84aSdan    CREATE TABLE t1(x, y);
2793*abd6d84aSdan    INSERT INTO t1 VALUES(1, 2);
2794*abd6d84aSdan    CREATE TABLE t2(x, y);
2795*abd6d84aSdan    INSERT INTO t2 VALUES(1, 2);
2796*abd6d84aSdan    CREATE TABLE t3(x, y);
2797*abd6d84aSdan    INSERT INTO t3 VALUES(1, 2);
2798*abd6d84aSdan  }
2799*abd6d84aSdan  db close
2800*abd6d84aSdan  sqlite3 db test.db
2801*abd6d84aSdan
2802*abd6d84aSdan  db eval { PRAGMA mmap_limit = 0 }
2803*abd6d84aSdan  db eval { SELECT * FROM t1 }
2804*abd6d84aSdan  sqlite3_db_status db CACHE_MISS 0
2805*abd6d84aSdan} {0 2 0}
2806*abd6d84aSdan
2807*abd6d84aSdando_test 43.2 {
2808*abd6d84aSdan  db eval { SELECT * FROM t2 }
2809*abd6d84aSdan  sqlite3_db_status db CACHE_MISS 1
2810*abd6d84aSdan} {0 3 0}
2811*abd6d84aSdan
2812*abd6d84aSdando_test 43.3 {
2813*abd6d84aSdan  db eval { SELECT * FROM t3 }
2814*abd6d84aSdan  sqlite3_db_status db CACHE_MISS 0
2815*abd6d84aSdan} {0 1 0}
2816d7a558a9Sdan
2817d353331aSdanfinish_test
2818*abd6d84aSdan
2819