xref: /sqlite-3.40.0/test/pager1.test (revision 8e6cf0a7)
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
274f9c8ce3cSdrh} {1 {CHECK constraint failed: counter}}
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
532*8e6cf0a7Sdrhset ::mj_delete_cnt 0
533e08341c6Sdanproc copy_on_mj_delete {method filename args} {
534e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
535c5484654Smistachkin    #
536c5484654Smistachkin    # NOTE: Is the file name relative?  If so, add the length of the current
537c5484654Smistachkin    #       directory.
538c5484654Smistachkin    #
539c5484654Smistachkin    if {[is_relative_file $filename]} {
540c5484654Smistachkin      set ::mj_filename_length \
541c5484654Smistachkin        [expr {[string length $filename] + [string length $::pwd]}]
542c5484654Smistachkin    } else {
543e08341c6Sdan      set ::mj_filename_length [string length $filename]
544c5484654Smistachkin    }
545e08341c6Sdan    faultsim_save
546*8e6cf0a7Sdrh    incr ::mj_delete_cnt
547e08341c6Sdan  }
548e08341c6Sdan  return SQLITE_OK
549e08341c6Sdan}
550e08341c6Sdan
551e08341c6Sdanforeach {tn1 tcl} {
552e08341c6Sdan  1 { set prefix "test.db" }
553e08341c6Sdan  2 {
554e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
555e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
556e08341c6Sdan    # contains a master-journal pointer so large that it could contain
557e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
558e08341c6Sdan    # make sure SQLite doesn't get confused by this.
559e08341c6Sdan    #
560e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
56133d85c9cSshaneh    if {$tcl_platform(platform)=="windows"} {
56233d85c9cSshaneh      # TBD need to figure out how to do this correctly for Windows!!!
56333d85c9cSshaneh      set nPadding [expr 255 - $::mj_filename_length]
56433d85c9cSshaneh    }
565e08341c6Sdan
566e08341c6Sdan    # We cannot just create a really long database file name to open, as
567e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
568e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
569e08341c6Sdan    # hierarchy to work in.
570e08341c6Sdan    #
571e08341c6Sdan    set dirname "d123456789012345678901234567890/"
572e08341c6Sdan    set nDir [expr $nPadding / 32]
573e08341c6Sdan    if { $nDir } {
574e08341c6Sdan      set p [string repeat $dirname $nDir]
575e08341c6Sdan      file mkdir $p
576e08341c6Sdan      cd $p
577e08341c6Sdan    }
578e08341c6Sdan
579e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
580e08341c6Sdan    set prefix "test.db${padding}"
581e08341c6Sdan  }
582e08341c6Sdan} {
583e08341c6Sdan  eval $tcl
584*8e6cf0a7Sdrh  foreach {tn2 sql usesMJ} {
585e08341c6Sdan    o {
586e08341c6Sdan      PRAGMA main.synchronous=OFF;
587e08341c6Sdan      PRAGMA aux.synchronous=OFF;
5883f94b609Sdan      PRAGMA journal_mode = DELETE;
589*8e6cf0a7Sdrh    } 0
590e08341c6Sdan    o512 {
591e08341c6Sdan      PRAGMA main.synchronous=OFF;
592e08341c6Sdan      PRAGMA aux.synchronous=OFF;
593e08341c6Sdan      PRAGMA main.page_size = 512;
594e08341c6Sdan      PRAGMA aux.page_size = 512;
5953f94b609Sdan      PRAGMA journal_mode = DELETE;
596*8e6cf0a7Sdrh    } 0
597e08341c6Sdan    n {
598e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
599e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
6003f94b609Sdan      PRAGMA journal_mode = DELETE;
601*8e6cf0a7Sdrh    } 1
602e08341c6Sdan    f {
603e08341c6Sdan      PRAGMA main.synchronous=FULL;
604e08341c6Sdan      PRAGMA aux.synchronous=FULL;
6053f94b609Sdan      PRAGMA journal_mode = DELETE;
606*8e6cf0a7Sdrh    } 1
607*8e6cf0a7Sdrh    w1 {
608*8e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
609*8e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
610*8e6cf0a7Sdrh      PRAGMA journal_mode = WAL;
611*8e6cf0a7Sdrh    } 0
612*8e6cf0a7Sdrh    w2 {
613*8e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
614*8e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
615*8e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
616*8e6cf0a7Sdrh      PRAGMA aux.journal_mode=WAL;
617*8e6cf0a7Sdrh    } 0
618*8e6cf0a7Sdrh    o1a {
619*8e6cf0a7Sdrh      PRAGMA main.synchronous=FULL;
620*8e6cf0a7Sdrh      PRAGMA aux.synchronous=OFF;
621*8e6cf0a7Sdrh      PRAGMA journal_mode=DELETE;
622*8e6cf0a7Sdrh    } 0
623*8e6cf0a7Sdrh    o1b {
624*8e6cf0a7Sdrh      PRAGMA main.synchronous=OFF;
625*8e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
626*8e6cf0a7Sdrh      PRAGMA journal_mode=DELETE;
627*8e6cf0a7Sdrh    } 0
628*8e6cf0a7Sdrh    m1 {
629*8e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
630*8e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
631*8e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
632*8e6cf0a7Sdrh      PRAGMA aux.journal_mode = MEMORY;
633*8e6cf0a7Sdrh    } 0
634*8e6cf0a7Sdrh    t1 {
635*8e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
636*8e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
637*8e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
638*8e6cf0a7Sdrh      PRAGMA aux.journal_mode = TRUNCATE;
639*8e6cf0a7Sdrh    } 1
640*8e6cf0a7Sdrh    p1 {
641*8e6cf0a7Sdrh      PRAGMA main.synchronous=NORMAL;
642*8e6cf0a7Sdrh      PRAGMA aux.synchronous=NORMAL;
643*8e6cf0a7Sdrh      PRAGMA main.journal_mode=DELETE;
644*8e6cf0a7Sdrh      PRAGMA aux.journal_mode = PERSIST;
645*8e6cf0a7Sdrh    } 1
646e08341c6Sdan  } {
647e08341c6Sdan
648e08341c6Sdan    set tn "${tn1}.${tn2}"
649e08341c6Sdan
650e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
651e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
652e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
653e08341c6Sdan    # file is deleted to commit the transaction.
654e08341c6Sdan    #
655e08341c6Sdan    tv filter xDelete
656e08341c6Sdan    do_test pager1-4.4.$tn.1 {
657*8e6cf0a7Sdrh      set ::mj_delete_cnt 0
658e08341c6Sdan      faultsim_delete_and_reopen $prefix
659e08341c6Sdan      execsql "
660e08341c6Sdan        ATTACH '${prefix}2' AS aux;
661e08341c6Sdan        $sql
662e08341c6Sdan        CREATE TABLE a(x);
663e08341c6Sdan        CREATE TABLE aux.b(x);
664e08341c6Sdan        INSERT INTO a VALUES('double-you');
665e08341c6Sdan        INSERT INTO a VALUES('why');
666e08341c6Sdan        INSERT INTO a VALUES('zed');
667e08341c6Sdan        INSERT INTO b VALUES('won');
668e08341c6Sdan        INSERT INTO b VALUES('too');
669e08341c6Sdan        INSERT INTO b VALUES('free');
670e08341c6Sdan      "
671e08341c6Sdan      execsql {
672e08341c6Sdan        BEGIN;
673e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
674e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
675e08341c6Sdan        COMMIT;
676e08341c6Sdan      }
677e08341c6Sdan    } {}
678e08341c6Sdan    tv filter {}
679e08341c6Sdan
680*8e6cf0a7Sdrh    # Verify that a master journal was deleted only for those cases where
681*8e6cf0a7Sdrh    # master journals really ought to be used
682*8e6cf0a7Sdrh    #
683*8e6cf0a7Sdrh    do_test pager1-4.4.$tn.1b {
684*8e6cf0a7Sdrh      set ::mj_delete_cnt
685*8e6cf0a7Sdrh    } $usesMJ
686*8e6cf0a7Sdrh
687e08341c6Sdan    # Check that the transaction was committed successfully.
688e08341c6Sdan    #
689e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
690e08341c6Sdan      SELECT * FROM a
691e08341c6Sdan    } {double-you why zed won too free}
692e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
693e08341c6Sdan      SELECT * FROM b
694e08341c6Sdan    } {won too free double-you why zed}
695e08341c6Sdan
696*8e6cf0a7Sdrh    if {$usesMJ} {
697e08341c6Sdan      # Restore the file-system and reopen the databases. Check that it now
698e08341c6Sdan      # appears that the transaction was not committed (because the file-system
699e08341c6Sdan      # was restored to the state where it had not been).
700e08341c6Sdan      #
701e08341c6Sdan      do_test pager1-4.4.$tn.4 {
702e08341c6Sdan        faultsim_restore_and_reopen $prefix
703e08341c6Sdan        execsql "ATTACH '${prefix}2' AS aux"
704e08341c6Sdan      } {}
705e08341c6Sdan      do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
706e08341c6Sdan      do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
707*8e6cf0a7Sdrh    }
708e08341c6Sdan
709e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
710e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
711e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
712e08341c6Sdan    #
713e08341c6Sdan    do_test pager1-4.4.$tn.7 {
714*8e6cf0a7Sdrh      if {$::mj_delete_cnt>0} {
715e08341c6Sdan        faultsim_restore_and_reopen $prefix
716fda06befSmistachkin        foreach f [glob ${prefix}-mj*] { forcedelete $f }
717*8e6cf0a7Sdrh      } else {
718*8e6cf0a7Sdrh        db close
719*8e6cf0a7Sdrh        sqlite3 db $prefix
720*8e6cf0a7Sdrh      }
721e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
722*8e6cf0a7Sdrh      glob -nocomplain ${prefix}-mj*
723e08341c6Sdan    } {}
724e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
725e08341c6Sdan      SELECT * FROM a
726e08341c6Sdan    } {double-you why zed won too free}
727e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
728e08341c6Sdan      SELECT * FROM b
729e08341c6Sdan    } {won too free double-you why zed}
730e08341c6Sdan  }
731e08341c6Sdan
732e08341c6Sdan  cd $pwd
733e08341c6Sdan}
734e08341c6Sdandb close
735e08341c6Sdantv delete
736fda06befSmistachkinforcedelete $dirname
7370e986f51Sdan
7380e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
7390e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
7400e986f51Sdan# two database pages (and page 1 - the change counter).
7410e986f51Sdan#
7420e986f51Sdantestvfs tv -default 1
7430e986f51Sdantv sectorsize 512
7440e986f51Sdantv script copy_on_journal_delete
7450e986f51Sdantv filter xDelete
7460e986f51Sdanproc copy_on_journal_delete {method filename args} {
7470e986f51Sdan  if {[string match *journal $filename]} faultsim_save
7480e986f51Sdan  return SQLITE_OK
7490e986f51Sdan}
7500e986f51Sdanfaultsim_delete_and_reopen
7510e986f51Sdando_execsql_test pager1.4.5.1 {
7523f94b609Sdan  PRAGMA journal_mode = DELETE;
7530e986f51Sdan  PRAGMA page_size = 1024;
7540e986f51Sdan  CREATE TABLE t1(a, b);
7550e986f51Sdan  CREATE TABLE t2(a, b);
7560e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
7570e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
7580e986f51Sdan  BEGIN;
7590e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
7600e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
7610e986f51Sdan  COMMIT;
7623f94b609Sdan} {delete}
7630e986f51Sdantv filter {}
7640e986f51Sdan
7650e986f51Sdan# Check the transaction was committed:
7660e986f51Sdan#
7670e986f51Sdando_execsql_test pager1.4.5.2 {
7680e986f51Sdan  SELECT * FROM t1;
7690e986f51Sdan  SELECT * FROM t2;
7700e986f51Sdan} {I II 1 2 III IV 3 4}
7710e986f51Sdan
772ec6ffc1aSdan# Now try four tests:
7730e986f51Sdan#
7740e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
7750e986f51Sdan#                is rolled back.
7760e986f51Sdan#
7770e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
7780e986f51Sdan#                journal. Check the transaction is not rolled back.
7790e986f51Sdan#
7800e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
7810e986f51Sdan#                journal. Check that the first record in the transaction is
7820e986f51Sdan#                played back, but not the second.
7830e986f51Sdan#
78410f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
78510f5a50eSdan#                readonly connection. This should fail, as a read-only
78610f5a50eSdan#                connection cannot roll back the database file.
78710f5a50eSdan#
7880e986f51Sdanfaultsim_restore_and_reopen
7890e986f51Sdando_execsql_test pager1.4.5.3 {
7900e986f51Sdan  SELECT * FROM t1;
7910e986f51Sdan  SELECT * FROM t2;
7920e986f51Sdan} {I II III IV}
7930e986f51Sdanfaultsim_restore_and_reopen
7940e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
7950e986f51Sdando_execsql_test pager1.4.5.4 {
7960e986f51Sdan  SELECT * FROM t1;
7970e986f51Sdan  SELECT * FROM t2;
7980e986f51Sdan} {I II 1 2 III IV 3 4}
7990e986f51Sdanfaultsim_restore_and_reopen
8000e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
8010e986f51Sdando_execsql_test pager1.4.5.5 {
8020e986f51Sdan  SELECT * FROM t1;
8030e986f51Sdan  SELECT * FROM t2;
8040e986f51Sdan} {I II III IV 3 4}
8050e986f51Sdan
80610f5a50eSdanfaultsim_restore_and_reopen
80710f5a50eSdandb close
80810f5a50eSdansqlite3 db test.db -readonly 1
80910f5a50eSdando_catchsql_test pager1.4.5.6 {
81010f5a50eSdan  SELECT * FROM t1;
81110f5a50eSdan  SELECT * FROM t2;
812b83c21e6Sdan} {1 {attempt to write a readonly database}}
813ec6ffc1aSdandb close
814ec6ffc1aSdan
815ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
816ec6ffc1aSdan# of the master journal file in $::mj_filename.
817ec6ffc1aSdan#
818ec6ffc1aSdantv script copy_on_mj_delete
819ec6ffc1aSdantv filter xDelete
820ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
821ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
822ec6ffc1aSdan    set ::mj_filename $filename
823ec6ffc1aSdan    faultsim_save
824ec6ffc1aSdan  }
825ec6ffc1aSdan  return SQLITE_OK
826ec6ffc1aSdan}
827ec6ffc1aSdando_test pager1.4.6.1 {
828ec6ffc1aSdan  faultsim_delete_and_reopen
829ec6ffc1aSdan  execsql {
8303f94b609Sdan    PRAGMA journal_mode = DELETE;
831ec6ffc1aSdan    ATTACH 'test.db2' AS two;
832ec6ffc1aSdan    CREATE TABLE t1(a, b);
833ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
834ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
835ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
836ec6ffc1aSdan    BEGIN;
837ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
838ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
839ec6ffc1aSdan    COMMIT;
840ec6ffc1aSdan  }
841ec6ffc1aSdan  tv filter {}
842ec6ffc1aSdan  db close
843ec6ffc1aSdan} {}
844ec6ffc1aSdan
845ec6ffc1aSdanfaultsim_restore_and_reopen
846ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
847ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
848ec6ffc1aSdando_execsql_test pager1.4.6.4 {
849ec6ffc1aSdan  ATTACH 'test.db2' AS two;
850ec6ffc1aSdan  SELECT * FROM t2;
851ec6ffc1aSdan} {1 t2.1}
852ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
853ec6ffc1aSdan
854ec6ffc1aSdanfaultsim_restore_and_reopen
855ec6ffc1aSdandb close
856ec6ffc1aSdando_test pager1.4.6.8 {
857ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
858ec6ffc1aSdan  tv filter xDelete
859ec6ffc1aSdan  sqlite3 db test.db2
860ec6ffc1aSdan  execsql {
8613f94b609Sdan    PRAGMA journal_mode = DELETE;
862ec6ffc1aSdan    ATTACH 'test.db3' AS three;
863ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
864ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
865ec6ffc1aSdan    BEGIN;
866ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
867ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
868ec6ffc1aSdan    COMMIT;
869ec6ffc1aSdan  }
870ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
871ec6ffc1aSdan} {1}
872ec6ffc1aSdanfaultsim_restore_and_reopen
873ec6ffc1aSdantv filter {}
874ec6ffc1aSdan
875ec6ffc1aSdan# The file-system now contains:
876ec6ffc1aSdan#
877ec6ffc1aSdan#   * three databases
878ec6ffc1aSdan#   * three hot-journal files
879ec6ffc1aSdan#   * two master-journal files.
880ec6ffc1aSdan#
881ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
882ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
883ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
884ec6ffc1aSdan# test.db should delete $::mj_filename1.
885ec6ffc1aSdan#
886ec6ffc1aSdando_test pager1.4.6.9 {
887ec6ffc1aSdan  lsort [glob test.db*]
888ec6ffc1aSdan} [lsort [list                                           \
889ec6ffc1aSdan  test.db test.db2 test.db3                              \
890ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
891ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
892ec6ffc1aSdan]]
893ec6ffc1aSdan
894ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
895ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
896ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
897ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
898ec6ffc1aSdan#
899ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
900ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
901ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
902ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
903ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
904ec6ffc1aSdan
905ec6ffc1aSdando_execsql_test pager1.4.6.12 {
906ec6ffc1aSdan  ATTACH 'test.db2' AS two;
907ec6ffc1aSdan  SELECT * FROM t2;
908ec6ffc1aSdan} {1 t2.1}
909ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
910ec6ffc1aSdando_execsql_test pager1.4.6.14 {
911ec6ffc1aSdan  ATTACH 'test.db3' AS three;
912ec6ffc1aSdan  SELECT * FROM t3;
913ec6ffc1aSdan} {1 t3.1}
914ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
91510f5a50eSdan
9160e986f51Sdandb close
9170e986f51Sdantv delete
918e08341c6Sdan
919c8ce3972Sdantestvfs tv -default 1
920c8ce3972Sdantv sectorsize 512
921c8ce3972Sdantv script copy_on_journal_delete
922c8ce3972Sdantv filter xDelete
923c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
924c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
925c8ce3972Sdan  return SQLITE_OK
926c8ce3972Sdan}
927c8ce3972Sdanfaultsim_delete_and_reopen
928c8ce3972Sdando_execsql_test pager1.4.7.1 {
9293f94b609Sdan  PRAGMA journal_mode = DELETE;
930c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
931c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
932c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
933c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
934c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
935c8ce3972Sdan  BEGIN;
936c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
937c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
938c8ce3972Sdan  COMMIT;
9393f94b609Sdan} {delete}
940c8ce3972Sdantv filter {}
941c8ce3972Sdandb close
942c8ce3972Sdantv delete
943e1186ab2Sdrhcatch {
944e1186ab2Sdrh  test_syscall install fchmod
945e1186ab2Sdrh  test_syscall fault 1 1
946e1186ab2Sdrh}
947c8ce3972Sdando_test pager1.4.7.2 {
948c8ce3972Sdan  faultsim_restore_and_reopen
949c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
950c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
951c8ce3972Sdan  catchsql { SELECT * FROM t1 }
952c8ce3972Sdan} {1 {unable to open database file}}
953e1186ab2Sdrhcatch {
954e1186ab2Sdrh  test_syscall reset
955e1186ab2Sdrh  test_syscall fault 0 0
956e1186ab2Sdrh}
957c8ce3972Sdando_test pager1.4.7.3 {
958c8ce3972Sdan  db close
959c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
960c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
961fda06befSmistachkin  delete_file test.db-journal
962c8ce3972Sdan  file exists test.db-journal
963c8ce3972Sdan} {0}
964421377e6Sdrhdo_test pager1.4.8.1 {
965421377e6Sdrh  catch {file attributes test.db -permissions r--------}
966421377e6Sdrh  catch {file attributes test.db -readonly 1}
967421377e6Sdrh  sqlite3 db test.db
968421377e6Sdrh  db eval { SELECT * FROM t1 }
969421377e6Sdrh  sqlite3_db_readonly db main
970421377e6Sdrh} {1}
971421377e6Sdrhdo_test pager1.4.8.2 {
972421377e6Sdrh  sqlite3_db_readonly db xyz
973421377e6Sdrh} {-1}
974421377e6Sdrhdo_test pager1.4.8.3 {
975421377e6Sdrh  db close
976421377e6Sdrh  catch {file attributes test.db -readonly 0}
977db0ad5f2Sdan  catch {file attributes test.db -permissions rw-rw-rw-} msg
978421377e6Sdrh  sqlite3 db test.db
979421377e6Sdrh  db eval { SELECT * FROM t1 }
980421377e6Sdrh  sqlite3_db_readonly db main
981421377e6Sdrh} {0}
982c8ce3972Sdan
983de4996e2Sdan#-------------------------------------------------------------------------
984146ed78bSdan# The following tests deal with multi-file commits.
985de4996e2Sdan#
986146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
987146ed78bSdan#               another connection is holding a SHARED lock on one of the
988146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
989146ed78bSdan#
990146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
991146ed78bSdan#
992146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
993146ed78bSdan#
994146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
995146ed78bSdan#               name is added to a journal file immediately after the last
996146ed78bSdan#               journal record. But with synchronous=full, extra unused space
997146ed78bSdan#               is allocated between the last journal record and the
998146ed78bSdan#               master-journal file name so that the master-journal file
999146ed78bSdan#               name does not lie on the same sector as the last journal file
1000146ed78bSdan#               record.
1001146ed78bSdan#
1002e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
1003e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
1004e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
1005e08341c6Sdan#
1006146ed78bSdan#
1007146ed78bSdando_test pager1-5.1.1 {
1008146ed78bSdan  faultsim_delete_and_reopen
1009146ed78bSdan  execsql {
1010146ed78bSdan    ATTACH 'test.db2' AS aux;
1011146ed78bSdan    CREATE TABLE t1(a, b);
1012146ed78bSdan    CREATE TABLE aux.t2(a, b);
1013146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
1014146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
1015146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
1016146ed78bSdan  }
1017146ed78bSdan} {}
1018146ed78bSdando_test pager1-5.1.2 {
1019146ed78bSdan  execsql {
1020146ed78bSdan    BEGIN;
1021146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
1022146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
1023146ed78bSdan  }
1024146ed78bSdan  sqlite3 db2 test.db2
1025146ed78bSdan  execsql {
1026146ed78bSdan    BEGIN;
1027146ed78bSdan      SELECT * FROM t2;
1028146ed78bSdan  } db2
1029146ed78bSdan} {}
1030146ed78bSdando_test pager1-5.1.3 {
1031146ed78bSdan  catchsql COMMIT
1032146ed78bSdan} {1 {database is locked}}
1033146ed78bSdando_test pager1-5.1.4 {
1034146ed78bSdan  execsql COMMIT db2
1035146ed78bSdan  execsql COMMIT
1036146ed78bSdan  execsql { SELECT * FROM t2 } db2
1037146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
1038146ed78bSdando_test pager1-5.1.5 {
1039146ed78bSdan  db2 close
1040146ed78bSdan} {}
1041146ed78bSdan
1042146ed78bSdando_test pager1-5.2.1 {
1043146ed78bSdan  execsql {
1044146ed78bSdan    PRAGMA journal_mode = memory;
1045146ed78bSdan    BEGIN;
1046146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
1047146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
1048146ed78bSdan    COMMIT;
1049146ed78bSdan  }
1050146ed78bSdan} {memory}
1051146ed78bSdando_test pager1-5.3.1 {
1052146ed78bSdan  execsql {
1053146ed78bSdan    PRAGMA journal_mode = off;
1054146ed78bSdan    BEGIN;
1055146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1056146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1057146ed78bSdan    COMMIT;
1058146ed78bSdan  }
1059146ed78bSdan} {off}
1060146ed78bSdan
1061146ed78bSdando_test pager1-5.4.1 {
1062146ed78bSdan  db close
1063146ed78bSdan  testvfs tv
1064146ed78bSdan  sqlite3 db test.db -vfs tv
1065146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
1066146ed78bSdan
1067146ed78bSdan  tv filter xDelete
1068146ed78bSdan  tv script max_journal_size
1069146ed78bSdan  tv sectorsize 512
1070146ed78bSdan  set ::max_journal 0
1071146ed78bSdan  proc max_journal_size {method args} {
1072146ed78bSdan    set sz 0
1073146ed78bSdan    catch { set sz [file size test.db-journal] }
1074146ed78bSdan    if {$sz > $::max_journal} {
1075146ed78bSdan      set ::max_journal $sz
1076146ed78bSdan    }
1077146ed78bSdan    return SQLITE_OK
1078146ed78bSdan  }
1079146ed78bSdan  execsql {
1080146ed78bSdan    PRAGMA journal_mode = DELETE;
1081146ed78bSdan    PRAGMA synchronous = NORMAL;
1082146ed78bSdan    BEGIN;
1083146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
1084146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
1085146ed78bSdan    COMMIT;
1086146ed78bSdan  }
10877f9026ddSdan
10887f9026ddSdan  # The size of the journal file is now:
10897f9026ddSdan  #
10907f9026ddSdan  #   1) 512 byte header +
10917f9026ddSdan  #   2) 2 * (1024+8) byte records +
10927f9026ddSdan  #   3) 20+N bytes of master-journal pointer, where N is the size of
10937f9026ddSdan  #      the master-journal name encoded as utf-8 with no nul term.
10947f9026ddSdan  #
10957f9026ddSdan  set mj_pointer [expr {
1096c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
10977f9026ddSdan  }]
1098c5484654Smistachkin  #
1099c5484654Smistachkin  #   NOTE: For item 3 above, if the current SQLite VFS lacks the concept of a
1100c5484654Smistachkin  #         current directory, the length of the current directory name plus 1
1101c5484654Smistachkin  #         character for the directory separator character are NOT counted as
1102c5484654Smistachkin  #         part of the total size; otherwise, they are.
1103c5484654Smistachkin  #
1104c5484654Smistachkin  ifcapable curdir {
11056aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1106c5484654Smistachkin  }
11077f9026ddSdan  expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
11087f9026ddSdan} 1
1109146ed78bSdando_test pager1-5.4.2 {
1110146ed78bSdan  set ::max_journal 0
1111146ed78bSdan  execsql {
1112146ed78bSdan    PRAGMA synchronous = full;
1113146ed78bSdan    BEGIN;
1114146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
1115146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
1116146ed78bSdan    COMMIT;
1117146ed78bSdan  }
11187f9026ddSdan
11197f9026ddSdan  # In synchronous=full mode, the master-journal pointer is not written
11207f9026ddSdan  # directly after the last record in the journal file. Instead, it is
11217f9026ddSdan  # written starting at the next (in this case 512 byte) sector boundary.
11227f9026ddSdan  #
11237f9026ddSdan  set mj_pointer [expr {
1124c5484654Smistachkin    20 + [string length "test.db-mjXXXXXX9XX"]
11257f9026ddSdan  }]
1126c5484654Smistachkin  #
1127c5484654Smistachkin  #   NOTE: If the current SQLite VFS lacks the concept of a current directory,
1128c5484654Smistachkin  #         the length of the current directory name plus 1 character for the
1129c5484654Smistachkin  #         directory separator character are NOT counted as part of the total
1130c5484654Smistachkin  #         size; otherwise, they are.
1131c5484654Smistachkin  #
1132c5484654Smistachkin  ifcapable curdir {
11336aa18c95Smistachkin    set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
1134c5484654Smistachkin  }
11357f9026ddSdan  expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
11367f9026ddSdan} 1
1137146ed78bSdandb close
1138146ed78bSdantv delete
1139146ed78bSdan
1140146ed78bSdando_test pager1-5.5.1 {
1141146ed78bSdan  sqlite3 db test.db
1142146ed78bSdan  execsql {
1143146ed78bSdan    ATTACH 'test.db2' AS aux;
1144146ed78bSdan    PRAGMA journal_mode = PERSIST;
1145146ed78bSdan    CREATE TABLE t3(a, b);
1146146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
1147146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
1148146ed78bSdan  }
1149146ed78bSdan  expr [file size test.db-journal] > 15000
1150146ed78bSdan} {1}
1151146ed78bSdando_test pager1-5.5.2 {
1152146ed78bSdan  execsql {
1153146ed78bSdan    PRAGMA synchronous = full;
1154146ed78bSdan    BEGIN;
1155146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
1156146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
1157146ed78bSdan    COMMIT;
1158146ed78bSdan  }
1159146ed78bSdan  file size test.db-journal
1160146ed78bSdan} {0}
1161146ed78bSdan
1162146ed78bSdan
1163146ed78bSdan#-------------------------------------------------------------------------
1164146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1165146ed78bSdan#
1166146ed78bSdando_test pager1-6.1 {
1167146ed78bSdan  faultsim_delete_and_reopen
1168146ed78bSdan  execsql {
1169f43d7fceSdan    PRAGMA auto_vacuum = none;
1170146ed78bSdan    PRAGMA max_page_count = 10;
1171146ed78bSdan    CREATE TABLE t2(a, b);
1172146ed78bSdan    CREATE TABLE t3(a, b);
1173146ed78bSdan    CREATE TABLE t4(a, b);
1174146ed78bSdan    CREATE TABLE t5(a, b);
1175146ed78bSdan    CREATE TABLE t6(a, b);
1176146ed78bSdan    CREATE TABLE t7(a, b);
1177146ed78bSdan    CREATE TABLE t8(a, b);
1178146ed78bSdan    CREATE TABLE t9(a, b);
1179146ed78bSdan    CREATE TABLE t10(a, b);
1180146ed78bSdan  }
1181146ed78bSdan} {10}
1182d353331aSdando_catchsql_test pager1-6.2 {
1183d353331aSdan  CREATE TABLE t11(a, b)
1184146ed78bSdan} {1 {database or disk is full}}
1185d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1186d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1187d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1188d353331aSdando_execsql_test pager1-6.7 {
1189d353331aSdan  BEGIN;
1190d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1191d353331aSdan    PRAGMA max_page_count = 13;
1192d353331aSdan} {13}
1193d353331aSdando_execsql_test pager1-6.8 {
1194d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1195d353331aSdan    PRAGMA max_page_count = 10;
1196d353331aSdan} {11}
1197d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1198de4996e2Sdan
119960ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
120022b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
120122b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
120222b328b2Sdan
1203153eda0aSdan
1204153eda0aSdan#-------------------------------------------------------------------------
1205153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1206153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1207153eda0aSdan#
1208153eda0aSdan# Each test is specified with 5 variables. As follows:
1209153eda0aSdan#
1210153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1211153eda0aSdan#   $sql: SQL to execute.
1212153eda0aSdan#   $res: Expected result of executing $sql.
1213153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1214153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1215153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1216153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1217153eda0aSdan#
121838e1a279Sdanifcapable wal {
1219153eda0aSdan  faultsim_delete_and_reopen
1220153eda0aSdan  foreach {tn sql res js ws} [subst {
1221153eda0aSdan
1222153eda0aSdan    1  {
1223153eda0aSdan      CREATE TABLE t1(a, b);
1224153eda0aSdan      PRAGMA auto_vacuum=OFF;
1225153eda0aSdan      PRAGMA synchronous=NORMAL;
1226153eda0aSdan      PRAGMA page_size=1024;
1227153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1228153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1229153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1230153eda0aSdan    } {exclusive truncate} 0 -1
1231153eda0aSdan
1232153eda0aSdan    2  {
1233153eda0aSdan      BEGIN IMMEDIATE;
1234153eda0aSdan        SELECT * FROM t1;
1235153eda0aSdan      COMMIT;
1236153eda0aSdan    } {1 2} 0 -1
1237153eda0aSdan
1238153eda0aSdan    3  {
1239153eda0aSdan      BEGIN;
1240153eda0aSdan        SELECT * FROM t1;
1241153eda0aSdan      COMMIT;
1242153eda0aSdan    } {1 2} 0 -1
1243153eda0aSdan
1244153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal       -1 -1
1245153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}        -1 [wal_file_size 1 1024]
12468c408004Sdan    6  { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
1247153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
1248153eda0aSdan
1249153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1250153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1251153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1252153eda0aSdan
1253153eda0aSdan  }] {
1254153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1255153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1256153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1257153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1258153eda0aSdan  }
125938e1a279Sdan}
1260153eda0aSdan
126189ccf448Sdando_test pager1-7.2.1 {
126289ccf448Sdan  faultsim_delete_and_reopen
126389ccf448Sdan  execsql {
126489ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
126589ccf448Sdan    CREATE TABLE t1(a, b);
126689ccf448Sdan    BEGIN;
126789ccf448Sdan      PRAGMA journal_mode = delete;
126889ccf448Sdan      PRAGMA journal_mode = truncate;
126989ccf448Sdan  }
127089ccf448Sdan} {exclusive delete truncate}
127189ccf448Sdando_test pager1-7.2.2 {
127289ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
127389ccf448Sdan  execsql { PRAGMA journal_mode = persist }
127489ccf448Sdan} {truncate}
127589ccf448Sdando_test pager1-7.2.3 {
127689ccf448Sdan  execsql { COMMIT }
127789ccf448Sdan  execsql {
127889ccf448Sdan    PRAGMA journal_mode = persist;
127989ccf448Sdan    PRAGMA journal_size_limit;
128089ccf448Sdan  }
128189ccf448Sdan} {persist -1}
128289ccf448Sdan
1283d353331aSdan#-------------------------------------------------------------------------
1284d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1285d353331aSdan# ":memory:" and "" open temporary databases.
1286d353331aSdan#
12870e986f51Sdanforeach {tn filename} {
12880e986f51Sdan  1 :memory:
12890e986f51Sdan  2 ""
12900e986f51Sdan} {
12910e986f51Sdan  do_test pager1-8.$tn.1 {
1292153eda0aSdan    faultsim_delete_and_reopen
1293153eda0aSdan    db close
12940e986f51Sdan    sqlite3 db $filename
1295153eda0aSdan    execsql {
1296c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1297153eda0aSdan      CREATE TABLE x1(x);
1298153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1299153eda0aSdan      INSERT INTO x1 VALUES('James');
1300153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1301153eda0aSdan      SELECT * FROM x1;
1302153eda0aSdan    }
1303153eda0aSdan  } {Charles James Mary}
13040e986f51Sdan
13050e986f51Sdan  do_test pager1-8.$tn.2 {
13060e986f51Sdan    sqlite3 db2 $filename
13070e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1308153eda0aSdan  } {1 {no such table: x1}}
1309153eda0aSdan
13100e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
13110e986f51Sdan    BEGIN;
13120e986f51Sdan      INSERT INTO x1 VALUES('William');
13130e986f51Sdan      INSERT INTO x1 VALUES('Anne');
13140e986f51Sdan    ROLLBACK;
13150e986f51Sdan  } {}
13160e986f51Sdan}
13170e986f51Sdan
1318dca321aeSdan#-------------------------------------------------------------------------
1319dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1320dca321aeSdan# the pager and the backup API. Test cases:
1321dca321aeSdan#
1322dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1323dca321aeSdan#                 source db is written to during the backup op.
1324dca321aeSdan#
1325dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1326dca321aeSdan#                 source db is written to and then rolled back during a
1327dca321aeSdan#                 backup operation.
1328dca321aeSdan#
1329dca321aeSdando_test pager1-9.0.1 {
1330dca321aeSdan  faultsim_delete_and_reopen
1331dca321aeSdan  db func a_string a_string
1332dca321aeSdan  execsql {
1333dca321aeSdan    PRAGMA cache_size = 10;
1334dca321aeSdan    BEGIN;
1335dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1336dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1337dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1338dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1339dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1340dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1341dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1342dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1343dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1344dca321aeSdan    COMMIT;
1345dca321aeSdan  }
1346dca321aeSdan} {}
1347dca321aeSdando_test pager1-9.0.2 {
1348dca321aeSdan  sqlite3 db2 test.db2
1349dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1350dca321aeSdan  sqlite3_backup B db2 main db main
1351dca321aeSdan  list [B step 10000] [B finish]
1352dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1353dca321aeSdando_test pager1-9.0.3 {
1354dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1355dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1356dca321aeSdan
1357dca321aeSdando_test pager1-9.1.1 {
1358dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1359dca321aeSdan  sqlite3_backup B db2 main db main
1360dca321aeSdan  B step 30
1361dca321aeSdan} {SQLITE_OK}
1362dca321aeSdando_test pager1-9.1.2 {
1363dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1364dca321aeSdan  list [B step 10000] [B finish]
1365dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1366dca321aeSdando_test pager1-9.1.3 {
1367dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1368dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1369dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1370dca321aeSdan
1371dca321aeSdando_test pager1-9.2.1 {
1372dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1373dca321aeSdan  sqlite3_backup B db2 main db main
1374dca321aeSdan  B step 30
1375dca321aeSdan} {SQLITE_OK}
1376dca321aeSdando_test pager1-9.2.2 {
1377dca321aeSdan  execsql {
1378dca321aeSdan    BEGIN;
1379dca321aeSdan      UPDATE ab SET b = a_string(301);
1380dca321aeSdan    ROLLBACK;
1381dca321aeSdan  }
1382dca321aeSdan  list [B step 10000] [B finish]
1383dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1384dca321aeSdando_test pager1-9.2.3 {
1385dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1386dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1387dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1388ec6ffc1aSdandb close
1389ec6ffc1aSdandb2 close
1390ec6ffc1aSdan
1391c396d4afSdando_test pager1-9.3.1 {
1392c396d4afSdan  testvfs tv -default 1
1393c396d4afSdan  tv sectorsize 4096
1394c396d4afSdan  faultsim_delete_and_reopen
1395c396d4afSdan
1396c396d4afSdan  execsql { PRAGMA page_size = 1024 }
1397c396d4afSdan  for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
1398c396d4afSdan} {}
1399c396d4afSdando_test pager1-9.3.2 {
1400c396d4afSdan  sqlite3 db2 test.db2
1401f412ee2eSdan
1402c396d4afSdan  execsql {
1403c396d4afSdan    PRAGMA page_size = 4096;
1404c396d4afSdan    PRAGMA synchronous = OFF;
1405c396d4afSdan    CREATE TABLE t1(a, b);
1406c396d4afSdan    CREATE TABLE t2(a, b);
1407c396d4afSdan  } db2
1408c396d4afSdan
1409c396d4afSdan  sqlite3_backup B db2 main db main
1410c396d4afSdan  B step 30
1411c396d4afSdan  list [B step 10000] [B finish]
1412c396d4afSdan} {SQLITE_DONE SQLITE_OK}
1413c396d4afSdando_test pager1-9.3.3 {
1414c396d4afSdan  db2 close
1415c396d4afSdan  db close
1416c396d4afSdan  tv delete
1417c396d4afSdan  file size test.db2
1418c396d4afSdan} [file size test.db]
1419c396d4afSdan
1420f412ee2eSdando_test pager1-9.4.1 {
1421f412ee2eSdan  faultsim_delete_and_reopen
1422f412ee2eSdan  sqlite3 db2 test.db2
1423f412ee2eSdan  execsql {
1424f412ee2eSdan    PRAGMA page_size = 4096;
1425f412ee2eSdan    CREATE TABLE t1(a, b);
1426f412ee2eSdan    CREATE TABLE t2(a, b);
1427f412ee2eSdan  } db2
1428f412ee2eSdan  sqlite3_backup B db2 main db main
1429f412ee2eSdan  list [B step 10000] [B finish]
1430f412ee2eSdan} {SQLITE_DONE SQLITE_OK}
1431f412ee2eSdando_test pager1-9.4.2 {
1432f412ee2eSdan  list [file size test.db2] [file size test.db]
1433b483eba0Sdan} {1024 0}
143433d85c9cSshanehdb2 close
1435d0b0d4dcSdan
1436ec6ffc1aSdan#-------------------------------------------------------------------------
1437ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1438ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1439ec6ffc1aSdan#
1440ec6ffc1aSdantestvfs tv -default 1
1441ec6ffc1aSdanforeach sectorsize {
1442d7a558a9Sdan    16
1443ec6ffc1aSdan    32   64   128   256   512   1024   2048
1444ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1445ec6ffc1aSdan} {
1446ec6ffc1aSdan  tv sectorsize $sectorsize
14471eaaf93aSdrh  tv devchar {}
1448ec6ffc1aSdan  set eff $sectorsize
1449ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1450ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1451ec6ffc1aSdan
1452d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1453ec6ffc1aSdan    faultsim_delete_and_reopen
1454d0b0d4dcSdan    db func a_string a_string
1455ec6ffc1aSdan    execsql {
1456ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1457ec6ffc1aSdan      PRAGMA page_size = 1024;
1458d0b0d4dcSdan      BEGIN;
1459ec6ffc1aSdan        CREATE TABLE t1(a, b);
1460d0b0d4dcSdan        CREATE TABLE t2(a, b);
1461d0b0d4dcSdan        CREATE TABLE t3(a, b);
1462d0b0d4dcSdan      COMMIT;
1463ec6ffc1aSdan    }
1464ec6ffc1aSdan    file size test.db-journal
1465d7a558a9Sdan  } [expr $sectorsize > 65536 ? 65536 : ($sectorsize<32 ? 512 : $sectorsize)]
1466d0b0d4dcSdan
1467d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1468d0b0d4dcSdan    execsql {
1469d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1470d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1471d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1472d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1473d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1474d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1475ec6ffc1aSdan    }
1476d0b0d4dcSdan  } {}
1477d0b0d4dcSdan
1478d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1479d0b0d4dcSdan    db close
1480d0b0d4dcSdan    sqlite3 db test.db
1481d0b0d4dcSdan    execsql {
1482d0b0d4dcSdan      PRAGMA cache_size = 10;
1483d0b0d4dcSdan      BEGIN;
1484d0b0d4dcSdan    }
1485d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1486d0b0d4dcSdan    execsql {
1487d0b0d4dcSdan      COMMIT;
1488d0b0d4dcSdan      SELECT * FROM t2;
1489d0b0d4dcSdan    }
1490d0b0d4dcSdan  } {1 2}
1491d0b0d4dcSdan
1492d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1493d0b0d4dcSdan    execsql {
1494d0b0d4dcSdan      CREATE TABLE t6(a, b);
1495d0b0d4dcSdan      CREATE TABLE t7(a, b);
1496d0b0d4dcSdan      CREATE TABLE t5(a, b);
1497d0b0d4dcSdan      DROP TABLE t6;
1498d0b0d4dcSdan      DROP TABLE t7;
1499d0b0d4dcSdan    }
1500d0b0d4dcSdan    execsql {
1501d0b0d4dcSdan      BEGIN;
1502d0b0d4dcSdan        CREATE TABLE t6(a, b);
1503d0b0d4dcSdan    }
1504d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1505d0b0d4dcSdan    execsql {
1506d0b0d4dcSdan      COMMIT;
1507d0b0d4dcSdan      SELECT * FROM t5;
1508d0b0d4dcSdan    }
1509d0b0d4dcSdan  } {1 2}
1510d0b0d4dcSdan
1511d0b0d4dcSdan}
1512d0b0d4dcSdandb close
1513d0b0d4dcSdan
1514d0b0d4dcSdantv sectorsize 4096
1515d0b0d4dcSdando_test pager1.10.x.1 {
1516d0b0d4dcSdan  faultsim_delete_and_reopen
1517d0b0d4dcSdan  execsql {
1518f43d7fceSdan    PRAGMA auto_vacuum = none;
1519d0b0d4dcSdan    PRAGMA page_size = 1024;
1520d0b0d4dcSdan    CREATE TABLE t1(x);
1521d0b0d4dcSdan  }
1522d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1523d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1524d0b0d4dcSdan  }
1525d0b0d4dcSdan  file size test.db
1526d0b0d4dcSdan} {32768}
1527d0b0d4dcSdando_test pager1.10.x.2 {
1528d0b0d4dcSdan  execsql {
1529d0b0d4dcSdan    CREATE TABLE t2(x);
1530d0b0d4dcSdan    DROP TABLE t2;
1531d0b0d4dcSdan  }
1532d0b0d4dcSdan  file size test.db
1533d0b0d4dcSdan} {33792}
1534d0b0d4dcSdando_test pager1.10.x.3 {
1535d0b0d4dcSdan  execsql {
1536d0b0d4dcSdan    BEGIN;
1537d0b0d4dcSdan    CREATE TABLE t2(x);
1538d0b0d4dcSdan  }
1539d0b0d4dcSdan  recursive_select 30 t1
1540d0b0d4dcSdan  execsql {
1541d0b0d4dcSdan    CREATE TABLE t3(x);
1542d0b0d4dcSdan    COMMIT;
1543d0b0d4dcSdan  }
1544d0b0d4dcSdan} {}
1545d0b0d4dcSdan
1546ec6ffc1aSdandb close
1547ec6ffc1aSdantv delete
1548ec6ffc1aSdan
1549ec6ffc1aSdantestvfs tv -default 1
1550ec6ffc1aSdanfaultsim_delete_and_reopen
1551ec6ffc1aSdandb func a_string a_string
1552ec6ffc1aSdando_execsql_test pager1-11.1 {
15533f94b609Sdan  PRAGMA journal_mode = DELETE;
1554ec6ffc1aSdan  PRAGMA cache_size = 10;
1555ec6ffc1aSdan  BEGIN;
1556ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1557ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1558ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1559ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1560ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1561ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1562ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1563ec6ffc1aSdan  COMMIT;
1564ec6ffc1aSdan  BEGIN;
1565ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
15663f94b609Sdan} {delete}
1567ec6ffc1aSdan
1568ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1569ec6ffc1aSdantv script lockout
1570ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1571ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1572ec6ffc1aSdan
1573ec6ffc1aSdantv script {}
1574ec6ffc1aSdando_test pager1-11.3 {
1575ec6ffc1aSdan  sqlite3 db2 test.db
1576ec6ffc1aSdan  execsql {
1577ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1578ec6ffc1aSdan    PRAGMA integrity_check;
1579ec6ffc1aSdan  } db2
1580ec6ffc1aSdan} {truncate ok}
1581ec6ffc1aSdando_test pager1-11.4 {
1582ec6ffc1aSdan  db2 close
1583f6c61471Sdan  file exists test.db-journal
1584ec6ffc1aSdan} {0}
1585ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1586f9b4419dSdandb close
1587f9b4419dSdantv delete
1588ec6ffc1aSdan
1589f9b4419dSdan#-------------------------------------------------------------------------
1590f9b4419dSdan# Test "PRAGMA page_size"
1591f9b4419dSdan#
1592f43d7fceSdantestvfs tv -default 1
1593f43d7fceSdantv sectorsize 1024
1594f9b4419dSdanforeach pagesize {
1595f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1596f9b4419dSdan} {
1597f9b4419dSdan  faultsim_delete_and_reopen
1598f9b4419dSdan
1599f43d7fceSdan  # The sector-size (according to the VFS) is 1024 bytes. So if the
1600f43d7fceSdan  # page-size requested using "PRAGMA page_size" is greater than the
1601f43d7fceSdan  # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
1602f43d7fceSdan  # page-size remains 1024 bytes.
1603f43d7fceSdan  #
1604f43d7fceSdan  set eff $pagesize
1605f43d7fceSdan  if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
1606f43d7fceSdan
1607f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1608f9b4419dSdan    sqlite3 db2 test.db
1609f9b4419dSdan    execsql "
1610f9b4419dSdan      PRAGMA page_size = $pagesize;
1611f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1612f9b4419dSdan    " db2
1613f9b4419dSdan    file size test.db
1614f43d7fceSdan  } $eff
1615f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1616f9b4419dSdan    sqlite3 db2 test.db
1617f9b4419dSdan    execsql {
1618f9b4419dSdan      SELECT count(*) FROM v;
1619f9b4419dSdan      PRAGMA main.page_size;
1620f9b4419dSdan    } db2
1621f43d7fceSdan  } [list 1 $eff]
1622f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1623f9b4419dSdan    execsql {
1624f9b4419dSdan      SELECT count(*) FROM v;
1625f9b4419dSdan      PRAGMA main.page_size;
1626f9b4419dSdan    }
1627f43d7fceSdan  } [list 1 $eff]
1628f9b4419dSdan  db2 close
1629f9b4419dSdan}
1630f43d7fceSdandb close
1631f43d7fceSdantv delete
1632dca321aeSdan
1633d353331aSdan#-------------------------------------------------------------------------
1634d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1635d353331aSdan#
1636d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1637d353331aSdan#                journal mode: If the journal associated with a transaction
1638d353331aSdan#                is smaller than the journal file (because a previous
1639d353331aSdan#                transaction left a very large non-hot journal file in the
1640d353331aSdan#                file-system), then SQLite has to be careful that there is
1641d353331aSdan#                not a journal-header left over from a previous transaction
1642d353331aSdan#                immediately following the journal content just written.
1643d353331aSdan#                If there is, and the process crashes so that the journal
1644d353331aSdan#                becomes a hot-journal and must be rolled back by another
1645d353331aSdan#                process, there is a danger that the other process may roll
1646d353331aSdan#                back the aborted transaction, then continue copying data
1647d353331aSdan#                from an older transaction from the remainder of the journal.
1648d353331aSdan#                See the syncJournal() function for details.
1649d353331aSdan#
1650d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1651d353331aSdan#                the mix to make the integrity-check more likely to catch
1652d353331aSdan#                errors.
1653d353331aSdan#
1654d353331aSdantestvfs tv -default 1
1655d353331aSdantv script xSyncCb
1656d353331aSdantv filter xSync
1657d353331aSdanproc xSyncCb {method filename args} {
1658d353331aSdan  set t [file tail $filename]
1659d353331aSdan  if {$t == "test.db"} faultsim_save
1660d353331aSdan  return SQLITE_OK
1661d353331aSdan}
1662d353331aSdanfaultsim_delete_and_reopen
1663d353331aSdandb func a_string a_string
1664e91a54e1Sdan
1665d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1666d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1667d353331aSdan# frequent journal headers.
1668d353331aSdan#
1669d353331aSdando_execsql_test pager1-13.1.1 {
1670d353331aSdan  PRAGMA page_size = 1024;
1671d353331aSdan  PRAGMA journal_mode = PERSIST;
1672d353331aSdan  PRAGMA cache_size = 10;
1673d353331aSdan  BEGIN;
1674d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1675d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1676d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1677d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1678d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1679d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1680d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1681d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1682d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1683d353331aSdan  COMMIT;
1684d353331aSdan  UPDATE t1 SET b = a_string(400);
1685d353331aSdan} {persist}
1686d353331aSdan
1687b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1688d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1689d353331aSdan# of these will write just enough content that one of the old headers created
1690d353331aSdan# by the transaction in the block above lies immediately after the content
1691d353331aSdan# journalled by the current transaction.
1692d353331aSdan#
1693d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1694d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1695d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1696d353331aSdan  } {}
1697d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1698d353331aSdan
1699d353331aSdan  # Try to access the snapshot of the file-system.
1700d353331aSdan  #
1701d353331aSdan  sqlite3 db2 sv_test.db
1702d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1703d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1704d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1705d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1706d353331aSdan    execsql { PRAGMA integrity_check } db2
1707d353331aSdan  } {ok}
1708d353331aSdan  db2 close
1709d353331aSdan}
1710b2f20bfcSshaneh}
1711d353331aSdan
1712b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1713d353331aSdan# Same test as above. But this time with an index on the table.
1714d353331aSdan#
1715d353331aSdando_execsql_test pager1-13.2.1 {
1716d353331aSdan  CREATE INDEX i1 ON t1(b);
1717d353331aSdan  UPDATE t1 SET b = a_string(400);
1718d353331aSdan} {}
1719d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1720d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1721d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1722d353331aSdan  } {}
1723d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1724d353331aSdan  sqlite3 db2 sv_test.db
1725d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1726d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1727d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1728d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1729d353331aSdan    execsql { PRAGMA integrity_check } db2
1730d353331aSdan  } {ok}
1731d353331aSdan  db2 close
1732d353331aSdan}
1733b2f20bfcSshaneh}
1734d353331aSdan
1735d353331aSdandb close
1736d353331aSdantv delete
1737d353331aSdan
1738d353331aSdan#-------------------------------------------------------------------------
1739d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1740d353331aSdan#
1741d353331aSdanfaultsim_delete_and_reopen
1742d353331aSdando_execsql_test pager1-14.1.1 {
1743d353331aSdan  PRAGMA journal_mode = OFF;
1744d353331aSdan  CREATE TABLE t1(a, b);
1745d353331aSdan  BEGIN;
1746d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1747d353331aSdan  COMMIT;
1748d353331aSdan  SELECT * FROM t1;
1749d353331aSdan} {off 1 2}
1750d353331aSdando_catchsql_test pager1-14.1.2 {
1751d353331aSdan  BEGIN;
1752d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1753d353331aSdan  ROLLBACK;
1754d353331aSdan} {0 {}}
1755d353331aSdando_execsql_test pager1-14.1.3 {
1756d353331aSdan  SELECT * FROM t1;
1757354bfe03Sdan} {1 2}
1758d353331aSdando_catchsql_test pager1-14.1.4 {
1759d353331aSdan  BEGIN;
1760d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1761d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1762f9c8ce3cSdrh} {1 {UNIQUE constraint failed: t1.rowid}}
1763d353331aSdando_execsql_test pager1-14.1.5 {
1764d353331aSdan  COMMIT;
1765d353331aSdan  SELECT * FROM t1;
1766354bfe03Sdan} {1 2 2 2}
1767d353331aSdan
1768c8ce3972Sdan#-------------------------------------------------------------------------
1769c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1770c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1771c8ce3972Sdan#
1772c8ce3972Sdanfaultsim_delete_and_reopen
1773c8ce3972Sdando_execsql_test pager1-15.0 {
1774c8ce3972Sdan  CREATE TABLE tx(y, z);
1775c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1776c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1777c8ce3972Sdan} {}
1778c8ce3972Sdandb close
1779c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1780c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1781c8ce3972Sdan  sqlite3 db test.db
1782c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1783c8ce3972Sdan    SELECT * FROM tx;
1784c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1785c8ce3972Sdan  db close
1786c8ce3972Sdan  tv delete
1787c8ce3972Sdan}
1788c8ce3972Sdan
1789c8ce3972Sdan#-------------------------------------------------------------------------
1790c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1791c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1792c8ce3972Sdan#
1793c8ce3972Sdantestvfs tv -default 1
1794c8ce3972Sdantv script xOpenCb
1795c8ce3972Sdantv filter xOpen
179633f5379cSdanproc xOpenCb {method filename args} {
1797c8ce3972Sdan  set ::file_len [string length $filename]
1798c8ce3972Sdan}
1799c8ce3972Sdansqlite3 db test.db
1800c8ce3972Sdandb close
1801c8ce3972Sdantv delete
1802c8ce3972Sdan
1803c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1804c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1805c8ce3972Sdan
1806c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1807c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1808c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1809c8ce3972Sdan  #
1810c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1811c8ce3972Sdan    set res {0 {}}
1812c8ce3972Sdan  } else {
1813c8ce3972Sdan    set res {1 {unable to open database file}}
1814c8ce3972Sdan  }
1815c8ce3972Sdan
1816c8ce3972Sdan  do_test pager1-16.1.$ii {
1817c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1818c8ce3972Sdan  } $res
1819c8ce3972Sdan
1820c8ce3972Sdan  catch {db close}
1821c8ce3972Sdan  tv delete
1822c8ce3972Sdan}
1823c8ce3972Sdan
1824c8ce3972Sdan
1825c8ce3972Sdan#-------------------------------------------------------------------------
1826c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1827c8ce3972Sdan# numbers:
1828c8ce3972Sdan#
1829c8ce3972Sdan#   + The locking page,
1830c8ce3972Sdan#   + Page 0,
1831c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1832c8ce3972Sdan#
1833f4ba1093Sdan# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
1834f4ba1093Sdan# that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
1835f4ba1093Sdan#
1836f4ba1093Sdanifcapable !direct_read {
1837c8ce3972Sdando_test pager1-18.1 {
1838c8ce3972Sdan  faultsim_delete_and_reopen
1839c8ce3972Sdan  db func a_string a_string
1840c8ce3972Sdan  execsql {
1841c8ce3972Sdan    PRAGMA page_size = 1024;
1842c8ce3972Sdan    CREATE TABLE t1(a, b);
1843c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1844c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1845c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1846c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1847c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1848c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1849c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1850c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1851c8ce3972Sdan  }
1852c8ce3972Sdan} {}
1853c8ce3972Sdando_test pager1-18.2 {
1854c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1855c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1856c8ce3972Sdan  execsql {
1857c8ce3972Sdan    PRAGMA writable_schema = 1;
1858c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1859c8ce3972Sdan  }
1860c8ce3972Sdan  sqlite3 db2 test.db
1861c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1862c8ce3972Sdan} {1 {database disk image is malformed}}
1863c8ce3972Sdandb2 close
1864a748fdccSdrhdo_test pager1-18.3.1 {
1865c8ce3972Sdan  execsql {
1866c8ce3972Sdan    CREATE TABLE t2(x);
1867c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1868c8ce3972Sdan  }
1869c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1870c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1871c8ce3972Sdan  sqlite3 db2 test.db
1872a748fdccSdrh  # even though x is malformed, because typeof() does
1873a748fdccSdrh  # not load the content of x, the error is not noticed.
1874a748fdccSdrh  catchsql { SELECT typeof(x) FROM t2 } db2
1875a748fdccSdrh} {0 text}
1876a748fdccSdrhdo_test pager1-18.3.2 {
1877a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1878a748fdccSdrh  # detected
1879a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1880a748fdccSdrh} {1 {database disk image is malformed}}
1881a748fdccSdrhdb2 close
1882a748fdccSdrhdo_test pager1-18.3.3 {
1883a748fdccSdrh  execsql {
1884a748fdccSdrh    DELETE FROM t2;
1885a748fdccSdrh    INSERT INTO t2 VALUES(randomblob(5000));
1886a748fdccSdrh  }
1887a748fdccSdrh  set pgno [expr ([file size test.db] / 1024)-2]
1888a748fdccSdrh  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1889a748fdccSdrh  sqlite3 db2 test.db
1890a748fdccSdrh  # even though x is malformed, because length() and typeof() do
1891a748fdccSdrh  # not load the content of x, the error is not noticed.
1892a748fdccSdrh  catchsql { SELECT length(x), typeof(x) FROM t2 } db2
1893a748fdccSdrh} {0 {5000 blob}}
1894a748fdccSdrhdo_test pager1-18.3.4 {
1895a748fdccSdrh  # in this case, the value of x is loaded and so the error is
1896a748fdccSdrh  # detected
1897a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1898c8ce3972Sdan} {1 {database disk image is malformed}}
1899c8ce3972Sdandb2 close
1900c8ce3972Sdando_test pager1-18.4 {
1901c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1902c8ce3972Sdan  sqlite3 db2 test.db
1903a748fdccSdrh  catchsql { SELECT length(x||'') FROM t2 } db2
1904c8ce3972Sdan} {1 {database disk image is malformed}}
1905c8ce3972Sdandb2 close
1906c8ce3972Sdando_test pager1-18.5 {
1907c8ce3972Sdan  sqlite3 db ""
1908c8ce3972Sdan  execsql {
1909c8ce3972Sdan    CREATE TABLE t1(a, b);
1910c8ce3972Sdan    CREATE TABLE t2(a, b);
1911c8ce3972Sdan    PRAGMA writable_schema = 1;
1912c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1913c8ce3972Sdan    PRAGMA writable_schema = 0;
1914c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1915c8ce3972Sdan  }
1916c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1917ba3cbf3dSdan} {1 {database disk image is malformed}}
1918c8ce3972Sdandb close
1919c8ce3972Sdan
1920ba3cbf3dSdando_test pager1-18.6 {
1921ba3cbf3dSdan  faultsim_delete_and_reopen
1922ba3cbf3dSdan  db func a_string a_string
1923ba3cbf3dSdan  execsql {
1924ba3cbf3dSdan    PRAGMA page_size = 1024;
1925ba3cbf3dSdan    CREATE TABLE t1(x);
1926ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1927ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1928ba3cbf3dSdan  }
1929ba3cbf3dSdan
1930ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1931ba3cbf3dSdan  db close
1932ba3cbf3dSdan
1933ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1934ba3cbf3dSdan  sqlite3 db test.db
1935ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1936ba3cbf3dSdan} {1 {database disk image is malformed}}
1937f4ba1093Sdan}
1938ba3cbf3dSdan
1939ba3cbf3dSdando_test pager1-19.1 {
1940ba3cbf3dSdan  sqlite3 db ""
1941ba3cbf3dSdan  db func a_string a_string
1942ba3cbf3dSdan  execsql {
1943ba3cbf3dSdan    PRAGMA page_size = 512;
1944ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1945ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1946ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1947ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1948ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1949ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1950ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1951ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1952ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1953ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1954ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1955ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1956ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1957ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1958ba3cbf3dSdan    );
1959ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1960ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1961ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1962ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1963ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1964ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1965ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1966ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1967ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1968ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1969ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1970ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1971ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1972ba3cbf3dSdan    );
1973ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
1974ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
1975ba3cbf3dSdan    VACUUM;
1976ba3cbf3dSdan  }
1977ba3cbf3dSdan} {}
1978ba3cbf3dSdan
19796b63ab47Sdan#-------------------------------------------------------------------------
19806b63ab47Sdan# Test a couple of special cases that come up while committing
19816b63ab47Sdan# transactions:
19826b63ab47Sdan#
19836b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
19846b63ab47Sdan#                  database has not been modified at all.
19856b63ab47Sdan#
19866b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
19876b63ab47Sdan#
19886b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
19896b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
19906b63ab47Sdan#                  disk before the commit.
19916b63ab47Sdan#
19926b63ab47Sdando_test pager1-20.1.1 {
19936b63ab47Sdan  catch {db close}
19946b63ab47Sdan  sqlite3 db :memory:
19956b63ab47Sdan  execsql {
19966b63ab47Sdan    CREATE TABLE one(two, three);
19976b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
19986b63ab47Sdan  }
19996b63ab47Sdan} {}
20006b63ab47Sdando_test pager1-20.1.2 {
20016b63ab47Sdan  execsql {
20026b63ab47Sdan    BEGIN EXCLUSIVE;
20036b63ab47Sdan    COMMIT;
20046b63ab47Sdan  }
20056b63ab47Sdan} {}
20066b63ab47Sdan
20076b63ab47Sdando_test pager1-20.2.1 {
20086b63ab47Sdan  faultsim_delete_and_reopen
20096b63ab47Sdan  execsql {
20106b63ab47Sdan    PRAGMA locking_mode = exclusive;
20116b63ab47Sdan    PRAGMA journal_mode = persist;
20126b63ab47Sdan    CREATE TABLE one(two, three);
20136b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
20146b63ab47Sdan  }
20156b63ab47Sdan} {exclusive persist}
20166b63ab47Sdando_test pager1-20.2.2 {
20176b63ab47Sdan  execsql {
20186b63ab47Sdan    BEGIN EXCLUSIVE;
20196b63ab47Sdan    COMMIT;
20206b63ab47Sdan  }
20216b63ab47Sdan} {}
20226b63ab47Sdan
20239091f775Sshanehifcapable wal {
20246b63ab47Sdan  do_test pager1-20.3.1 {
20256b63ab47Sdan    faultsim_delete_and_reopen
20266b63ab47Sdan    db func a_string a_string
20276b63ab47Sdan    execsql {
20286b63ab47Sdan      PRAGMA cache_size = 10;
20296b63ab47Sdan      PRAGMA journal_mode = wal;
20306b63ab47Sdan      BEGIN;
20316b63ab47Sdan        CREATE TABLE t1(x);
20326b63ab47Sdan        CREATE TABLE t2(y);
20336b63ab47Sdan        INSERT INTO t1 VALUES(a_string(800));
20346b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
20356b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
20366b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
20376b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
20386b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
20396b63ab47Sdan      COMMIT;
20406b63ab47Sdan    }
20416b63ab47Sdan  } {wal}
20426b63ab47Sdan  do_test pager1-20.3.2 {
20436b63ab47Sdan    execsql {
20446b63ab47Sdan      BEGIN;
20456b63ab47Sdan      INSERT INTO t2 VALUES('xxxx');
20466b63ab47Sdan    }
2047c396d4afSdan    recursive_select 32 t1
20486b63ab47Sdan    execsql COMMIT
20496b63ab47Sdan  } {}
20509091f775Sshaneh}
20516b63ab47Sdan
205289ccf448Sdan#-------------------------------------------------------------------------
205389ccf448Sdan# Test that a WAL database may not be opened if:
205489ccf448Sdan#
205589ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
205689ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
205789ccf448Sdan#
20589091f775Sshanehifcapable wal {
205989ccf448Sdan  do_test pager1-21.0 {
206089ccf448Sdan    faultsim_delete_and_reopen
206189ccf448Sdan    execsql {
206289ccf448Sdan      PRAGMA journal_mode = WAL;
206389ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
206489ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
206589ccf448Sdan    }
206689ccf448Sdan  } {wal}
206789ccf448Sdan  do_test pager1-21.1 {
206889ccf448Sdan    testvfs tv -noshm 1
206989ccf448Sdan    sqlite3 db2 test.db -vfs tv
207089ccf448Sdan    catchsql { SELECT * FROM ko } db2
207189ccf448Sdan  } {1 {unable to open database file}}
207289ccf448Sdan  db2 close
207389ccf448Sdan  tv delete
207489ccf448Sdan  do_test pager1-21.2 {
207589ccf448Sdan    testvfs tv -iversion 1
207689ccf448Sdan    sqlite3 db2 test.db -vfs tv
207789ccf448Sdan    catchsql { SELECT * FROM ko } db2
207889ccf448Sdan  } {1 {unable to open database file}}
207989ccf448Sdan  db2 close
208089ccf448Sdan  tv delete
20819091f775Sshaneh}
208289ccf448Sdan
208389ccf448Sdan#-------------------------------------------------------------------------
208489ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
208589ccf448Sdan#
208689ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
208789ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
208889ccf448Sdan#
20895209132aSdanifcapable wal {
209089ccf448Sdan  do_test pager1-22.1.1 {
209189ccf448Sdan    faultsim_delete_and_reopen
209289ccf448Sdan    execsql {
209389ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
209489ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
209589ccf448Sdan    }
209689ccf448Sdan    execsql { PRAGMA wal_checkpoint }
2097bdd9af0fSdan  } {0 -1 -1}
209889ccf448Sdan  do_test pager1-22.2.1 {
209989ccf448Sdan    testvfs tv -default 1
210089ccf448Sdan    tv filter xSync
210189ccf448Sdan    tv script xSyncCb
210289ccf448Sdan    proc xSyncCb {args} {incr ::synccount}
210389ccf448Sdan    set ::synccount 0
210489ccf448Sdan    sqlite3 db test.db
210589ccf448Sdan    execsql {
210689ccf448Sdan      PRAGMA synchronous = off;
210789ccf448Sdan      PRAGMA journal_mode = WAL;
210889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
210989ccf448Sdan    }
211089ccf448Sdan    execsql { PRAGMA wal_checkpoint }
211189ccf448Sdan    set synccount
211289ccf448Sdan  } {0}
211389ccf448Sdan  db close
211489ccf448Sdan  tv delete
21155209132aSdan}
211689ccf448Sdan
211789ccf448Sdan#-------------------------------------------------------------------------
211889ccf448Sdan# Tests for changing journal mode.
211989ccf448Sdan#
212089ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
212189ccf448Sdan#                  the journal file is deleted.
212289ccf448Sdan#
212389ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
212489ccf448Sdan#                  on the database file.
212589ccf448Sdan#
212689ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
212789ccf448Sdan#                  on the database file.
212889ccf448Sdan#
212989ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
213089ccf448Sdan#
213189ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
213289ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
213389ccf448Sdan#
2134d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
2135d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
2136d0b0d4dcSdan#                  locking_mode=exclusive).
2137d0b0d4dcSdan#
213889ccf448Sdando_test pager1-23.1.1 {
213989ccf448Sdan  faultsim_delete_and_reopen
214089ccf448Sdan  execsql {
214189ccf448Sdan    PRAGMA journal_mode = PERSIST;
214289ccf448Sdan    CREATE TABLE t1(a, b);
214389ccf448Sdan  }
214489ccf448Sdan  file exists test.db-journal
214589ccf448Sdan} {1}
214689ccf448Sdando_test pager1-23.1.2 {
214789ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
214889ccf448Sdan  file exists test.db-journal
214989ccf448Sdan} {0}
215089ccf448Sdan
215189ccf448Sdando_test pager1-23.2.1 {
215289ccf448Sdan  execsql {
215389ccf448Sdan    PRAGMA journal_mode = PERSIST;
215489ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
215589ccf448Sdan  }
215689ccf448Sdan  db eval { SELECT * FROM t1 } {
215789ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
215889ccf448Sdan  }
215989ccf448Sdan  execsql { PRAGMA journal_mode }
216089ccf448Sdan} {delete}
216189ccf448Sdando_test pager1-23.2.2 {
216289ccf448Sdan  file exists test.db-journal
216389ccf448Sdan} {0}
216489ccf448Sdan
216589ccf448Sdando_test pager1-23.3.1 {
216689ccf448Sdan  execsql {
216789ccf448Sdan    PRAGMA journal_mode = PERSIST;
216889ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
216989ccf448Sdan    BEGIN IMMEDIATE;
217089ccf448Sdan  }
217189ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
217289ccf448Sdan  execsql { PRAGMA journal_mode }
217389ccf448Sdan} {delete}
217489ccf448Sdando_test pager1-23.3.2 {
217589ccf448Sdan  file exists test.db-journal
217689ccf448Sdan} {0}
217789ccf448Sdando_test pager1-23.3.3 {
217889ccf448Sdan  execsql COMMIT
217989ccf448Sdan} {}
218089ccf448Sdan
218189ccf448Sdando_test pager1-23.4.1 {
218289ccf448Sdan  execsql {
218389ccf448Sdan    PRAGMA journal_mode = PERSIST;
218489ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
218589ccf448Sdan    BEGIN EXCLUSIVE;
218689ccf448Sdan  }
218789ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
218889ccf448Sdan  execsql { PRAGMA journal_mode }
218989ccf448Sdan} {delete}
219089ccf448Sdando_test pager1-23.4.2 {
219189ccf448Sdan  file exists test.db-journal
219289ccf448Sdan} {0}
219389ccf448Sdando_test pager1-23.4.3 {
219489ccf448Sdan  execsql COMMIT
219589ccf448Sdan} {}
219689ccf448Sdan
219789ccf448Sdando_test pager1-23.5.1 {
219889ccf448Sdan  faultsim_delete_and_reopen
219989ccf448Sdan  sqlite3 db :memory:
220089ccf448Sdan} {}
220189ccf448Sdanforeach {tn mode possible} {
220289ccf448Sdan  2  off      1
220389ccf448Sdan  3  memory   1
220489ccf448Sdan  4  persist  0
220589ccf448Sdan  5  delete   0
220689ccf448Sdan  6  wal      0
220789ccf448Sdan  7  truncate 0
220889ccf448Sdan} {
220989ccf448Sdan  do_test pager1-23.5.$tn.1 {
221089ccf448Sdan    execsql "PRAGMA journal_mode = off"
221189ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
221289ccf448Sdan  } [if $possible {list $mode} {list off}]
221389ccf448Sdan  do_test pager1-23.5.$tn.2 {
221489ccf448Sdan    execsql "PRAGMA journal_mode = memory"
221589ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
221689ccf448Sdan  } [if $possible {list $mode} {list memory}]
221789ccf448Sdan}
2218d0b0d4dcSdando_test pager1-23.6.1 {
221989ccf448Sdan  execsql {PRAGMA locking_mode = normal}
222089ccf448Sdan} {exclusive}
2221d0b0d4dcSdando_test pager1-23.6.2 {
222289ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
222389ccf448Sdan} {exclusive}
2224d0b0d4dcSdando_test pager1-23.6.3 {
222589ccf448Sdan  execsql {PRAGMA locking_mode}
222689ccf448Sdan} {exclusive}
2227d0b0d4dcSdando_test pager1-23.6.4 {
222889ccf448Sdan  execsql {PRAGMA main.locking_mode}
222989ccf448Sdan} {exclusive}
22306b63ab47Sdan
2231d0b0d4dcSdan#-------------------------------------------------------------------------
2232d0b0d4dcSdan#
2233d0b0d4dcSdando_test pager1-24.1.1 {
2234d0b0d4dcSdan  faultsim_delete_and_reopen
2235d0b0d4dcSdan  db func a_string a_string
2236d0b0d4dcSdan  execsql {
2237d0b0d4dcSdan    PRAGMA cache_size = 10;
2238d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2239d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2240d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2241d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2242d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2243d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2244d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2245d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2246d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2247d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2248d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2249d0b0d4dcSdan  }
2250d0b0d4dcSdan} {}
2251d0b0d4dcSdando_test pager1-24.1.2 {
2252d0b0d4dcSdan  execsql {
2253d0b0d4dcSdan    BEGIN;
2254d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2255d0b0d4dcSdan  }
2256c396d4afSdan  recursive_select 64 x2
2257d0b0d4dcSdan} {}
2258d0b0d4dcSdando_test pager1-24.1.3 {
2259d0b0d4dcSdan  execsql {
2260d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2261d0b0d4dcSdan    COMMIT;
2262d0b0d4dcSdan    PRAGMA integrity_check;
2263d0b0d4dcSdan    SELECT count(*) FROM x1;
2264d0b0d4dcSdan  }
2265d0b0d4dcSdan} {ok 33}
2266d0b0d4dcSdan
2267d0b0d4dcSdando_test pager1-24.1.4 {
2268d0b0d4dcSdan  execsql {
2269d0b0d4dcSdan    DELETE FROM x1;
2270d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2271d0b0d4dcSdan    BEGIN;
2272d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2273d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2274d0b0d4dcSdan  }
2275c396d4afSdan  recursive_select 64 x2 {db eval COMMIT}
2276d0b0d4dcSdan  execsql {
2277d0b0d4dcSdan    PRAGMA integrity_check;
2278d0b0d4dcSdan    SELECT count(*) FROM x1;
2279d0b0d4dcSdan  }
2280d0b0d4dcSdan} {ok 33}
2281d0b0d4dcSdan
2282d0b0d4dcSdando_test pager1-24.1.5 {
2283d0b0d4dcSdan  execsql {
2284d0b0d4dcSdan    DELETE FROM x1;
2285d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2286d0b0d4dcSdan  }
2287c396d4afSdan  recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
2288d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2289d0b0d4dcSdan} {}
2290d0b0d4dcSdan
2291d0b0d4dcSdan#-------------------------------------------------------------------------
2292d0b0d4dcSdan#
2293d0b0d4dcSdando_test pager1-25-1 {
2294d0b0d4dcSdan  faultsim_delete_and_reopen
2295d0b0d4dcSdan  execsql {
2296d0b0d4dcSdan    BEGIN;
2297d0b0d4dcSdan      SAVEPOINT abc;
2298d0b0d4dcSdan        CREATE TABLE t1(a, b);
2299d0b0d4dcSdan      ROLLBACK TO abc;
2300d0b0d4dcSdan    COMMIT;
2301d0b0d4dcSdan  }
2302d0b0d4dcSdan  db close
2303d0b0d4dcSdan} {}
2304d0b0d4dcSdando_test pager1-25-2 {
2305d0b0d4dcSdan  faultsim_delete_and_reopen
2306d0b0d4dcSdan  execsql {
2307d0b0d4dcSdan    SAVEPOINT abc;
2308d0b0d4dcSdan      CREATE TABLE t1(a, b);
2309d0b0d4dcSdan    ROLLBACK TO abc;
2310d0b0d4dcSdan    COMMIT;
2311d0b0d4dcSdan  }
2312d0b0d4dcSdan  db close
2313d0b0d4dcSdan} {}
23146b63ab47Sdan
2315c396d4afSdan#-------------------------------------------------------------------------
2316c396d4afSdan# Sector-size tests.
2317c396d4afSdan#
2318c396d4afSdando_test pager1-26.1 {
2319c396d4afSdan  testvfs tv -default 1
2320c396d4afSdan  tv sectorsize 4096
2321c396d4afSdan  faultsim_delete_and_reopen
2322c396d4afSdan  db func a_string a_string
2323c396d4afSdan  execsql {
2324c396d4afSdan    PRAGMA page_size = 512;
2325c396d4afSdan    CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
2326c396d4afSdan    BEGIN;
2327c396d4afSdan      INSERT INTO tbl VALUES(a_string(25), a_string(600));
2328c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2329c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2330c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2331c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2332c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2333c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2334c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2335c396d4afSdan    COMMIT;
2336c396d4afSdan  }
2337c396d4afSdan} {}
2338c396d4afSdando_execsql_test pager1-26.1 {
2339c396d4afSdan  UPDATE tbl SET b = a_string(550);
2340c396d4afSdan} {}
2341c396d4afSdandb close
2342c396d4afSdantv delete
2343c396d4afSdan
2344c396d4afSdan#-------------------------------------------------------------------------
234522b328b2Sdan#
2346c396d4afSdando_test pager1.27.1 {
2347c396d4afSdan  faultsim_delete_and_reopen
2348c396d4afSdan  sqlite3_pager_refcounts db
2349c396d4afSdan  execsql {
2350c396d4afSdan    BEGIN;
2351c396d4afSdan      CREATE TABLE t1(a, b);
2352c396d4afSdan  }
2353c396d4afSdan  sqlite3_pager_refcounts db
2354c396d4afSdan  execsql COMMIT
2355c396d4afSdan} {}
2356c396d4afSdan
235722b328b2Sdan#-------------------------------------------------------------------------
235822b328b2Sdan# Test that attempting to open a write-transaction with
235922b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on
236022b328b2Sdan# the same database.
236122b328b2Sdan#
236222b328b2Sdancatch { db close }
23639091f775Sshanehifcapable wal {
236422b328b2Sdan  do_multiclient_test tn {
236522b328b2Sdan    do_test pager1-28.$tn.1 {
236622b328b2Sdan      sql1 {
236722b328b2Sdan        PRAGMA journal_mode = WAL;
236822b328b2Sdan        CREATE TABLE t1(a, b);
236922b328b2Sdan        INSERT INTO t1 VALUES('a', 'b');
237022b328b2Sdan      }
237122b328b2Sdan    } {wal}
237222b328b2Sdan    do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
237322b328b2Sdan
237422b328b2Sdan    do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
237522b328b2Sdan    do_test pager1-28.$tn.4 {
237622b328b2Sdan      csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
237722b328b2Sdan    } {1 {database is locked}}
237822b328b2Sdan    code2 { db2 close ; sqlite3 db2 test.db }
237922b328b2Sdan    do_test pager1-28.$tn.4 {
238022b328b2Sdan      sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
238122b328b2Sdan    } {}
238222b328b2Sdan  }
23839091f775Sshaneh}
23845653e4daSdan
23855653e4daSdan#-------------------------------------------------------------------------
23865653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager
23875653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a
23885653e4daSdan# RESERVED lock on the database file, this step is skipped.
23895653e4daSdan#
23905653e4daSdando_multiclient_test tn {
23915653e4daSdan  do_test pager1-28.$tn.1 {
23925653e4daSdan    sql1 {
23935653e4daSdan      PRAGMA journal_mode = PERSIST;
23945653e4daSdan      CREATE TABLE t1(a, b);
23955653e4daSdan      INSERT INTO t1 VALUES('a', 'b');
23965653e4daSdan    }
23975653e4daSdan  } {persist}
23985653e4daSdan  do_test pager1-28.$tn.2 { file exists test.db-journal } 1
23995653e4daSdan  do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
24005653e4daSdan  do_test pager1-28.$tn.4 { file exists test.db-journal } 0
24015653e4daSdan
24025653e4daSdan  do_test pager1-28.$tn.5 {
24035653e4daSdan    sql1 {
24045653e4daSdan      PRAGMA journal_mode = PERSIST;
24055653e4daSdan      INSERT INTO t1 VALUES('c', 'd');
24065653e4daSdan    }
24075653e4daSdan  } {persist}
24085653e4daSdan  do_test pager1-28.$tn.6 { file exists test.db-journal } 1
24095653e4daSdan  do_test pager1-28.$tn.7 {
24105653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
24115653e4daSdan  } {}
24125653e4daSdan  do_test pager1-28.$tn.8  { file exists test.db-journal } 1
24135653e4daSdan  do_test pager1-28.$tn.9  { sql1 { PRAGMA journal_mode = DELETE } } delete
24145653e4daSdan  do_test pager1-28.$tn.10 { file exists test.db-journal } 1
24155653e4daSdan
24165653e4daSdan  do_test pager1-28.$tn.11 { sql2 COMMIT } {}
24175653e4daSdan  do_test pager1-28.$tn.12 { file exists test.db-journal } 0
24185653e4daSdan
24195653e4daSdan  do_test pager1-28-$tn.13 {
24205653e4daSdan    code1 { set channel [db incrblob -readonly t1 a 2] }
24215653e4daSdan    sql1 {
24225653e4daSdan      PRAGMA journal_mode = PERSIST;
24235653e4daSdan      INSERT INTO t1 VALUES('g', 'h');
24245653e4daSdan    }
24255653e4daSdan  } {persist}
24265653e4daSdan  do_test pager1-28.$tn.14 { file exists test.db-journal } 1
24275653e4daSdan  do_test pager1-28.$tn.15 {
24285653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
24295653e4daSdan  } {}
24305653e4daSdan  do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
24315653e4daSdan  do_test pager1-28.$tn.17 { file exists test.db-journal } 1
24325653e4daSdan
24335653e4daSdan  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
24345653e4daSdan  do_test pager1-28-$tn.18 { code1 { read $channel } } c
24355653e4daSdan  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
24365653e4daSdan  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
24375653e4daSdan}
24385653e4daSdan
24391879b088Sdando_test pager1-29.1 {
24401879b088Sdan  faultsim_delete_and_reopen
24411879b088Sdan  execsql {
24421879b088Sdan    PRAGMA page_size = 1024;
24431879b088Sdan    PRAGMA auto_vacuum = full;
24441879b088Sdan    PRAGMA locking_mode=exclusive;
24451879b088Sdan    CREATE TABLE t1(a, b);
24461879b088Sdan    INSERT INTO t1 VALUES(1, 2);
24471879b088Sdan  }
24481879b088Sdan  file size test.db
24491879b088Sdan} [expr 1024*3]
24501879b088Sdando_test pager1-29.2 {
24511879b088Sdan  execsql {
24521879b088Sdan    PRAGMA page_size = 4096;
24531879b088Sdan    VACUUM;
24541879b088Sdan  }
24551879b088Sdan  file size test.db
24561879b088Sdan} [expr 4096*3]
24571879b088Sdan
2458e08c2066Sdan#-------------------------------------------------------------------------
2459e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in
2460e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system
2461e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while
2462e08c2066Sdan# doing this is not released.
2463e08c2066Sdan#
2464e08c2066Sdando_test pager1-30.1 {
2465e08c2066Sdan  db close
2466fda06befSmistachkin  delete_file test.db
2467fda06befSmistachkin  delete_file test.db-journal
2468e08c2066Sdan  set fd [open test.db-journal w]
2469e08c2066Sdan  seek $fd [expr 512+1032*2]
2470e08c2066Sdan  puts -nonewline $fd x
2471e08c2066Sdan  close $fd
2472e08c2066Sdan
2473e08c2066Sdan  sqlite3 db test.db
2474e08c2066Sdan  execsql {
2475e08c2066Sdan    PRAGMA locking_mode=EXCLUSIVE;
2476e08c2066Sdan    SELECT count(*) FROM sqlite_master;
2477e08c2066Sdan    PRAGMA lock_status;
2478e08c2066Sdan  }
2479e08c2066Sdan} {exclusive 0 main reserved temp closed}
2480e08c2066Sdan
2481e08c2066Sdan#-------------------------------------------------------------------------
2482e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal
2483e08c2066Sdan# file can still be rolled back. This is required for backward compatibility -
2484e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero.
2485e08c2066Sdan#
248633f5379cSdanif {$tcl_platform(platform)=="unix"} {
2487e08c2066Sdando_test pager1-31.1 {
2488e08c2066Sdan  faultsim_delete_and_reopen
2489e08c2066Sdan  execsql {
2490e08c2066Sdan    PRAGMA cache_size = 10;
2491e08c2066Sdan    PRAGMA page_size = 1024;
2492e08c2066Sdan    CREATE TABLE t1(x, y, UNIQUE(x, y));
2493e08c2066Sdan    INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
2494e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2495e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2496e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2497e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2498e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2499e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2500e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2501e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2502e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2503e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2504e08c2066Sdan    BEGIN;
2505e08c2066Sdan      UPDATE t1 SET y = randomblob(1499);
2506e08c2066Sdan  }
2507fda06befSmistachkin  copy_file test.db test.db2
2508fda06befSmistachkin  copy_file test.db-journal test.db2-journal
2509e08c2066Sdan
2510e08c2066Sdan  hexio_write test.db2-journal 24 00000000
2511e08c2066Sdan  sqlite3 db2 test.db2
2512e08c2066Sdan  execsql { PRAGMA integrity_check } db2
2513e08c2066Sdan} {ok}
251433f5379cSdan}
2515e08c2066Sdan
251631e80976Sdrh#-------------------------------------------------------------------------
251731e80976Sdrh# Test that a database file can be "pre-hinted" to a certain size and that
251831e80976Sdrh# subsequent spilling of the pager cache does not result in the database
251931e80976Sdrh# file being shrunk.
252031e80976Sdrh#
252131e80976Sdrhcatch {db close}
252231e80976Sdrhforcedelete test.db
252331e80976Sdrh
252431e80976Sdrhdo_test pager1-32.1 {
252531e80976Sdrh  sqlite3 db test.db
252631e80976Sdrh  execsql {
252731e80976Sdrh    CREATE TABLE t1(x, y);
252831e80976Sdrh  }
252931e80976Sdrh  db close
253031e80976Sdrh  sqlite3 db test.db
253131e80976Sdrh  execsql {
253231e80976Sdrh    BEGIN;
253331e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
253431e80976Sdrh  }
25352f7820d8Sdrh  file_control_chunksize_test db main 1024
253631e80976Sdrh  file_control_sizehint_test db main 20971520; # 20MB
253731e80976Sdrh  execsql {
253831e80976Sdrh    PRAGMA cache_size = 10;
253931e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
254031e80976Sdrh    INSERT INTO t1 VALUES(2, randomblob(10000));
254131e80976Sdrh    INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
254231e80976Sdrh    INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
254331e80976Sdrh    INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
254431e80976Sdrh    INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
254531e80976Sdrh    SELECT count(*) FROM t1;
254631e80976Sdrh    COMMIT;
254731e80976Sdrh  }
254831e80976Sdrh  db close
254931e80976Sdrh  file size test.db
255031e80976Sdrh} {20971520}
255131e80976Sdrh
255231e80976Sdrh# Cleanup 20MB file left by the previous test.
255331e80976Sdrhforcedelete test.db
25545653e4daSdan
25559fc5b4a5Sdan#-------------------------------------------------------------------------
25569fc5b4a5Sdan# Test that if a transaction is committed in journal_mode=DELETE mode,
25579fc5b4a5Sdan# and the call to unlink() returns an ENOENT error, the COMMIT does not
25589fc5b4a5Sdan# succeed.
25599fc5b4a5Sdan#
25609fc5b4a5Sdanif {$::tcl_platform(platform)=="unix"} {
25619fc5b4a5Sdan  do_test pager1-33.1 {
25629fc5b4a5Sdan    sqlite3 db test.db
25639fc5b4a5Sdan    execsql {
25649fc5b4a5Sdan      CREATE TABLE t1(x);
25659fc5b4a5Sdan      INSERT INTO t1 VALUES('one');
25669fc5b4a5Sdan      INSERT INTO t1 VALUES('two');
25679fc5b4a5Sdan      BEGIN;
25689fc5b4a5Sdan        INSERT INTO t1 VALUES('three');
25699fc5b4a5Sdan        INSERT INTO t1 VALUES('four');
25709fc5b4a5Sdan    }
25719fc5b4a5Sdan    forcedelete bak-journal
25729fc5b4a5Sdan    file rename test.db-journal bak-journal
25739fc5b4a5Sdan
25749fc5b4a5Sdan    catchsql COMMIT
25759fc5b4a5Sdan  } {1 {disk I/O error}}
25769fc5b4a5Sdan
25779fc5b4a5Sdan  do_test pager1-33.2 {
25789fc5b4a5Sdan    file rename bak-journal test.db-journal
25799fc5b4a5Sdan    execsql { SELECT * FROM t1 }
25809fc5b4a5Sdan  } {one two}
25819fc5b4a5Sdan}
25829fc5b4a5Sdan
2583d7a558a9Sdan#-------------------------------------------------------------------------
2584d7a558a9Sdan# Test that appending pages to the database file then moving those pages
2585d7a558a9Sdan# to the free-list before the transaction is committed does not cause
2586d7a558a9Sdan# an error.
2587d7a558a9Sdan#
2588d7a558a9Sdanforeach {tn pragma strsize} {
25899b4c59faSdrh  1 { PRAGMA mmap_size = 0 } 2400
2590d7a558a9Sdan  2 { }                       2400
25919b4c59faSdrh  3 { PRAGMA mmap_size = 0 } 4400
2592d7a558a9Sdan  4 { }                       4400
2593d7a558a9Sdan} {
2594d7a558a9Sdan  reset_db
2595d7a558a9Sdan  db func a_string a_string
2596d7a558a9Sdan  db eval $pragma
2597d7a558a9Sdan  do_execsql_test 34.$tn.1 {
2598d7a558a9Sdan    CREATE TABLE t1(a, b);
2599d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2600d7a558a9Sdan  }
2601d7a558a9Sdan  do_execsql_test 34.$tn.2 {
2602d7a558a9Sdan    BEGIN;
2603d7a558a9Sdan    INSERT INTO t1 VALUES(2, a_string($strsize));
2604d7a558a9Sdan    DELETE FROM t1 WHERE oid=2;
2605d7a558a9Sdan    COMMIT;
2606d7a558a9Sdan    PRAGMA integrity_check;
2607d7a558a9Sdan  } {ok}
2608d7a558a9Sdan}
2609d7a558a9Sdan
2610d7a558a9Sdan#-------------------------------------------------------------------------
2611d7a558a9Sdan#
2612d7a558a9Sdanreset_db
2613d7a558a9Sdando_test 35 {
2614d7a558a9Sdan  sqlite3 db test.db
2615d7a558a9Sdan
2616d7a558a9Sdan  execsql {
2617d7a558a9Sdan    CREATE TABLE t1(x, y);
2618d7a558a9Sdan    PRAGMA journal_mode = WAL;
2619d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2620d7a558a9Sdan  }
2621d7a558a9Sdan
2622d7a558a9Sdan  execsql {
2623d7a558a9Sdan    BEGIN;
2624d7a558a9Sdan      CREATE TABLE t2(a, b);
2625d7a558a9Sdan  }
2626d7a558a9Sdan
2627d7a558a9Sdan  hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192]
2628d7a558a9Sdan  catchsql ROLLBACK
2629d7a558a9Sdan} {0 {}}
2630d7a558a9Sdan
2631d7a558a9Sdando_multiclient_test tn {
2632d7a558a9Sdan  sql1 {
2633d7a558a9Sdan    PRAGMA auto_vacuum = 0;
2634d7a558a9Sdan    CREATE TABLE t1(x, y);
2635d7a558a9Sdan    INSERT INTO t1 VALUES(1, 2);
2636d7a558a9Sdan  }
2637d7a558a9Sdan
2638d7a558a9Sdan  do_test 36.$tn.1 {
2639d7a558a9Sdan    sql2 { PRAGMA max_page_count = 2 }
2640d7a558a9Sdan    list [catch { sql2 { CREATE TABLE t2(x) } } msg] $msg
2641d7a558a9Sdan  } {1 {database or disk is full}}
2642d7a558a9Sdan
2643d7a558a9Sdan  sql1 { PRAGMA checkpoint_fullfsync = 1 }
2644d7a558a9Sdan  sql1 { CREATE TABLE t2(x) }
2645d7a558a9Sdan
2646d7a558a9Sdan  do_test 36.$tn.2 {
2647d7a558a9Sdan    sql2 { INSERT INTO t2 VALUES('xyz') }
2648d7a558a9Sdan    list [catch { sql2 { CREATE TABLE t3(x) } } msg] $msg
2649d7a558a9Sdan  } {1 {database or disk is full}}
2650d7a558a9Sdan}
2651d7a558a9Sdan
2652d7a558a9Sdanforcedelete test1 test2
2653d7a558a9Sdanforeach {tn uri} {
2654d7a558a9Sdan  1   {file:?mode=memory&cache=shared}
2655d7a558a9Sdan  2   {file:one?mode=memory&cache=shared}
2656d7a558a9Sdan  3   {file:test1?cache=shared}
2657d7a558a9Sdan  4   {file:test2?another=parameter&yet=anotherone}
2658d7a558a9Sdan} {
2659d7a558a9Sdan  do_test 37.$tn {
2660d7a558a9Sdan    catch { db close }
2661d7a558a9Sdan    sqlite3_shutdown
2662d7a558a9Sdan    sqlite3_config_uri 1
2663d7a558a9Sdan    sqlite3 db $uri
2664abd6d84aSdan
2665d7a558a9Sdan    db eval {
2666d7a558a9Sdan      CREATE TABLE t1(x);
2667d7a558a9Sdan      INSERT INTO t1 VALUES(1);
2668d7a558a9Sdan      SELECT * FROM t1;
2669d7a558a9Sdan    }
2670d7a558a9Sdan  } {1}
2671abd6d84aSdan
2672abd6d84aSdan  do_execsql_test 37.$tn.2 {
2673abd6d84aSdan    VACUUM;
2674abd6d84aSdan    SELECT * FROM t1;
2675abd6d84aSdan  } {1}
2676abd6d84aSdan
2677d7a558a9Sdan  db close
2678d7a558a9Sdan  sqlite3_shutdown
2679d7a558a9Sdan  sqlite3_config_uri 0
2680d7a558a9Sdan}
2681d7a558a9Sdan
2682d7a558a9Sdando_test 38.1 {
2683d7a558a9Sdan  catch { db close }
2684d7a558a9Sdan  forcedelete test.db
2685d7a558a9Sdan  set fd [open test.db w]
2686d7a558a9Sdan  puts $fd "hello world"
2687d7a558a9Sdan  close $fd
2688d7a558a9Sdan  sqlite3 db test.db
2689d7a558a9Sdan  catchsql { CREATE TABLE t1(x) }
2690d7a558a9Sdan} {1 {file is encrypted or is not a database}}
2691d7a558a9Sdando_test 38.2 {
2692d7a558a9Sdan  catch { db close }
2693d7a558a9Sdan  forcedelete test.db
2694d7a558a9Sdan} {}
2695d7a558a9Sdan
2696d7a558a9Sdando_test 39.1 {
2697d7a558a9Sdan  sqlite3 db test.db
2698d7a558a9Sdan  execsql {
2699d7a558a9Sdan    PRAGMA auto_vacuum = 1;
2700d7a558a9Sdan    CREATE TABLE t1(x);
2701d7a558a9Sdan    INSERT INTO t1 VALUES('xxx');
2702d7a558a9Sdan    INSERT INTO t1 VALUES('two');
2703d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2704d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2705d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2706d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(400));
2707d7a558a9Sdan    BEGIN;
2708d7a558a9Sdan    UPDATE t1 SET x = 'one' WHERE rowid=1;
2709d7a558a9Sdan  }
2710d7a558a9Sdan  set ::stmt [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
2711d7a558a9Sdan  sqlite3_step $::stmt
2712d7a558a9Sdan  sqlite3_column_text $::stmt 0
2713d7a558a9Sdan} {one}
2714d7a558a9Sdando_test 39.2 {
2715d7a558a9Sdan  execsql { CREATE TABLE t2(x) }
2716d7a558a9Sdan  sqlite3_step $::stmt
2717d7a558a9Sdan  sqlite3_column_text $::stmt 0
2718d7a558a9Sdan} {two}
2719d7a558a9Sdando_test 39.3 {
2720d7a558a9Sdan  sqlite3_finalize $::stmt
2721d7a558a9Sdan  execsql COMMIT
2722d7a558a9Sdan} {}
2723d7a558a9Sdan
2724d7a558a9Sdando_execsql_test 39.4 {
2725d7a558a9Sdan  PRAGMA auto_vacuum = 2;
2726d7a558a9Sdan  CREATE TABLE t3(x);
2727d7a558a9Sdan  CREATE TABLE t4(x);
2728d7a558a9Sdan
2729d7a558a9Sdan  DROP TABLE t2;
2730d7a558a9Sdan  DROP TABLE t3;
2731d7a558a9Sdan  DROP TABLE t4;
2732d7a558a9Sdan}
2733d7a558a9Sdando_test 39.5 {
2734d7a558a9Sdan  db close
2735d7a558a9Sdan  sqlite3 db test.db
2736d7a558a9Sdan  execsql {
2737d7a558a9Sdan    PRAGMA cache_size = 1;
2738d7a558a9Sdan    PRAGMA incremental_vacuum;
2739d7a558a9Sdan    PRAGMA integrity_check;
2740d7a558a9Sdan  }
2741d7a558a9Sdan} {ok}
2742d7a558a9Sdan
2743d7a558a9Sdando_test 40.1 {
2744d7a558a9Sdan  reset_db
2745d7a558a9Sdan  execsql {
2746d7a558a9Sdan    PRAGMA auto_vacuum = 1;
2747d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
2748d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2749d7a558a9Sdan    PRAGMA page_count;
2750d7a558a9Sdan  }
2751d7a558a9Sdan} {6}
2752d7a558a9Sdando_test 40.2 {
2753d7a558a9Sdan  execsql {
2754d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2755d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2756d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(1200));
2757d7a558a9Sdan  }
2758d7a558a9Sdan} {}
2759d7a558a9Sdando_test 40.3 {
2760d7a558a9Sdan  db close
2761d7a558a9Sdan  sqlite3 db test.db
2762d7a558a9Sdan  execsql {
2763d7a558a9Sdan    PRAGMA cache_size = 1;
2764d7a558a9Sdan    CREATE TABLE t2(x);
2765d7a558a9Sdan    PRAGMA integrity_check;
2766d7a558a9Sdan  }
2767d7a558a9Sdan} {ok}
2768d7a558a9Sdan
2769d7a558a9Sdando_test 41.1 {
2770d7a558a9Sdan  reset_db
2771d7a558a9Sdan  execsql {
2772d7a558a9Sdan    CREATE TABLE t1(x PRIMARY KEY);
2773d7a558a9Sdan    INSERT INTO t1 VALUES(randomblob(200));
2774d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2775d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2776d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2777d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2778d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2779d7a558a9Sdan    INSERT INTO t1 SELECT randomblob(200) FROM t1;
2780d7a558a9Sdan  }
2781d7a558a9Sdan} {}
2782d7a558a9Sdando_test 41.2 {
2783d7a558a9Sdan  testvfs tv -default 1
2784d7a558a9Sdan  tv sectorsize 16384;
2785d7a558a9Sdan  tv devchar [list]
2786d7a558a9Sdan  db close
2787d7a558a9Sdan  sqlite3 db test.db
2788d7a558a9Sdan  execsql {
2789d7a558a9Sdan    PRAGMA cache_size = 1;
2790d7a558a9Sdan    DELETE FROM t1 WHERE rowid%4;
2791d7a558a9Sdan    PRAGMA integrity_check;
2792d7a558a9Sdan  }
2793d7a558a9Sdan} {ok}
2794abd6d84aSdandb close
2795abd6d84aSdantv delete
2796d7a558a9Sdan
2797abd6d84aSdanset pending_prev [sqlite3_test_control_pending_byte 0x1000000]
2798abd6d84aSdando_test 42.1 {
2799abd6d84aSdan  reset_db
2800abd6d84aSdan  execsql {
2801abd6d84aSdan    CREATE TABLE t1(x, y);
2802abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
2803abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2804abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2805abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2806abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2807abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2808abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2809abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2810abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2811abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2812abd6d84aSdan  }
2813abd6d84aSdan  db close
2814abd6d84aSdan  sqlite3_test_control_pending_byte 0x0010000
2815abd6d84aSdan  sqlite3 db test.db
28169b4c59faSdrh  db eval { PRAGMA mmap_size = 0 }
2817abd6d84aSdan  catchsql { SELECT sum(length(y)) FROM t1 }
2818abd6d84aSdan} {1 {database disk image is malformed}}
2819abd6d84aSdando_test 42.2 {
2820abd6d84aSdan  reset_db
2821abd6d84aSdan  execsql {
2822abd6d84aSdan    CREATE TABLE t1(x, y);
2823abd6d84aSdan    INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
2824abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2825abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2826abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2827abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2828abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2829abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2830abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2831abd6d84aSdan    INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
2832abd6d84aSdan  }
2833abd6d84aSdan  db close
2834abd6d84aSdan
2835abd6d84aSdan  testvfs tv -default 1
2836abd6d84aSdan  tv sectorsize 16384;
2837abd6d84aSdan  tv devchar [list]
2838abd6d84aSdan  sqlite3 db test.db -vfs tv
2839abd6d84aSdan  execsql { UPDATE t1 SET x = randomblob(200) }
2840abd6d84aSdan} {}
2841abd6d84aSdandb close
2842abd6d84aSdantv delete
2843abd6d84aSdansqlite3_test_control_pending_byte $pending_prev
2844abd6d84aSdan
2845abd6d84aSdando_test 43.1 {
2846abd6d84aSdan  reset_db
2847abd6d84aSdan  execsql {
2848abd6d84aSdan    CREATE TABLE t1(x, y);
2849abd6d84aSdan    INSERT INTO t1 VALUES(1, 2);
2850abd6d84aSdan    CREATE TABLE t2(x, y);
2851abd6d84aSdan    INSERT INTO t2 VALUES(1, 2);
2852abd6d84aSdan    CREATE TABLE t3(x, y);
2853abd6d84aSdan    INSERT INTO t3 VALUES(1, 2);
2854abd6d84aSdan  }
2855abd6d84aSdan  db close
2856abd6d84aSdan  sqlite3 db test.db
2857abd6d84aSdan
28589b4c59faSdrh  db eval { PRAGMA mmap_size = 0 }
2859abd6d84aSdan  db eval { SELECT * FROM t1 }
2860abd6d84aSdan  sqlite3_db_status db CACHE_MISS 0
2861abd6d84aSdan} {0 2 0}
2862abd6d84aSdan
2863abd6d84aSdando_test 43.2 {
2864abd6d84aSdan  db eval { SELECT * FROM t2 }
2865abd6d84aSdan  sqlite3_db_status db CACHE_MISS 1
2866abd6d84aSdan} {0 3 0}
2867abd6d84aSdan
2868abd6d84aSdando_test 43.3 {
2869abd6d84aSdan  db eval { SELECT * FROM t3 }
2870abd6d84aSdan  sqlite3_db_status db CACHE_MISS 0
2871abd6d84aSdan} {0 1 0}
2872d7a558a9Sdan
2873d353331aSdanfinish_test
2874