xref: /sqlite-3.40.0/test/pager1.test (revision 33f111dc)
1e91a54e1Sdan# 2010 June 15
2e91a54e1Sdan#
3e91a54e1Sdan# The author disclaims copyright to this source code.  In place of
4e91a54e1Sdan# a legal notice, here is a blessing:
5e91a54e1Sdan#
6e91a54e1Sdan#    May you do good and not evil.
7e91a54e1Sdan#    May you find forgiveness for yourself and forgive others.
8e91a54e1Sdan#    May you share freely, never taking more than you give.
9e91a54e1Sdan#
10e91a54e1Sdan#***********************************************************************
11e91a54e1Sdan#
12e91a54e1Sdan
13e91a54e1Sdanset testdir [file dirname $argv0]
14e91a54e1Sdansource $testdir/tester.tcl
15e91a54e1Sdansource $testdir/lock_common.tcl
16e91a54e1Sdansource $testdir/malloc_common.tcl
17153eda0aSdansource $testdir/wal_common.tcl
1868928b6cSdan
1968928b6cSdan# Do not use a codec for tests in this file, as the database file is
2068928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command).
2168928b6cSdan#
2268928b6cSdando_not_use_codec
23e91a54e1Sdan
24b0ac3e3aSdan#
25b0ac3e3aSdan# pager1-1.*: Test inter-process locking (clients in multiple processes).
26b0ac3e3aSdan#
27b0ac3e3aSdan# pager1-2.*: Test intra-process locking (multiple clients in this process).
28b0ac3e3aSdan#
29b0ac3e3aSdan# pager1-3.*: Savepoint related tests.
30b0ac3e3aSdan#
311f4cb65aSdan# pager1-4.*: Hot-journal related tests.
321f4cb65aSdan#
33de4996e2Sdan# pager1-5.*: Cases related to multi-file commits.
34de4996e2Sdan#
35146ed78bSdan# pager1-6.*: Cases related to "PRAGMA max_page_count"
36146ed78bSdan#
37153eda0aSdan# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
38153eda0aSdan#
390e986f51Sdan# pager1-8.*: Cases using temporary and in-memory databases.
400e986f51Sdan#
41dca321aeSdan# pager1-9.*: Tests related to the backup API.
42dca321aeSdan#
43ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to
44ec6ffc1aSdan#              64KB.
45ec6ffc1aSdan#
46d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size"
47d353331aSdan#
48d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST"
49d353331aSdan#
50d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF"
51ec6ffc1aSdan#
52c8ce3972Sdan# pager1-15.*: Varying sqlite3_vfs.szOsFile
53c8ce3972Sdan#
54c8ce3972Sdan# pager1-16.*: Varying sqlite3_vfs.mxPathname
55c8ce3972Sdan#
56c8ce3972Sdan# pager1-17.*: Tests related to "PRAGMA omit_readlock"
57*33f111dcSdrh#              (The omit_readlock pragma has been removed and so have
58*33f111dcSdrh#              these tests.)
59c8ce3972Sdan#
60c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree
61c8ce3972Sdan#              requests an invalid page number (due to db corruption).
62c8ce3972Sdan#
63b0ac3e3aSdan
64c396d4afSdanproc recursive_select {id table {script {}}} {
65c396d4afSdan  set cnt 0
66c396d4afSdan  db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
67c396d4afSdan    recursive_select $rowid $table $script
68c396d4afSdan    incr cnt
69c396d4afSdan  }
70c396d4afSdan  if {$cnt==0} { eval $script }
71c396d4afSdan}
72c396d4afSdan
7353f04f3bSdanset a_string_counter 1
7453f04f3bSdanproc a_string {n} {
7553f04f3bSdan  global a_string_counter
7653f04f3bSdan  incr a_string_counter
7753f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
7853f04f3bSdan}
7953f04f3bSdandb func a_string a_string
8053f04f3bSdan
81a4a9095eSdando_multiclient_test tn {
82e91a54e1Sdan
83e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
84e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
85e91a54e1Sdan  #
86e91a54e1Sdan  do_test pager1-$tn.1 {
87e91a54e1Sdan    sql1 {
88e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
89e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
90d353331aSdan      INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
91e91a54e1Sdan    }
92e91a54e1Sdan  } {}
93e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
94e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
95e91a54e1Sdan
96e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
97e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
98e91a54e1Sdan  # read the database content as it was before the transaction was
99e91a54e1Sdan  # opened. [db] should see the inserted row.
100e91a54e1Sdan  #
101e91a54e1Sdan  do_test pager1-$tn.4 {
102e91a54e1Sdan    sql1 {
103e91a54e1Sdan      BEGIN;
104e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
105e91a54e1Sdan    }
106e91a54e1Sdan  } {}
107e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
108e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
109e91a54e1Sdan
110e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
111e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
112e91a54e1Sdan  #
113e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
114e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
115e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
116e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
117e91a54e1Sdan  #
118e91a54e1Sdan  do_test pager1-$tn.8 {
119e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
120e91a54e1Sdan  } {1 {database is locked}}
121e91a54e1Sdan  do_test pager1-$tn.9 {
122e91a54e1Sdan    csql2 {
123e91a54e1Sdan      BEGIN;
124e91a54e1Sdan      UPDATE t1 SET a = a + 10;
125e91a54e1Sdan    }
126e91a54e1Sdan  } {1 {database is locked}}
127e91a54e1Sdan
128e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
129e91a54e1Sdan  # now see the new database content.
130e91a54e1Sdan  #
131e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
132e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
133e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
134e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
135e91a54e1Sdan
136e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
137e91a54e1Sdan  # after the attempt to write the database failed.
138e91a54e1Sdan  #
139e91a54e1Sdan  do_test pager1-$tn.14 {
140e91a54e1Sdan    csql2 { BEGIN }
141e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
142e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
143e91a54e1Sdan
144e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
145e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
146e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
147e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
148e91a54e1Sdan  #
149e91a54e1Sdan  do_test pager1-$tn.15 {
150e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
151e91a54e1Sdan  } {1 one 2 two 3 three}
152e91a54e1Sdan  do_test pager1-$tn.16 {
153e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
154e91a54e1Sdan  } {1 {database is locked}}
155e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
156e91a54e1Sdan
157e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
158e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
159e91a54e1Sdan  # the SHARED lock [db2] is holding.
160e91a54e1Sdan  #
161e91a54e1Sdan  do_test pager1-$tn.18 {
162e91a54e1Sdan    sql1 {
163e91a54e1Sdan      BEGIN;
164e91a54e1Sdan      UPDATE t1 SET a = a + 10;
165e91a54e1Sdan    }
166e91a54e1Sdan  } {}
167e91a54e1Sdan  do_test pager1-$tn-19 {
168e91a54e1Sdan    sql1 { PRAGMA lock_status }
169e91a54e1Sdan  } {main reserved temp closed}
170e91a54e1Sdan  do_test pager1-$tn-20 {
171e91a54e1Sdan    sql2 { PRAGMA lock_status }
172e91a54e1Sdan  } {main shared temp closed}
173e91a54e1Sdan
174e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
175e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
176e91a54e1Sdan  #
177e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
178e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
179e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
180e91a54e1Sdan
181e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
182e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
183e91a54e1Sdan  # upgrades to a PENDING lock.
184e91a54e1Sdan  #
185e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
186e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
187e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
188e91a54e1Sdan  # the database.
189e91a54e1Sdan  #
190e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
191e91a54e1Sdan  do_test pager1-$tn-25 {
192e91a54e1Sdan    sql1 { PRAGMA lock_status }
193e91a54e1Sdan  } {main pending temp closed}
194e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
195e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
196e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
197e91a54e1Sdan
198e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
199e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
200e91a54e1Sdan  # is still holding a PENDING).
201e91a54e1Sdan  #
202e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
203e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
204e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
205e91a54e1Sdan
206e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
207e91a54e1Sdan  # committed, all three connections can read the new content.
208e91a54e1Sdan  #
209e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
210e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
211e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
212e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
213e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
214d353331aSdan
215d353331aSdan  # Install a busy-handler for connection [db].
216d353331aSdan  #
217d353331aSdan  set ::nbusy [list]
218d353331aSdan  proc busy {n} {
219d353331aSdan    lappend ::nbusy $n
220d353331aSdan    if {$n>5} { sql2 COMMIT }
221d353331aSdan    return 0
222d353331aSdan  }
223d353331aSdan  db busy busy
224d353331aSdan
225d353331aSdan  do_test pager1-$tn.29 {
226d353331aSdan    sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
227d353331aSdan  } {}
228d353331aSdan  do_test pager1-$tn.30 {
229d353331aSdan    sql2 { BEGIN ; SELECT * FROM t1 }
230d353331aSdan  } {21 one 22 two 23 three}
231d353331aSdan  do_test pager1-$tn.31 { sql1 COMMIT } {}
232d353331aSdan  do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
233e91a54e1Sdan}
234e91a54e1Sdan
23553f04f3bSdan#-------------------------------------------------------------------------
23653f04f3bSdan# Savepoint related test cases.
23753f04f3bSdan#
238dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
239dca321aeSdan#                 to grow.
240dca321aeSdan#
241273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
242273f3f0dSdan#                 of a savepoint rollback.
243273f3f0dSdan#
2440e986f51Sdando_test pager1-3.1.1 {
245b0ac3e3aSdan  faultsim_delete_and_reopen
246b0ac3e3aSdan  execsql {
247b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
248b0ac3e3aSdan    CREATE TABLE counter(
249b0ac3e3aSdan      i CHECK (i<5),
250b0ac3e3aSdan      u CHECK (u<10)
251b0ac3e3aSdan    );
252b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
253b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
254b0ac3e3aSdan      UPDATE counter SET i = i+1;
255b0ac3e3aSdan    END;
256b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
257b0ac3e3aSdan      UPDATE counter SET u = u+1;
258b0ac3e3aSdan    END;
259b0ac3e3aSdan  }
260b0ac3e3aSdan  execsql { SELECT * FROM counter }
261b0ac3e3aSdan} {0 0}
262b0ac3e3aSdan
2630e986f51Sdando_execsql_test pager1-3.1.2 {
264d353331aSdan  PRAGMA cache_size = 10;
265b0ac3e3aSdan  BEGIN;
266b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
267b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
268b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
269b0ac3e3aSdan    SELECT * FROM counter;
270b0ac3e3aSdan} {3 0}
2710e986f51Sdando_catchsql_test pager1-3.1.3 {
272b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
273b0ac3e3aSdan} {1 {constraint failed}}
274b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
275b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
276b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
277b0ac3e3aSdan
278273f3f0dSdanforeach {tn sql tcl} {
279d353331aSdan  7  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
280273f3f0dSdan    testvfs tv -default 1
281273f3f0dSdan    tv devchar safe_append
282273f3f0dSdan  }
283d353331aSdan  8  { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
284d353331aSdan    testvfs tv -default 1
285d353331aSdan    tv devchar sequential
286d353331aSdan  }
287d353331aSdan  9  { PRAGMA synchronous = FULL } { }
288d353331aSdan  10 { PRAGMA synchronous = NORMAL } { }
289d353331aSdan  11 { PRAGMA synchronous = OFF } { }
290d353331aSdan  12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
291d353331aSdan  13 { PRAGMA synchronous = FULL } {
292d353331aSdan    testvfs tv -default 1
293d353331aSdan    tv devchar sequential
294d353331aSdan  }
2956b63ab47Sdan  14 { PRAGMA locking_mode = EXCLUSIVE } {
2966b63ab47Sdan  }
297273f3f0dSdan} {
298273f3f0dSdan  do_test pager1-3.$tn.1 {
299273f3f0dSdan    eval $tcl
300dca321aeSdan    faultsim_delete_and_reopen
301dca321aeSdan    db func a_string a_string
302273f3f0dSdan    execsql $sql
303dca321aeSdan    execsql {
304dca321aeSdan      PRAGMA auto_vacuum = 2;
305dca321aeSdan      PRAGMA cache_size = 10;
306dca321aeSdan      CREATE TABLE z(x INTEGER PRIMARY KEY, y);
307dca321aeSdan      BEGIN;
308dca321aeSdan        INSERT INTO z VALUES(NULL, a_string(800));
309dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
310dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
311dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
312dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
313dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
314dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
315dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
316dca321aeSdan        INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
317dca321aeSdan      COMMIT;
318dca321aeSdan    }
319dca321aeSdan    execsql { PRAGMA auto_vacuum }
320dca321aeSdan  } {2}
321273f3f0dSdan  do_execsql_test pager1-3.$tn.2 {
322dca321aeSdan    BEGIN;
323dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
324dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
325dca321aeSdan      SAVEPOINT one;
326273f3f0dSdan        UPDATE z SET y = NULL WHERE x>256;
327dca321aeSdan        PRAGMA incremental_vacuum;
328dca321aeSdan        SELECT count(*) FROM z WHERE x < 100;
329dca321aeSdan      ROLLBACK TO one;
330dca321aeSdan    COMMIT;
331dca321aeSdan  } {99}
332dca321aeSdan
333273f3f0dSdan  do_execsql_test pager1-3.$tn.3 {
334273f3f0dSdan    BEGIN;
335273f3f0dSdan      SAVEPOINT one;
336273f3f0dSdan        UPDATE z SET y = y||x;
337273f3f0dSdan      ROLLBACK TO one;
338273f3f0dSdan    COMMIT;
339273f3f0dSdan    SELECT count(*) FROM z;
340273f3f0dSdan  } {258}
341273f3f0dSdan
342273f3f0dSdan  do_execsql_test pager1-3.$tn.4 {
343273f3f0dSdan    SAVEPOINT one;
344273f3f0dSdan      UPDATE z SET y = y||x;
345273f3f0dSdan    ROLLBACK TO one;
346273f3f0dSdan  } {}
347273f3f0dSdan  do_execsql_test pager1-3.$tn.5 {
348273f3f0dSdan    SELECT count(*) FROM z;
349273f3f0dSdan    RELEASE one;
350273f3f0dSdan    PRAGMA integrity_check;
351273f3f0dSdan  } {258 ok}
352273f3f0dSdan
35378f1e538Sdan  do_execsql_test pager1-3.$tn.6 {
35478f1e538Sdan    SAVEPOINT one;
35578f1e538Sdan    RELEASE one;
35678f1e538Sdan  } {}
35778f1e538Sdan
358273f3f0dSdan  db close
359273f3f0dSdan  catch { tv delete }
360273f3f0dSdan}
361273f3f0dSdan
36253f04f3bSdan#-------------------------------------------------------------------------
36353f04f3bSdan# Hot journal rollback related test cases.
36453f04f3bSdan#
36553f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
36653f04f3bSdan#               journal files.
36753f04f3bSdan#
36853f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
36953f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
37053f04f3bSdan#               compute) the associated journal is rolled back (and no
37153f04f3bSdan#               xAccess() call to check for the presence of any master
37253f04f3bSdan#               journal file is made).
37353f04f3bSdan#
374de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
375de4996e2Sdan#               page-size or sector-size in the journal header appear to
376de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
377de4996e2Sdan#
378e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
379e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
380e08341c6Sdan#               modes.
381e08341c6Sdan#
382e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
383e08341c6Sdan#               journal-record for which the checksum fails.
384e08341c6Sdan#
385ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
386ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
387ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
388ec6ffc1aSdan#
389c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can
390c8ce3972Sdan#               open it for reading only, the database cannot be accessed and
391c8ce3972Sdan#               SQLITE_CANTOPEN is returned.
392c8ce3972Sdan#
39353f04f3bSdando_test pager1.4.1.1 {
39453f04f3bSdan  faultsim_delete_and_reopen
39553f04f3bSdan  execsql {
39653f04f3bSdan    CREATE TABLE x(y, z);
39753f04f3bSdan    INSERT INTO x VALUES(1, 2);
39853f04f3bSdan  }
39953f04f3bSdan  set fd [open test.db-journal w]
40053f04f3bSdan  puts -nonewline $fd "helloworld"
40153f04f3bSdan  close $fd
40253f04f3bSdan  file exists test.db-journal
40353f04f3bSdan} {1}
40453f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
40553f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
40653f04f3bSdan
40753f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
40853f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
40953f04f3bSdan#
41053f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
41153f04f3bSdan# up the file system to contain two databases, two hot-journal files and
41253f04f3bSdan# a master-journal.
41353f04f3bSdan#
41453f04f3bSdando_test pager1.4.2.1 {
41553f04f3bSdan  testvfs tstvfs -default 1
41653f04f3bSdan  tstvfs filter xDelete
41753f04f3bSdan  tstvfs script xDeleteCallback
41853f04f3bSdan  proc xDeleteCallback {method file args} {
41953f04f3bSdan    set file [file tail $file]
42053f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
42153f04f3bSdan  }
42253f04f3bSdan  faultsim_delete_and_reopen
42353f04f3bSdan  db func a_string a_string
42453f04f3bSdan  execsql {
42553f04f3bSdan    ATTACH 'test.db2' AS aux;
42653f04f3bSdan    PRAGMA journal_mode = DELETE;
42753f04f3bSdan    PRAGMA main.cache_size = 10;
42853f04f3bSdan    PRAGMA aux.cache_size = 10;
42953f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
43053f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
43153f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
43253f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43353f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
43453f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
43553f04f3bSdan    BEGIN;
43653f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
43753f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
43853f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
43953f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
44053f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
44153f04f3bSdan    COMMIT;
44253f04f3bSdan  }
44353f04f3bSdan  db close
44453f04f3bSdan  tstvfs delete
44553f04f3bSdan} {}
446b2f20bfcSshaneh
447b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
44853f04f3bSdando_test pager1.4.2.2 {
44953f04f3bSdan  faultsim_restore_and_reopen
45053f04f3bSdan  execsql {
45153f04f3bSdan    SELECT count(*) FROM t1;
45253f04f3bSdan    PRAGMA integrity_check;
45353f04f3bSdan  }
45453f04f3bSdan} {4 ok}
45553f04f3bSdando_test pager1.4.2.3 {
45653f04f3bSdan  faultsim_restore_and_reopen
457fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
45853f04f3bSdan  execsql {
45953f04f3bSdan    SELECT count(*) FROM t1;
46053f04f3bSdan    PRAGMA integrity_check;
46153f04f3bSdan  }
46253f04f3bSdan} {64 ok}
46353f04f3bSdando_test pager1.4.2.4 {
46453f04f3bSdan  faultsim_restore_and_reopen
46553f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
46653f04f3bSdan  execsql {
46753f04f3bSdan    SELECT count(*) FROM t1;
46853f04f3bSdan    PRAGMA integrity_check;
46953f04f3bSdan  }
47053f04f3bSdan} {4 ok}
47153f04f3bSdando_test pager1.4.2.5 {
47253f04f3bSdan  faultsim_restore_and_reopen
47353f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
474fda06befSmistachkin  foreach f [glob test.db-mj*] { forcedelete $f }
47553f04f3bSdan  execsql {
47653f04f3bSdan    SELECT count(*) FROM t1;
47753f04f3bSdan    PRAGMA integrity_check;
47853f04f3bSdan  }
47953f04f3bSdan} {4 ok}
480b2f20bfcSshaneh}
48153f04f3bSdan
482de4996e2Sdando_test pager1.4.3.1 {
483de4996e2Sdan  testvfs tstvfs -default 1
484de4996e2Sdan  tstvfs filter xSync
485de4996e2Sdan  tstvfs script xSyncCallback
486de4996e2Sdan  proc xSyncCallback {method file args} {
487de4996e2Sdan    set file [file tail $file]
488de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
489de4996e2Sdan  }
490de4996e2Sdan  faultsim_delete_and_reopen
491de4996e2Sdan  execsql {
492de4996e2Sdan    PRAGMA journal_mode = DELETE;
493de4996e2Sdan    CREATE TABLE t1(a, b);
494de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
495de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
496de4996e2Sdan  }
497de4996e2Sdan  db close
498de4996e2Sdan  tstvfs delete
499de4996e2Sdan} {}
500de4996e2Sdan
501de4996e2Sdanforeach {tn ofst value result} {
502de4996e2Sdan          2   20    31       {1 2 3 4}
503de4996e2Sdan          3   20    32       {1 2 3 4}
504de4996e2Sdan          4   20    33       {1 2 3 4}
505de4996e2Sdan          5   20    65536    {1 2 3 4}
506de4996e2Sdan          6   20    131072   {1 2 3 4}
507de4996e2Sdan
508de4996e2Sdan          7   24    511      {1 2 3 4}
509de4996e2Sdan          8   24    513      {1 2 3 4}
510b2eced5dSdrh          9   24    131072   {1 2 3 4}
511de4996e2Sdan
512de4996e2Sdan         10   32    65536    {1 2}
513de4996e2Sdan} {
514de4996e2Sdan  do_test pager1.4.3.$tn {
515de4996e2Sdan    faultsim_restore_and_reopen
516de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
517de4996e2Sdan    execsql { SELECT * FROM t1 }
518de4996e2Sdan  } $result
519de4996e2Sdan}
520de4996e2Sdandb close
521de4996e2Sdan
522e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
523e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
524e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
525e08341c6Sdan# master journal file from the file-system.
526e08341c6Sdan#
527e08341c6Sdantestvfs tv -default 1
528e08341c6Sdantv script copy_on_mj_delete
529e08341c6Sdanset ::mj_filename_length 0
530e08341c6Sdanproc copy_on_mj_delete {method filename args} {
531e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
532e08341c6Sdan    set ::mj_filename_length [string length $filename]
533e08341c6Sdan    faultsim_save
534e08341c6Sdan  }
535e08341c6Sdan  return SQLITE_OK
536e08341c6Sdan}
537e08341c6Sdan
538e08341c6Sdanset pwd [pwd]
539e08341c6Sdanforeach {tn1 tcl} {
540e08341c6Sdan  1 { set prefix "test.db" }
541e08341c6Sdan  2 {
542e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
543e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
544e08341c6Sdan    # contains a master-journal pointer so large that it could contain
545e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
546e08341c6Sdan    # make sure SQLite doesn't get confused by this.
547e08341c6Sdan    #
548e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
54933d85c9cSshaneh    if {$tcl_platform(platform)=="windows"} {
55033d85c9cSshaneh      # TBD need to figure out how to do this correctly for Windows!!!
55133d85c9cSshaneh      set nPadding [expr 255 - $::mj_filename_length]
55233d85c9cSshaneh    }
553e08341c6Sdan
554e08341c6Sdan    # We cannot just create a really long database file name to open, as
555e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
556e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
557e08341c6Sdan    # hierarchy to work in.
558e08341c6Sdan    #
559e08341c6Sdan    set dirname "d123456789012345678901234567890/"
560e08341c6Sdan    set nDir [expr $nPadding / 32]
561e08341c6Sdan    if { $nDir } {
562e08341c6Sdan      set p [string repeat $dirname $nDir]
563e08341c6Sdan      file mkdir $p
564e08341c6Sdan      cd $p
565e08341c6Sdan    }
566e08341c6Sdan
567e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
568e08341c6Sdan    set prefix "test.db${padding}"
569e08341c6Sdan  }
570e08341c6Sdan} {
571e08341c6Sdan  eval $tcl
572e08341c6Sdan  foreach {tn2 sql} {
573e08341c6Sdan    o {
574e08341c6Sdan      PRAGMA main.synchronous=OFF;
575e08341c6Sdan      PRAGMA aux.synchronous=OFF;
5763f94b609Sdan      PRAGMA journal_mode = DELETE;
577e08341c6Sdan    }
578e08341c6Sdan    o512 {
579e08341c6Sdan      PRAGMA main.synchronous=OFF;
580e08341c6Sdan      PRAGMA aux.synchronous=OFF;
581e08341c6Sdan      PRAGMA main.page_size = 512;
582e08341c6Sdan      PRAGMA aux.page_size = 512;
5833f94b609Sdan      PRAGMA journal_mode = DELETE;
584e08341c6Sdan    }
585e08341c6Sdan    n {
586e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
587e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
5883f94b609Sdan      PRAGMA journal_mode = DELETE;
589e08341c6Sdan    }
590e08341c6Sdan    f {
591e08341c6Sdan      PRAGMA main.synchronous=FULL;
592e08341c6Sdan      PRAGMA aux.synchronous=FULL;
5933f94b609Sdan      PRAGMA journal_mode = DELETE;
594e08341c6Sdan    }
595e08341c6Sdan  } {
596e08341c6Sdan
597e08341c6Sdan    set tn "${tn1}.${tn2}"
598e08341c6Sdan
599e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
600e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
601e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
602e08341c6Sdan    # file is deleted to commit the transaction.
603e08341c6Sdan    #
604e08341c6Sdan    tv filter xDelete
605e08341c6Sdan    do_test pager1-4.4.$tn.1 {
606e08341c6Sdan      faultsim_delete_and_reopen $prefix
607e08341c6Sdan      execsql "
608e08341c6Sdan        ATTACH '${prefix}2' AS aux;
609e08341c6Sdan        $sql
610e08341c6Sdan        CREATE TABLE a(x);
611e08341c6Sdan        CREATE TABLE aux.b(x);
612e08341c6Sdan        INSERT INTO a VALUES('double-you');
613e08341c6Sdan        INSERT INTO a VALUES('why');
614e08341c6Sdan        INSERT INTO a VALUES('zed');
615e08341c6Sdan        INSERT INTO b VALUES('won');
616e08341c6Sdan        INSERT INTO b VALUES('too');
617e08341c6Sdan        INSERT INTO b VALUES('free');
618e08341c6Sdan      "
619e08341c6Sdan      execsql {
620e08341c6Sdan        BEGIN;
621e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
622e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
623e08341c6Sdan        COMMIT;
624e08341c6Sdan      }
625e08341c6Sdan    } {}
626e08341c6Sdan    tv filter {}
627e08341c6Sdan
628e08341c6Sdan    # Check that the transaction was committed successfully.
629e08341c6Sdan    #
630e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
631e08341c6Sdan      SELECT * FROM a
632e08341c6Sdan    } {double-you why zed won too free}
633e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
634e08341c6Sdan      SELECT * FROM b
635e08341c6Sdan    } {won too free double-you why zed}
636e08341c6Sdan
637e08341c6Sdan    # Restore the file-system and reopen the databases. Check that it now
638e08341c6Sdan    # appears that the transaction was not committed (because the file-system
639e08341c6Sdan    # was restored to the state where it had not been).
640e08341c6Sdan    #
641e08341c6Sdan    do_test pager1-4.4.$tn.4 {
642e08341c6Sdan      faultsim_restore_and_reopen $prefix
643e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
644e08341c6Sdan    } {}
645e08341c6Sdan    do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
646e08341c6Sdan    do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
647e08341c6Sdan
648e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
649e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
650e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
651e08341c6Sdan    #
652e08341c6Sdan    do_test pager1-4.4.$tn.7 {
653e08341c6Sdan      faultsim_restore_and_reopen $prefix
654fda06befSmistachkin      foreach f [glob ${prefix}-mj*] { forcedelete $f }
655e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
656e08341c6Sdan    } {}
657e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
658e08341c6Sdan      SELECT * FROM a
659e08341c6Sdan    } {double-you why zed won too free}
660e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
661e08341c6Sdan      SELECT * FROM b
662e08341c6Sdan    } {won too free double-you why zed}
663e08341c6Sdan  }
664e08341c6Sdan
665e08341c6Sdan  cd $pwd
666e08341c6Sdan}
667e08341c6Sdandb close
668e08341c6Sdantv delete
669fda06befSmistachkinforcedelete $dirname
6700e986f51Sdan
6710e986f51Sdan
6720e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
6730e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
6740e986f51Sdan# two database pages (and page 1 - the change counter).
6750e986f51Sdan#
6760e986f51Sdantestvfs tv -default 1
6770e986f51Sdantv sectorsize 512
6780e986f51Sdantv script copy_on_journal_delete
6790e986f51Sdantv filter xDelete
6800e986f51Sdanproc copy_on_journal_delete {method filename args} {
6810e986f51Sdan  if {[string match *journal $filename]} faultsim_save
6820e986f51Sdan  return SQLITE_OK
6830e986f51Sdan}
6840e986f51Sdanfaultsim_delete_and_reopen
6850e986f51Sdando_execsql_test pager1.4.5.1 {
6863f94b609Sdan  PRAGMA journal_mode = DELETE;
6870e986f51Sdan  PRAGMA page_size = 1024;
6880e986f51Sdan  CREATE TABLE t1(a, b);
6890e986f51Sdan  CREATE TABLE t2(a, b);
6900e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
6910e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
6920e986f51Sdan  BEGIN;
6930e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
6940e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
6950e986f51Sdan  COMMIT;
6963f94b609Sdan} {delete}
6970e986f51Sdantv filter {}
6980e986f51Sdan
6990e986f51Sdan# Check the transaction was committed:
7000e986f51Sdan#
7010e986f51Sdando_execsql_test pager1.4.5.2 {
7020e986f51Sdan  SELECT * FROM t1;
7030e986f51Sdan  SELECT * FROM t2;
7040e986f51Sdan} {I II 1 2 III IV 3 4}
7050e986f51Sdan
706ec6ffc1aSdan# Now try four tests:
7070e986f51Sdan#
7080e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
7090e986f51Sdan#                is rolled back.
7100e986f51Sdan#
7110e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
7120e986f51Sdan#                journal. Check the transaction is not rolled back.
7130e986f51Sdan#
7140e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
7150e986f51Sdan#                journal. Check that the first record in the transaction is
7160e986f51Sdan#                played back, but not the second.
7170e986f51Sdan#
71810f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
71910f5a50eSdan#                readonly connection. This should fail, as a read-only
72010f5a50eSdan#                connection cannot roll back the database file.
72110f5a50eSdan#
7220e986f51Sdanfaultsim_restore_and_reopen
7230e986f51Sdando_execsql_test pager1.4.5.3 {
7240e986f51Sdan  SELECT * FROM t1;
7250e986f51Sdan  SELECT * FROM t2;
7260e986f51Sdan} {I II III IV}
7270e986f51Sdanfaultsim_restore_and_reopen
7280e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
7290e986f51Sdando_execsql_test pager1.4.5.4 {
7300e986f51Sdan  SELECT * FROM t1;
7310e986f51Sdan  SELECT * FROM t2;
7320e986f51Sdan} {I II 1 2 III IV 3 4}
7330e986f51Sdanfaultsim_restore_and_reopen
7340e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
7350e986f51Sdando_execsql_test pager1.4.5.5 {
7360e986f51Sdan  SELECT * FROM t1;
7370e986f51Sdan  SELECT * FROM t2;
7380e986f51Sdan} {I II III IV 3 4}
7390e986f51Sdan
74010f5a50eSdanfaultsim_restore_and_reopen
74110f5a50eSdandb close
74210f5a50eSdansqlite3 db test.db -readonly 1
74310f5a50eSdando_catchsql_test pager1.4.5.6 {
74410f5a50eSdan  SELECT * FROM t1;
74510f5a50eSdan  SELECT * FROM t2;
74610f5a50eSdan} {1 {disk I/O error}}
747ec6ffc1aSdandb close
748ec6ffc1aSdan
749ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
750ec6ffc1aSdan# of the master journal file in $::mj_filename.
751ec6ffc1aSdan#
752ec6ffc1aSdantv script copy_on_mj_delete
753ec6ffc1aSdantv filter xDelete
754ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
755ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
756ec6ffc1aSdan    set ::mj_filename $filename
757ec6ffc1aSdan    faultsim_save
758ec6ffc1aSdan  }
759ec6ffc1aSdan  return SQLITE_OK
760ec6ffc1aSdan}
761ec6ffc1aSdando_test pager1.4.6.1 {
762ec6ffc1aSdan  faultsim_delete_and_reopen
763ec6ffc1aSdan  execsql {
7643f94b609Sdan    PRAGMA journal_mode = DELETE;
765ec6ffc1aSdan    ATTACH 'test.db2' AS two;
766ec6ffc1aSdan    CREATE TABLE t1(a, b);
767ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
768ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
769ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
770ec6ffc1aSdan    BEGIN;
771ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
772ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
773ec6ffc1aSdan    COMMIT;
774ec6ffc1aSdan  }
775ec6ffc1aSdan  tv filter {}
776ec6ffc1aSdan  db close
777ec6ffc1aSdan} {}
778ec6ffc1aSdan
779ec6ffc1aSdanfaultsim_restore_and_reopen
780ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
781ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
782ec6ffc1aSdando_execsql_test pager1.4.6.4 {
783ec6ffc1aSdan  ATTACH 'test.db2' AS two;
784ec6ffc1aSdan  SELECT * FROM t2;
785ec6ffc1aSdan} {1 t2.1}
786ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
787ec6ffc1aSdan
788ec6ffc1aSdanfaultsim_restore_and_reopen
789ec6ffc1aSdandb close
790ec6ffc1aSdando_test pager1.4.6.8 {
791ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
792ec6ffc1aSdan  tv filter xDelete
793ec6ffc1aSdan  sqlite3 db test.db2
794ec6ffc1aSdan  execsql {
7953f94b609Sdan    PRAGMA journal_mode = DELETE;
796ec6ffc1aSdan    ATTACH 'test.db3' AS three;
797ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
798ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
799ec6ffc1aSdan    BEGIN;
800ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
801ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
802ec6ffc1aSdan    COMMIT;
803ec6ffc1aSdan  }
804ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
805ec6ffc1aSdan} {1}
806ec6ffc1aSdanfaultsim_restore_and_reopen
807ec6ffc1aSdantv filter {}
808ec6ffc1aSdan
809ec6ffc1aSdan# The file-system now contains:
810ec6ffc1aSdan#
811ec6ffc1aSdan#   * three databases
812ec6ffc1aSdan#   * three hot-journal files
813ec6ffc1aSdan#   * two master-journal files.
814ec6ffc1aSdan#
815ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
816ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
817ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
818ec6ffc1aSdan# test.db should delete $::mj_filename1.
819ec6ffc1aSdan#
820ec6ffc1aSdando_test pager1.4.6.9 {
821ec6ffc1aSdan  lsort [glob test.db*]
822ec6ffc1aSdan} [lsort [list                                           \
823ec6ffc1aSdan  test.db test.db2 test.db3                              \
824ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
825ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
826ec6ffc1aSdan]]
827ec6ffc1aSdan
828ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
829ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
830ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
831ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
832ec6ffc1aSdan#
833ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
834ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
835ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
836ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
837ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
838ec6ffc1aSdan
839ec6ffc1aSdando_execsql_test pager1.4.6.12 {
840ec6ffc1aSdan  ATTACH 'test.db2' AS two;
841ec6ffc1aSdan  SELECT * FROM t2;
842ec6ffc1aSdan} {1 t2.1}
843ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
844ec6ffc1aSdando_execsql_test pager1.4.6.14 {
845ec6ffc1aSdan  ATTACH 'test.db3' AS three;
846ec6ffc1aSdan  SELECT * FROM t3;
847ec6ffc1aSdan} {1 t3.1}
848ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
84910f5a50eSdan
8500e986f51Sdandb close
8510e986f51Sdantv delete
852e08341c6Sdan
853c8ce3972Sdantestvfs tv -default 1
854c8ce3972Sdantv sectorsize 512
855c8ce3972Sdantv script copy_on_journal_delete
856c8ce3972Sdantv filter xDelete
857c8ce3972Sdanproc copy_on_journal_delete {method filename args} {
858c8ce3972Sdan  if {[string match *journal $filename]} faultsim_save
859c8ce3972Sdan  return SQLITE_OK
860c8ce3972Sdan}
861c8ce3972Sdanfaultsim_delete_and_reopen
862c8ce3972Sdando_execsql_test pager1.4.7.1 {
8633f94b609Sdan  PRAGMA journal_mode = DELETE;
864c8ce3972Sdan  CREATE TABLE t1(x PRIMARY KEY, y);
865c8ce3972Sdan  CREATE INDEX i1 ON t1(y);
866c8ce3972Sdan  INSERT INTO t1 VALUES('I',   'one');
867c8ce3972Sdan  INSERT INTO t1 VALUES('II',  'four');
868c8ce3972Sdan  INSERT INTO t1 VALUES('III', 'nine');
869c8ce3972Sdan  BEGIN;
870c8ce3972Sdan    INSERT INTO t1 VALUES('IV', 'sixteen');
871c8ce3972Sdan    INSERT INTO t1 VALUES('V' , 'twentyfive');
872c8ce3972Sdan  COMMIT;
8733f94b609Sdan} {delete}
874c8ce3972Sdantv filter {}
875c8ce3972Sdandb close
876c8ce3972Sdantv delete
877c8ce3972Sdando_test pager1.4.7.2 {
878c8ce3972Sdan  faultsim_restore_and_reopen
879c8ce3972Sdan  catch {file attributes test.db-journal -permissions r--------}
880c8ce3972Sdan  catch {file attributes test.db-journal -readonly 1}
881c8ce3972Sdan  catchsql { SELECT * FROM t1 }
882c8ce3972Sdan} {1 {unable to open database file}}
883c8ce3972Sdando_test pager1.4.7.3 {
884c8ce3972Sdan  db close
885c8ce3972Sdan  catch {file attributes test.db-journal -permissions rw-rw-rw-}
886c8ce3972Sdan  catch {file attributes test.db-journal -readonly 0}
887fda06befSmistachkin  delete_file test.db-journal
888c8ce3972Sdan  file exists test.db-journal
889c8ce3972Sdan} {0}
890c8ce3972Sdan
891de4996e2Sdan#-------------------------------------------------------------------------
892146ed78bSdan# The following tests deal with multi-file commits.
893de4996e2Sdan#
894146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
895146ed78bSdan#               another connection is holding a SHARED lock on one of the
896146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
897146ed78bSdan#
898146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
899146ed78bSdan#
900146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
901146ed78bSdan#
902146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
903146ed78bSdan#               name is added to a journal file immediately after the last
904146ed78bSdan#               journal record. But with synchronous=full, extra unused space
905146ed78bSdan#               is allocated between the last journal record and the
906146ed78bSdan#               master-journal file name so that the master-journal file
907146ed78bSdan#               name does not lie on the same sector as the last journal file
908146ed78bSdan#               record.
909146ed78bSdan#
910e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
911e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
912e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
913e08341c6Sdan#
914146ed78bSdan#
915146ed78bSdando_test pager1-5.1.1 {
916146ed78bSdan  faultsim_delete_and_reopen
917146ed78bSdan  execsql {
918146ed78bSdan    ATTACH 'test.db2' AS aux;
919146ed78bSdan    CREATE TABLE t1(a, b);
920146ed78bSdan    CREATE TABLE aux.t2(a, b);
921146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
922146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
923146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
924146ed78bSdan  }
925146ed78bSdan} {}
926146ed78bSdando_test pager1-5.1.2 {
927146ed78bSdan  execsql {
928146ed78bSdan    BEGIN;
929146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
930146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
931146ed78bSdan  }
932146ed78bSdan  sqlite3 db2 test.db2
933146ed78bSdan  execsql {
934146ed78bSdan    BEGIN;
935146ed78bSdan      SELECT * FROM t2;
936146ed78bSdan  } db2
937146ed78bSdan} {}
938146ed78bSdando_test pager1-5.1.3 {
939146ed78bSdan  catchsql COMMIT
940146ed78bSdan} {1 {database is locked}}
941146ed78bSdando_test pager1-5.1.4 {
942146ed78bSdan  execsql COMMIT db2
943146ed78bSdan  execsql COMMIT
944146ed78bSdan  execsql { SELECT * FROM t2 } db2
945146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
946146ed78bSdando_test pager1-5.1.5 {
947146ed78bSdan  db2 close
948146ed78bSdan} {}
949146ed78bSdan
950146ed78bSdando_test pager1-5.2.1 {
951146ed78bSdan  execsql {
952146ed78bSdan    PRAGMA journal_mode = memory;
953146ed78bSdan    BEGIN;
954146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
955146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
956146ed78bSdan    COMMIT;
957146ed78bSdan  }
958146ed78bSdan} {memory}
959146ed78bSdando_test pager1-5.3.1 {
960146ed78bSdan  execsql {
961146ed78bSdan    PRAGMA journal_mode = off;
962146ed78bSdan    BEGIN;
963146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
964146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
965146ed78bSdan    COMMIT;
966146ed78bSdan  }
967146ed78bSdan} {off}
968146ed78bSdan
969146ed78bSdando_test pager1-5.4.1 {
970146ed78bSdan  db close
971146ed78bSdan  testvfs tv
972146ed78bSdan  sqlite3 db test.db -vfs tv
973146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
974146ed78bSdan
975146ed78bSdan  tv filter xDelete
976146ed78bSdan  tv script max_journal_size
977146ed78bSdan  tv sectorsize 512
978146ed78bSdan  set ::max_journal 0
979146ed78bSdan  proc max_journal_size {method args} {
980146ed78bSdan    set sz 0
981146ed78bSdan    catch { set sz [file size test.db-journal] }
982146ed78bSdan    if {$sz > $::max_journal} {
983146ed78bSdan      set ::max_journal $sz
984146ed78bSdan    }
985146ed78bSdan    return SQLITE_OK
986146ed78bSdan  }
987146ed78bSdan  execsql {
988146ed78bSdan    PRAGMA journal_mode = DELETE;
989146ed78bSdan    PRAGMA synchronous = NORMAL;
990146ed78bSdan    BEGIN;
991146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
992146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
993146ed78bSdan    COMMIT;
994146ed78bSdan  }
9957f9026ddSdan
9967f9026ddSdan  # The size of the journal file is now:
9977f9026ddSdan  #
9987f9026ddSdan  #   1) 512 byte header +
9997f9026ddSdan  #   2) 2 * (1024+8) byte records +
10007f9026ddSdan  #   3) 20+N bytes of master-journal pointer, where N is the size of
10017f9026ddSdan  #      the master-journal name encoded as utf-8 with no nul term.
10027f9026ddSdan  #
10037f9026ddSdan  set mj_pointer [expr {
10047f9026ddSdan    20 + [string length [pwd]] + [string length "/test.db-mjXXXXXX9XX"]
10057f9026ddSdan  }]
10067f9026ddSdan  expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
10077f9026ddSdan} 1
1008146ed78bSdando_test pager1-5.4.2 {
1009146ed78bSdan  set ::max_journal 0
1010146ed78bSdan  execsql {
1011146ed78bSdan    PRAGMA synchronous = full;
1012146ed78bSdan    BEGIN;
1013146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
1014146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
1015146ed78bSdan    COMMIT;
1016146ed78bSdan  }
10177f9026ddSdan
10187f9026ddSdan  # In synchronous=full mode, the master-journal pointer is not written
10197f9026ddSdan  # directly after the last record in the journal file. Instead, it is
10207f9026ddSdan  # written starting at the next (in this case 512 byte) sector boundary.
10217f9026ddSdan  #
10227f9026ddSdan  set mj_pointer [expr {
10237f9026ddSdan    20 + [string length [pwd]] + [string length "/test.db-mjXXXXXX9XX"]
10247f9026ddSdan  }]
10257f9026ddSdan  expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
10267f9026ddSdan} 1
1027146ed78bSdandb close
1028146ed78bSdantv delete
1029146ed78bSdan
1030146ed78bSdando_test pager1-5.5.1 {
1031146ed78bSdan  sqlite3 db test.db
1032146ed78bSdan  execsql {
1033146ed78bSdan    ATTACH 'test.db2' AS aux;
1034146ed78bSdan    PRAGMA journal_mode = PERSIST;
1035146ed78bSdan    CREATE TABLE t3(a, b);
1036146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
1037146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
1038146ed78bSdan  }
1039146ed78bSdan  expr [file size test.db-journal] > 15000
1040146ed78bSdan} {1}
1041146ed78bSdando_test pager1-5.5.2 {
1042146ed78bSdan  execsql {
1043146ed78bSdan    PRAGMA synchronous = full;
1044146ed78bSdan    BEGIN;
1045146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
1046146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
1047146ed78bSdan    COMMIT;
1048146ed78bSdan  }
1049146ed78bSdan  file size test.db-journal
1050146ed78bSdan} {0}
1051146ed78bSdan
1052146ed78bSdan
1053146ed78bSdan#-------------------------------------------------------------------------
1054146ed78bSdan# The following tests work with "PRAGMA max_page_count"
1055146ed78bSdan#
1056146ed78bSdando_test pager1-6.1 {
1057146ed78bSdan  faultsim_delete_and_reopen
1058146ed78bSdan  execsql {
1059f43d7fceSdan    PRAGMA auto_vacuum = none;
1060146ed78bSdan    PRAGMA max_page_count = 10;
1061146ed78bSdan    CREATE TABLE t2(a, b);
1062146ed78bSdan    CREATE TABLE t3(a, b);
1063146ed78bSdan    CREATE TABLE t4(a, b);
1064146ed78bSdan    CREATE TABLE t5(a, b);
1065146ed78bSdan    CREATE TABLE t6(a, b);
1066146ed78bSdan    CREATE TABLE t7(a, b);
1067146ed78bSdan    CREATE TABLE t8(a, b);
1068146ed78bSdan    CREATE TABLE t9(a, b);
1069146ed78bSdan    CREATE TABLE t10(a, b);
1070146ed78bSdan  }
1071146ed78bSdan} {10}
1072d353331aSdando_catchsql_test pager1-6.2 {
1073d353331aSdan  CREATE TABLE t11(a, b)
1074146ed78bSdan} {1 {database or disk is full}}
1075d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count      } {10}
1076d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
1077d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b)     } {}
1078d353331aSdando_execsql_test pager1-6.7 {
1079d353331aSdan  BEGIN;
1080d353331aSdan    INSERT INTO t11 VALUES(1, 2);
1081d353331aSdan    PRAGMA max_page_count = 13;
1082d353331aSdan} {13}
1083d353331aSdando_execsql_test pager1-6.8 {
1084d353331aSdan    INSERT INTO t11 VALUES(3, 4);
1085d353331aSdan    PRAGMA max_page_count = 10;
1086d353331aSdan} {11}
1087d353331aSdando_execsql_test pager1-6.9 { COMMIT } {}
1088de4996e2Sdan
108960ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
109022b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
109122b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
109222b328b2Sdan
1093153eda0aSdan
1094153eda0aSdan#-------------------------------------------------------------------------
1095153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
1096153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
1097153eda0aSdan#
1098153eda0aSdan# Each test is specified with 5 variables. As follows:
1099153eda0aSdan#
1100153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
1101153eda0aSdan#   $sql: SQL to execute.
1102153eda0aSdan#   $res: Expected result of executing $sql.
1103153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
1104153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
1105153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
1106153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
1107153eda0aSdan#
110838e1a279Sdanifcapable wal {
1109153eda0aSdan  faultsim_delete_and_reopen
1110153eda0aSdan  foreach {tn sql res js ws} [subst {
1111153eda0aSdan
1112153eda0aSdan    1  {
1113153eda0aSdan      CREATE TABLE t1(a, b);
1114153eda0aSdan      PRAGMA auto_vacuum=OFF;
1115153eda0aSdan      PRAGMA synchronous=NORMAL;
1116153eda0aSdan      PRAGMA page_size=1024;
1117153eda0aSdan      PRAGMA locking_mode=EXCLUSIVE;
1118153eda0aSdan      PRAGMA journal_mode=TRUNCATE;
1119153eda0aSdan      INSERT INTO t1 VALUES(1, 2);
1120153eda0aSdan    } {exclusive truncate} 0 -1
1121153eda0aSdan
1122153eda0aSdan    2  {
1123153eda0aSdan      BEGIN IMMEDIATE;
1124153eda0aSdan        SELECT * FROM t1;
1125153eda0aSdan      COMMIT;
1126153eda0aSdan    } {1 2} 0 -1
1127153eda0aSdan
1128153eda0aSdan    3  {
1129153eda0aSdan      BEGIN;
1130153eda0aSdan        SELECT * FROM t1;
1131153eda0aSdan      COMMIT;
1132153eda0aSdan    } {1 2} 0 -1
1133153eda0aSdan
1134153eda0aSdan    4  { PRAGMA journal_mode = WAL }    wal       -1 -1
1135153eda0aSdan    5  { INSERT INTO t1 VALUES(3, 4) }  {}        -1 [wal_file_size 1 1024]
11368c408004Sdan    6  { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
1137153eda0aSdan    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
1138153eda0aSdan
1139153eda0aSdan    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
1140153eda0aSdan    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
1141153eda0aSdan    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
1142153eda0aSdan
1143153eda0aSdan  }] {
1144153eda0aSdan    do_execsql_test pager1-7.1.$tn.1 $sql $res
1145153eda0aSdan    catch { set J -1 ; set J [file size test.db-journal] }
1146153eda0aSdan    catch { set W -1 ; set W [file size test.db-wal] }
1147153eda0aSdan    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
1148153eda0aSdan  }
114938e1a279Sdan}
1150153eda0aSdan
115189ccf448Sdando_test pager1-7.2.1 {
115289ccf448Sdan  faultsim_delete_and_reopen
115389ccf448Sdan  execsql {
115489ccf448Sdan    PRAGMA locking_mode = EXCLUSIVE;
115589ccf448Sdan    CREATE TABLE t1(a, b);
115689ccf448Sdan    BEGIN;
115789ccf448Sdan      PRAGMA journal_mode = delete;
115889ccf448Sdan      PRAGMA journal_mode = truncate;
115989ccf448Sdan  }
116089ccf448Sdan} {exclusive delete truncate}
116189ccf448Sdando_test pager1-7.2.2 {
116289ccf448Sdan  execsql { INSERT INTO t1 VALUES(1, 2) }
116389ccf448Sdan  execsql { PRAGMA journal_mode = persist }
116489ccf448Sdan} {truncate}
116589ccf448Sdando_test pager1-7.2.3 {
116689ccf448Sdan  execsql { COMMIT }
116789ccf448Sdan  execsql {
116889ccf448Sdan    PRAGMA journal_mode = persist;
116989ccf448Sdan    PRAGMA journal_size_limit;
117089ccf448Sdan  }
117189ccf448Sdan} {persist -1}
117289ccf448Sdan
1173d353331aSdan#-------------------------------------------------------------------------
1174d353331aSdan# The following tests, pager1-8.*, test that the special filenames
1175d353331aSdan# ":memory:" and "" open temporary databases.
1176d353331aSdan#
11770e986f51Sdanforeach {tn filename} {
11780e986f51Sdan  1 :memory:
11790e986f51Sdan  2 ""
11800e986f51Sdan} {
11810e986f51Sdan  do_test pager1-8.$tn.1 {
1182153eda0aSdan    faultsim_delete_and_reopen
1183153eda0aSdan    db close
11840e986f51Sdan    sqlite3 db $filename
1185153eda0aSdan    execsql {
1186c8ce3972Sdan      PRAGMA auto_vacuum = 1;
1187153eda0aSdan      CREATE TABLE x1(x);
1188153eda0aSdan      INSERT INTO x1 VALUES('Charles');
1189153eda0aSdan      INSERT INTO x1 VALUES('James');
1190153eda0aSdan      INSERT INTO x1 VALUES('Mary');
1191153eda0aSdan      SELECT * FROM x1;
1192153eda0aSdan    }
1193153eda0aSdan  } {Charles James Mary}
11940e986f51Sdan
11950e986f51Sdan  do_test pager1-8.$tn.2 {
11960e986f51Sdan    sqlite3 db2 $filename
11970e986f51Sdan    catchsql { SELECT * FROM x1 } db2
1198153eda0aSdan  } {1 {no such table: x1}}
1199153eda0aSdan
12000e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
12010e986f51Sdan    BEGIN;
12020e986f51Sdan      INSERT INTO x1 VALUES('William');
12030e986f51Sdan      INSERT INTO x1 VALUES('Anne');
12040e986f51Sdan    ROLLBACK;
12050e986f51Sdan  } {}
12060e986f51Sdan}
12070e986f51Sdan
1208dca321aeSdan#-------------------------------------------------------------------------
1209dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
1210dca321aeSdan# the pager and the backup API. Test cases:
1211dca321aeSdan#
1212dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
1213dca321aeSdan#                 source db is written to during the backup op.
1214dca321aeSdan#
1215dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
1216dca321aeSdan#                 source db is written to and then rolled back during a
1217dca321aeSdan#                 backup operation.
1218dca321aeSdan#
1219dca321aeSdando_test pager1-9.0.1 {
1220dca321aeSdan  faultsim_delete_and_reopen
1221dca321aeSdan  db func a_string a_string
1222dca321aeSdan  execsql {
1223dca321aeSdan    PRAGMA cache_size = 10;
1224dca321aeSdan    BEGIN;
1225dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1226dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1227dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1228dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1229dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1230dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1231dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1232dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1233dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1234dca321aeSdan    COMMIT;
1235dca321aeSdan  }
1236dca321aeSdan} {}
1237dca321aeSdando_test pager1-9.0.2 {
1238dca321aeSdan  sqlite3 db2 test.db2
1239dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1240dca321aeSdan  sqlite3_backup B db2 main db main
1241dca321aeSdan  list [B step 10000] [B finish]
1242dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1243dca321aeSdando_test pager1-9.0.3 {
1244dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1245dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1246dca321aeSdan
1247dca321aeSdando_test pager1-9.1.1 {
1248dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1249dca321aeSdan  sqlite3_backup B db2 main db main
1250dca321aeSdan  B step 30
1251dca321aeSdan} {SQLITE_OK}
1252dca321aeSdando_test pager1-9.1.2 {
1253dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1254dca321aeSdan  list [B step 10000] [B finish]
1255dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1256dca321aeSdando_test pager1-9.1.3 {
1257dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1258dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1259dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1260dca321aeSdan
1261dca321aeSdando_test pager1-9.2.1 {
1262dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1263dca321aeSdan  sqlite3_backup B db2 main db main
1264dca321aeSdan  B step 30
1265dca321aeSdan} {SQLITE_OK}
1266dca321aeSdando_test pager1-9.2.2 {
1267dca321aeSdan  execsql {
1268dca321aeSdan    BEGIN;
1269dca321aeSdan      UPDATE ab SET b = a_string(301);
1270dca321aeSdan    ROLLBACK;
1271dca321aeSdan  }
1272dca321aeSdan  list [B step 10000] [B finish]
1273dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1274dca321aeSdando_test pager1-9.2.3 {
1275dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1276dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1277dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1278ec6ffc1aSdandb close
1279ec6ffc1aSdandb2 close
1280ec6ffc1aSdan
1281c396d4afSdando_test pager1-9.3.1 {
1282c396d4afSdan  testvfs tv -default 1
1283c396d4afSdan  tv sectorsize 4096
1284c396d4afSdan  faultsim_delete_and_reopen
1285c396d4afSdan
1286c396d4afSdan  execsql { PRAGMA page_size = 1024 }
1287c396d4afSdan  for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
1288c396d4afSdan} {}
1289c396d4afSdando_test pager1-9.3.2 {
1290c396d4afSdan  sqlite3 db2 test.db2
1291f412ee2eSdan
1292c396d4afSdan  execsql {
1293c396d4afSdan    PRAGMA page_size = 4096;
1294c396d4afSdan    PRAGMA synchronous = OFF;
1295c396d4afSdan    CREATE TABLE t1(a, b);
1296c396d4afSdan    CREATE TABLE t2(a, b);
1297c396d4afSdan  } db2
1298c396d4afSdan
1299c396d4afSdan  sqlite3_backup B db2 main db main
1300c396d4afSdan  B step 30
1301c396d4afSdan  list [B step 10000] [B finish]
1302c396d4afSdan} {SQLITE_DONE SQLITE_OK}
1303c396d4afSdando_test pager1-9.3.3 {
1304c396d4afSdan  db2 close
1305c396d4afSdan  db close
1306c396d4afSdan  tv delete
1307c396d4afSdan  file size test.db2
1308c396d4afSdan} [file size test.db]
1309c396d4afSdan
1310f412ee2eSdando_test pager1-9.4.1 {
1311f412ee2eSdan  faultsim_delete_and_reopen
1312f412ee2eSdan  sqlite3 db2 test.db2
1313f412ee2eSdan  execsql {
1314f412ee2eSdan    PRAGMA page_size = 4096;
1315f412ee2eSdan    CREATE TABLE t1(a, b);
1316f412ee2eSdan    CREATE TABLE t2(a, b);
1317f412ee2eSdan  } db2
1318f412ee2eSdan  sqlite3_backup B db2 main db main
1319f412ee2eSdan  list [B step 10000] [B finish]
1320f412ee2eSdan} {SQLITE_DONE SQLITE_OK}
1321f412ee2eSdando_test pager1-9.4.2 {
1322f412ee2eSdan  list [file size test.db2] [file size test.db]
1323f412ee2eSdan} {0 0}
132433d85c9cSshanehdb2 close
1325d0b0d4dcSdan
1326ec6ffc1aSdan#-------------------------------------------------------------------------
1327ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1328ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1329ec6ffc1aSdan#
1330ec6ffc1aSdantestvfs tv -default 1
1331ec6ffc1aSdanforeach sectorsize {
1332ec6ffc1aSdan    32   64   128   256   512   1024   2048
1333ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1334ec6ffc1aSdan} {
1335ec6ffc1aSdan  tv sectorsize $sectorsize
13361eaaf93aSdrh  tv devchar {}
1337ec6ffc1aSdan  set eff $sectorsize
1338ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1339ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1340ec6ffc1aSdan
1341d0b0d4dcSdan  do_test pager1-10.$sectorsize.1 {
1342ec6ffc1aSdan    faultsim_delete_and_reopen
1343d0b0d4dcSdan    db func a_string a_string
1344ec6ffc1aSdan    execsql {
1345ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1346ec6ffc1aSdan      PRAGMA page_size = 1024;
1347d0b0d4dcSdan      BEGIN;
1348ec6ffc1aSdan        CREATE TABLE t1(a, b);
1349d0b0d4dcSdan        CREATE TABLE t2(a, b);
1350d0b0d4dcSdan        CREATE TABLE t3(a, b);
1351d0b0d4dcSdan      COMMIT;
1352ec6ffc1aSdan    }
1353ec6ffc1aSdan    file size test.db-journal
1354ec6ffc1aSdan  } [expr $sectorsize > 65536 ? 65536 : $sectorsize]
1355d0b0d4dcSdan
1356d0b0d4dcSdan  do_test pager1-10.$sectorsize.2 {
1357d0b0d4dcSdan    execsql {
1358d0b0d4dcSdan      INSERT INTO t3 VALUES(a_string(300), a_string(300));
1359d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  2 */
1360d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  4 */
1361d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /*  8 */
1362d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 16 */
1363d0b0d4dcSdan      INSERT INTO t3 SELECT * FROM t3;        /* 32 */
1364ec6ffc1aSdan    }
1365d0b0d4dcSdan  } {}
1366d0b0d4dcSdan
1367d0b0d4dcSdan  do_test pager1-10.$sectorsize.3 {
1368d0b0d4dcSdan    db close
1369d0b0d4dcSdan    sqlite3 db test.db
1370d0b0d4dcSdan    execsql {
1371d0b0d4dcSdan      PRAGMA cache_size = 10;
1372d0b0d4dcSdan      BEGIN;
1373d0b0d4dcSdan    }
1374d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
1375d0b0d4dcSdan    execsql {
1376d0b0d4dcSdan      COMMIT;
1377d0b0d4dcSdan      SELECT * FROM t2;
1378d0b0d4dcSdan    }
1379d0b0d4dcSdan  } {1 2}
1380d0b0d4dcSdan
1381d0b0d4dcSdan  do_test pager1-10.$sectorsize.4 {
1382d0b0d4dcSdan    execsql {
1383d0b0d4dcSdan      CREATE TABLE t6(a, b);
1384d0b0d4dcSdan      CREATE TABLE t7(a, b);
1385d0b0d4dcSdan      CREATE TABLE t5(a, b);
1386d0b0d4dcSdan      DROP TABLE t6;
1387d0b0d4dcSdan      DROP TABLE t7;
1388d0b0d4dcSdan    }
1389d0b0d4dcSdan    execsql {
1390d0b0d4dcSdan      BEGIN;
1391d0b0d4dcSdan        CREATE TABLE t6(a, b);
1392d0b0d4dcSdan    }
1393d0b0d4dcSdan    recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
1394d0b0d4dcSdan    execsql {
1395d0b0d4dcSdan      COMMIT;
1396d0b0d4dcSdan      SELECT * FROM t5;
1397d0b0d4dcSdan    }
1398d0b0d4dcSdan  } {1 2}
1399d0b0d4dcSdan
1400d0b0d4dcSdan}
1401d0b0d4dcSdandb close
1402d0b0d4dcSdan
1403d0b0d4dcSdantv sectorsize 4096
1404d0b0d4dcSdando_test pager1.10.x.1 {
1405d0b0d4dcSdan  faultsim_delete_and_reopen
1406d0b0d4dcSdan  execsql {
1407f43d7fceSdan    PRAGMA auto_vacuum = none;
1408d0b0d4dcSdan    PRAGMA page_size = 1024;
1409d0b0d4dcSdan    CREATE TABLE t1(x);
1410d0b0d4dcSdan  }
1411d0b0d4dcSdan  for {set i 0} {$i<30} {incr i} {
1412d0b0d4dcSdan    execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
1413d0b0d4dcSdan  }
1414d0b0d4dcSdan  file size test.db
1415d0b0d4dcSdan} {32768}
1416d0b0d4dcSdando_test pager1.10.x.2 {
1417d0b0d4dcSdan  execsql {
1418d0b0d4dcSdan    CREATE TABLE t2(x);
1419d0b0d4dcSdan    DROP TABLE t2;
1420d0b0d4dcSdan  }
1421d0b0d4dcSdan  file size test.db
1422d0b0d4dcSdan} {33792}
1423d0b0d4dcSdando_test pager1.10.x.3 {
1424d0b0d4dcSdan  execsql {
1425d0b0d4dcSdan    BEGIN;
1426d0b0d4dcSdan    CREATE TABLE t2(x);
1427d0b0d4dcSdan  }
1428d0b0d4dcSdan  recursive_select 30 t1
1429d0b0d4dcSdan  execsql {
1430d0b0d4dcSdan    CREATE TABLE t3(x);
1431d0b0d4dcSdan    COMMIT;
1432d0b0d4dcSdan  }
1433d0b0d4dcSdan} {}
1434d0b0d4dcSdan
1435ec6ffc1aSdandb close
1436ec6ffc1aSdantv delete
1437ec6ffc1aSdan
1438ec6ffc1aSdantestvfs tv -default 1
1439ec6ffc1aSdanfaultsim_delete_and_reopen
1440ec6ffc1aSdandb func a_string a_string
1441ec6ffc1aSdando_execsql_test pager1-11.1 {
14423f94b609Sdan  PRAGMA journal_mode = DELETE;
1443ec6ffc1aSdan  PRAGMA cache_size = 10;
1444ec6ffc1aSdan  BEGIN;
1445ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1446ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1447ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1448ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1449ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1450ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1451ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1452ec6ffc1aSdan  COMMIT;
1453ec6ffc1aSdan  BEGIN;
1454ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
14553f94b609Sdan} {delete}
1456ec6ffc1aSdan
1457ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1458ec6ffc1aSdantv script lockout
1459ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1460ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1461ec6ffc1aSdan
1462ec6ffc1aSdantv script {}
1463ec6ffc1aSdando_test pager1-11.3 {
1464ec6ffc1aSdan  sqlite3 db2 test.db
1465ec6ffc1aSdan  execsql {
1466ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1467ec6ffc1aSdan    PRAGMA integrity_check;
1468ec6ffc1aSdan  } db2
1469ec6ffc1aSdan} {truncate ok}
1470ec6ffc1aSdando_test pager1-11.4 {
1471ec6ffc1aSdan  db2 close
1472f6c61471Sdan  file exists test.db-journal
1473ec6ffc1aSdan} {0}
1474ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1475f9b4419dSdandb close
1476f9b4419dSdantv delete
1477ec6ffc1aSdan
1478f9b4419dSdan#-------------------------------------------------------------------------
1479f9b4419dSdan# Test "PRAGMA page_size"
1480f9b4419dSdan#
1481f43d7fceSdantestvfs tv -default 1
1482f43d7fceSdantv sectorsize 1024
1483f9b4419dSdanforeach pagesize {
1484f9b4419dSdan    512   1024   2048 4096 8192 16384 32768
1485f9b4419dSdan} {
1486f9b4419dSdan  faultsim_delete_and_reopen
1487f9b4419dSdan
1488f43d7fceSdan  # The sector-size (according to the VFS) is 1024 bytes. So if the
1489f43d7fceSdan  # page-size requested using "PRAGMA page_size" is greater than the
1490f43d7fceSdan  # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
1491f43d7fceSdan  # page-size remains 1024 bytes.
1492f43d7fceSdan  #
1493f43d7fceSdan  set eff $pagesize
1494f43d7fceSdan  if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
1495f43d7fceSdan
1496f9b4419dSdan  do_test pager1-12.$pagesize.1 {
1497f9b4419dSdan    sqlite3 db2 test.db
1498f9b4419dSdan    execsql "
1499f9b4419dSdan      PRAGMA page_size = $pagesize;
1500f9b4419dSdan      CREATE VIEW v AS SELECT * FROM sqlite_master;
1501f9b4419dSdan    " db2
1502f9b4419dSdan    file size test.db
1503f43d7fceSdan  } $eff
1504f9b4419dSdan  do_test pager1-12.$pagesize.2 {
1505f9b4419dSdan    sqlite3 db2 test.db
1506f9b4419dSdan    execsql {
1507f9b4419dSdan      SELECT count(*) FROM v;
1508f9b4419dSdan      PRAGMA main.page_size;
1509f9b4419dSdan    } db2
1510f43d7fceSdan  } [list 1 $eff]
1511f9b4419dSdan  do_test pager1-12.$pagesize.3 {
1512f9b4419dSdan    execsql {
1513f9b4419dSdan      SELECT count(*) FROM v;
1514f9b4419dSdan      PRAGMA main.page_size;
1515f9b4419dSdan    }
1516f43d7fceSdan  } [list 1 $eff]
1517f9b4419dSdan  db2 close
1518f9b4419dSdan}
1519f43d7fceSdandb close
1520f43d7fceSdantv delete
1521dca321aeSdan
1522d353331aSdan#-------------------------------------------------------------------------
1523d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases.
1524d353331aSdan#
1525d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent
1526d353331aSdan#                journal mode: If the journal associated with a transaction
1527d353331aSdan#                is smaller than the journal file (because a previous
1528d353331aSdan#                transaction left a very large non-hot journal file in the
1529d353331aSdan#                file-system), then SQLite has to be careful that there is
1530d353331aSdan#                not a journal-header left over from a previous transaction
1531d353331aSdan#                immediately following the journal content just written.
1532d353331aSdan#                If there is, and the process crashes so that the journal
1533d353331aSdan#                becomes a hot-journal and must be rolled back by another
1534d353331aSdan#                process, there is a danger that the other process may roll
1535d353331aSdan#                back the aborted transaction, then continue copying data
1536d353331aSdan#                from an older transaction from the remainder of the journal.
1537d353331aSdan#                See the syncJournal() function for details.
1538d353331aSdan#
1539d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into
1540d353331aSdan#                the mix to make the integrity-check more likely to catch
1541d353331aSdan#                errors.
1542d353331aSdan#
1543d353331aSdantestvfs tv -default 1
1544d353331aSdantv script xSyncCb
1545d353331aSdantv filter xSync
1546d353331aSdanproc xSyncCb {method filename args} {
1547d353331aSdan  set t [file tail $filename]
1548d353331aSdan  if {$t == "test.db"} faultsim_save
1549d353331aSdan  return SQLITE_OK
1550d353331aSdan}
1551d353331aSdanfaultsim_delete_and_reopen
1552d353331aSdandb func a_string a_string
1553e91a54e1Sdan
1554d353331aSdan# The UPDATE statement at the end of this test case creates a really big
1555d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains
1556d353331aSdan# frequent journal headers.
1557d353331aSdan#
1558d353331aSdando_execsql_test pager1-13.1.1 {
1559d353331aSdan  PRAGMA page_size = 1024;
1560d353331aSdan  PRAGMA journal_mode = PERSIST;
1561d353331aSdan  PRAGMA cache_size = 10;
1562d353331aSdan  BEGIN;
1563d353331aSdan    CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
1564d353331aSdan    INSERT INTO t1 VALUES(NULL, a_string(400));
1565d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   2 */
1566d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   4 */
1567d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*   8 */
1568d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  16 */
1569d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  32 */
1570d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /*  64 */
1571d353331aSdan    INSERT INTO t1 SELECT NULL, a_string(400) FROM t1;          /* 128 */
1572d353331aSdan  COMMIT;
1573d353331aSdan  UPDATE t1 SET b = a_string(400);
1574d353331aSdan} {persist}
1575d353331aSdan
1576b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1577d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one)
1578d353331aSdan# of these will write just enough content that one of the old headers created
1579d353331aSdan# by the transaction in the block above lies immediately after the content
1580d353331aSdan# journalled by the current transaction.
1581d353331aSdan#
1582d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1583d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.1 {
1584d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1585d353331aSdan  } {}
1586d353331aSdan  do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
1587d353331aSdan
1588d353331aSdan  # Try to access the snapshot of the file-system.
1589d353331aSdan  #
1590d353331aSdan  sqlite3 db2 sv_test.db
1591d353331aSdan  do_test pager1-13.1.2.$nUp.3 {
1592d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1593d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1594d353331aSdan  do_test pager1-13.1.2.$nUp.4 {
1595d353331aSdan    execsql { PRAGMA integrity_check } db2
1596d353331aSdan  } {ok}
1597d353331aSdan  db2 close
1598d353331aSdan}
1599b2f20bfcSshaneh}
1600d353331aSdan
1601b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} {
1602d353331aSdan# Same test as above. But this time with an index on the table.
1603d353331aSdan#
1604d353331aSdando_execsql_test pager1-13.2.1 {
1605d353331aSdan  CREATE INDEX i1 ON t1(b);
1606d353331aSdan  UPDATE t1 SET b = a_string(400);
1607d353331aSdan} {}
1608d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} {
1609d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.1 {
1610d353331aSdan    UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
1611d353331aSdan  } {}
1612d353331aSdan  do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
1613d353331aSdan  sqlite3 db2 sv_test.db
1614d353331aSdan  do_test pager1-13.2.2.$nUp.3 {
1615d353331aSdan    execsql { SELECT sum(length(b)) FROM t1 } db2
1616d353331aSdan  } [expr {128*400 - ($nUp-1)}]
1617d353331aSdan  do_test pager1-13.2.2.$nUp.4 {
1618d353331aSdan    execsql { PRAGMA integrity_check } db2
1619d353331aSdan  } {ok}
1620d353331aSdan  db2 close
1621d353331aSdan}
1622b2f20bfcSshaneh}
1623d353331aSdan
1624d353331aSdandb close
1625d353331aSdantv delete
1626d353331aSdan
1627d353331aSdan#-------------------------------------------------------------------------
1628d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases.
1629d353331aSdan#
1630d353331aSdanfaultsim_delete_and_reopen
1631d353331aSdando_execsql_test pager1-14.1.1 {
1632d353331aSdan  PRAGMA journal_mode = OFF;
1633d353331aSdan  CREATE TABLE t1(a, b);
1634d353331aSdan  BEGIN;
1635d353331aSdan    INSERT INTO t1 VALUES(1, 2);
1636d353331aSdan  COMMIT;
1637d353331aSdan  SELECT * FROM t1;
1638d353331aSdan} {off 1 2}
1639d353331aSdando_catchsql_test pager1-14.1.2 {
1640d353331aSdan  BEGIN;
1641d353331aSdan    INSERT INTO t1 VALUES(3, 4);
1642d353331aSdan  ROLLBACK;
1643d353331aSdan} {0 {}}
1644d353331aSdando_execsql_test pager1-14.1.3 {
1645d353331aSdan  SELECT * FROM t1;
1646354bfe03Sdan} {1 2}
1647d353331aSdando_catchsql_test pager1-14.1.4 {
1648d353331aSdan  BEGIN;
1649d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1650d353331aSdan    INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
1651d353331aSdan} {1 {PRIMARY KEY must be unique}}
1652d353331aSdando_execsql_test pager1-14.1.5 {
1653d353331aSdan  COMMIT;
1654d353331aSdan  SELECT * FROM t1;
1655354bfe03Sdan} {1 2 2 2}
1656d353331aSdan
1657c8ce3972Sdan#-------------------------------------------------------------------------
1658c8ce3972Sdan# Test opening and closing the pager sub-system with different values
1659c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable.
1660c8ce3972Sdan#
1661c8ce3972Sdanfaultsim_delete_and_reopen
1662c8ce3972Sdando_execsql_test pager1-15.0 {
1663c8ce3972Sdan  CREATE TABLE tx(y, z);
1664c8ce3972Sdan  INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
1665c8ce3972Sdan  INSERT INTO tx VALUES('London', 'Tokyo');
1666c8ce3972Sdan} {}
1667c8ce3972Sdandb close
1668c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} {
1669c8ce3972Sdan  testvfs tv -default 1 -szosfile $i
1670c8ce3972Sdan  sqlite3 db test.db
1671c8ce3972Sdan  do_execsql_test pager1-15.$i.1 {
1672c8ce3972Sdan    SELECT * FROM tx;
1673c8ce3972Sdan  } {Ayutthaya Beijing London Tokyo}
1674c8ce3972Sdan  db close
1675c8ce3972Sdan  tv delete
1676c8ce3972Sdan}
1677c8ce3972Sdan
1678c8ce3972Sdan#-------------------------------------------------------------------------
1679c8ce3972Sdan# Check that it is not possible to open a database file if the full path
1680c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname.
1681c8ce3972Sdan#
1682c8ce3972Sdantestvfs tv -default 1
1683c8ce3972Sdantv script xOpenCb
1684c8ce3972Sdantv filter xOpen
168533f5379cSdanproc xOpenCb {method filename args} {
1686c8ce3972Sdan  set ::file_len [string length $filename]
1687c8ce3972Sdan}
1688c8ce3972Sdansqlite3 db test.db
1689c8ce3972Sdandb close
1690c8ce3972Sdantv delete
1691c8ce3972Sdan
1692c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
1693c8ce3972Sdan  testvfs tv -default 1 -mxpathname $ii
1694c8ce3972Sdan
1695c8ce3972Sdan  # The length of the full path to file "test.db-journal" is ($::file_len+8).
1696c8ce3972Sdan  # If the configured sqlite3_vfs.mxPathname value greater than or equal to
1697c8ce3972Sdan  # this, then the file can be opened. Otherwise, it cannot.
1698c8ce3972Sdan  #
1699c8ce3972Sdan  if {$ii >= [expr $::file_len+8]} {
1700c8ce3972Sdan    set res {0 {}}
1701c8ce3972Sdan  } else {
1702c8ce3972Sdan    set res {1 {unable to open database file}}
1703c8ce3972Sdan  }
1704c8ce3972Sdan
1705c8ce3972Sdan  do_test pager1-16.1.$ii {
1706c8ce3972Sdan    list [catch { sqlite3 db test.db } msg] $msg
1707c8ce3972Sdan  } $res
1708c8ce3972Sdan
1709c8ce3972Sdan  catch {db close}
1710c8ce3972Sdan  tv delete
1711c8ce3972Sdan}
1712c8ce3972Sdan
1713c8ce3972Sdan
1714c8ce3972Sdan#-------------------------------------------------------------------------
1715c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page
1716c8ce3972Sdan# numbers:
1717c8ce3972Sdan#
1718c8ce3972Sdan#   + The locking page,
1719c8ce3972Sdan#   + Page 0,
1720c8ce3972Sdan#   + A page with a page number greater than (2^31-1).
1721c8ce3972Sdan#
1722f4ba1093Sdan# These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
1723f4ba1093Sdan# that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
1724f4ba1093Sdan#
1725f4ba1093Sdanifcapable !direct_read {
1726c8ce3972Sdando_test pager1-18.1 {
1727c8ce3972Sdan  faultsim_delete_and_reopen
1728c8ce3972Sdan  db func a_string a_string
1729c8ce3972Sdan  execsql {
1730c8ce3972Sdan    PRAGMA page_size = 1024;
1731c8ce3972Sdan    CREATE TABLE t1(a, b);
1732c8ce3972Sdan    INSERT INTO t1 VALUES(a_string(500), a_string(200));
1733c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1734c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1735c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1736c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1737c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1738c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1739c8ce3972Sdan    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
1740c8ce3972Sdan  }
1741c8ce3972Sdan} {}
1742c8ce3972Sdando_test pager1-18.2 {
1743c8ce3972Sdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1744c8ce3972Sdan  set lockingpage [expr (0x10000/1024) + 1]
1745c8ce3972Sdan  execsql {
1746c8ce3972Sdan    PRAGMA writable_schema = 1;
1747c8ce3972Sdan    UPDATE sqlite_master SET rootpage = $lockingpage;
1748c8ce3972Sdan  }
1749c8ce3972Sdan  sqlite3 db2 test.db
1750c8ce3972Sdan  catchsql { SELECT count(*) FROM t1 } db2
1751c8ce3972Sdan} {1 {database disk image is malformed}}
1752c8ce3972Sdandb2 close
1753c8ce3972Sdando_test pager1-18.3 {
1754c8ce3972Sdan  execsql {
1755c8ce3972Sdan    CREATE TABLE t2(x);
1756c8ce3972Sdan    INSERT INTO t2 VALUES(a_string(5000));
1757c8ce3972Sdan  }
1758c8ce3972Sdan  set pgno [expr ([file size test.db] / 1024)-2]
1759c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 00000000
1760c8ce3972Sdan  sqlite3 db2 test.db
1761c8ce3972Sdan  catchsql { SELECT length(x) FROM t2 } db2
1762c8ce3972Sdan} {1 {database disk image is malformed}}
1763c8ce3972Sdandb2 close
1764c8ce3972Sdando_test pager1-18.4 {
1765c8ce3972Sdan  hexio_write test.db [expr ($pgno-1)*1024] 90000000
1766c8ce3972Sdan  sqlite3 db2 test.db
1767c8ce3972Sdan  catchsql { SELECT length(x) FROM t2 } db2
1768c8ce3972Sdan} {1 {database disk image is malformed}}
1769c8ce3972Sdandb2 close
1770c8ce3972Sdando_test pager1-18.5 {
1771c8ce3972Sdan  sqlite3 db ""
1772c8ce3972Sdan  execsql {
1773c8ce3972Sdan    CREATE TABLE t1(a, b);
1774c8ce3972Sdan    CREATE TABLE t2(a, b);
1775c8ce3972Sdan    PRAGMA writable_schema = 1;
1776c8ce3972Sdan    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
1777c8ce3972Sdan    PRAGMA writable_schema = 0;
1778c8ce3972Sdan    ALTER TABLE t1 RENAME TO x1;
1779c8ce3972Sdan  }
1780c8ce3972Sdan  catchsql { SELECT * FROM x1 }
1781ba3cbf3dSdan} {1 {database disk image is malformed}}
1782c8ce3972Sdandb close
1783c8ce3972Sdan
1784ba3cbf3dSdando_test pager1-18.6 {
1785ba3cbf3dSdan  faultsim_delete_and_reopen
1786ba3cbf3dSdan  db func a_string a_string
1787ba3cbf3dSdan  execsql {
1788ba3cbf3dSdan    PRAGMA page_size = 1024;
1789ba3cbf3dSdan    CREATE TABLE t1(x);
1790ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1791ba3cbf3dSdan    INSERT INTO t1 VALUES(a_string(800));
1792ba3cbf3dSdan  }
1793ba3cbf3dSdan
1794ba3cbf3dSdan  set root [db one "SELECT rootpage FROM sqlite_master"]
1795ba3cbf3dSdan  db close
1796ba3cbf3dSdan
1797ba3cbf3dSdan  hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
1798ba3cbf3dSdan  sqlite3 db test.db
1799ba3cbf3dSdan  catchsql { SELECT length(x) FROM t1 }
1800ba3cbf3dSdan} {1 {database disk image is malformed}}
1801f4ba1093Sdan}
1802ba3cbf3dSdan
1803ba3cbf3dSdando_test pager1-19.1 {
1804ba3cbf3dSdan  sqlite3 db ""
1805ba3cbf3dSdan  db func a_string a_string
1806ba3cbf3dSdan  execsql {
1807ba3cbf3dSdan    PRAGMA page_size = 512;
1808ba3cbf3dSdan    PRAGMA auto_vacuum = 1;
1809ba3cbf3dSdan    CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1810ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1811ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1812ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1813ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1814ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1815ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1816ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1817ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1818ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1819ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1820ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1821ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1822ba3cbf3dSdan    );
1823ba3cbf3dSdan    CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
1824ba3cbf3dSdan                    ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
1825ba3cbf3dSdan                    ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
1826ba3cbf3dSdan                    da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
1827ba3cbf3dSdan                    ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
1828ba3cbf3dSdan                    fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
1829ba3cbf3dSdan                    ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
1830ba3cbf3dSdan                    ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
1831ba3cbf3dSdan                    ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
1832ba3cbf3dSdan                    ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
1833ba3cbf3dSdan                    ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
1834ba3cbf3dSdan                    la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
1835ba3cbf3dSdan                    ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
1836ba3cbf3dSdan    );
1837ba3cbf3dSdan    INSERT INTO t1(aa) VALUES( a_string(100000) );
1838ba3cbf3dSdan    INSERT INTO t2(aa) VALUES( a_string(100000) );
1839ba3cbf3dSdan    VACUUM;
1840ba3cbf3dSdan  }
1841ba3cbf3dSdan} {}
1842ba3cbf3dSdan
18436b63ab47Sdan#-------------------------------------------------------------------------
18446b63ab47Sdan# Test a couple of special cases that come up while committing
18456b63ab47Sdan# transactions:
18466b63ab47Sdan#
18476b63ab47Sdan#   pager1-20.1.*: Committing an in-memory database transaction when the
18486b63ab47Sdan#                  database has not been modified at all.
18496b63ab47Sdan#
18506b63ab47Sdan#   pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
18516b63ab47Sdan#
18526b63ab47Sdan#   pager1-20.3.*: Committing a transaction in WAL mode where the database has
18536b63ab47Sdan#                  been modified, but all dirty pages have been flushed to
18546b63ab47Sdan#                  disk before the commit.
18556b63ab47Sdan#
18566b63ab47Sdando_test pager1-20.1.1 {
18576b63ab47Sdan  catch {db close}
18586b63ab47Sdan  sqlite3 db :memory:
18596b63ab47Sdan  execsql {
18606b63ab47Sdan    CREATE TABLE one(two, three);
18616b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
18626b63ab47Sdan  }
18636b63ab47Sdan} {}
18646b63ab47Sdando_test pager1-20.1.2 {
18656b63ab47Sdan  execsql {
18666b63ab47Sdan    BEGIN EXCLUSIVE;
18676b63ab47Sdan    COMMIT;
18686b63ab47Sdan  }
18696b63ab47Sdan} {}
18706b63ab47Sdan
18716b63ab47Sdando_test pager1-20.2.1 {
18726b63ab47Sdan  faultsim_delete_and_reopen
18736b63ab47Sdan  execsql {
18746b63ab47Sdan    PRAGMA locking_mode = exclusive;
18756b63ab47Sdan    PRAGMA journal_mode = persist;
18766b63ab47Sdan    CREATE TABLE one(two, three);
18776b63ab47Sdan    INSERT INTO one VALUES('a', 'b');
18786b63ab47Sdan  }
18796b63ab47Sdan} {exclusive persist}
18806b63ab47Sdando_test pager1-20.2.2 {
18816b63ab47Sdan  execsql {
18826b63ab47Sdan    BEGIN EXCLUSIVE;
18836b63ab47Sdan    COMMIT;
18846b63ab47Sdan  }
18856b63ab47Sdan} {}
18866b63ab47Sdan
18879091f775Sshanehifcapable wal {
18886b63ab47Sdan  do_test pager1-20.3.1 {
18896b63ab47Sdan    faultsim_delete_and_reopen
18906b63ab47Sdan    db func a_string a_string
18916b63ab47Sdan    execsql {
18926b63ab47Sdan      PRAGMA cache_size = 10;
18936b63ab47Sdan      PRAGMA journal_mode = wal;
18946b63ab47Sdan      BEGIN;
18956b63ab47Sdan        CREATE TABLE t1(x);
18966b63ab47Sdan        CREATE TABLE t2(y);
18976b63ab47Sdan        INSERT INTO t1 VALUES(a_string(800));
18986b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   2 */
18996b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   4 */
19006b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*   8 */
19016b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  16 */
19026b63ab47Sdan        INSERT INTO t1 SELECT a_string(800) FROM t1;         /*  32 */
19036b63ab47Sdan      COMMIT;
19046b63ab47Sdan    }
19056b63ab47Sdan  } {wal}
19066b63ab47Sdan  do_test pager1-20.3.2 {
19076b63ab47Sdan    execsql {
19086b63ab47Sdan      BEGIN;
19096b63ab47Sdan      INSERT INTO t2 VALUES('xxxx');
19106b63ab47Sdan    }
1911c396d4afSdan    recursive_select 32 t1
19126b63ab47Sdan    execsql COMMIT
19136b63ab47Sdan  } {}
19149091f775Sshaneh}
19156b63ab47Sdan
191689ccf448Sdan#-------------------------------------------------------------------------
191789ccf448Sdan# Test that a WAL database may not be opened if:
191889ccf448Sdan#
191989ccf448Sdan#   pager1-21.1.*: The VFS has an iVersion less than 2, or
192089ccf448Sdan#   pager1-21.2.*: The VFS does not provide xShmXXX() methods.
192189ccf448Sdan#
19229091f775Sshanehifcapable wal {
192389ccf448Sdan  do_test pager1-21.0 {
192489ccf448Sdan    faultsim_delete_and_reopen
192589ccf448Sdan    execsql {
192689ccf448Sdan      PRAGMA journal_mode = WAL;
192789ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
192889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
192989ccf448Sdan    }
193089ccf448Sdan  } {wal}
193189ccf448Sdan  do_test pager1-21.1 {
193289ccf448Sdan    testvfs tv -noshm 1
193389ccf448Sdan    sqlite3 db2 test.db -vfs tv
193489ccf448Sdan    catchsql { SELECT * FROM ko } db2
193589ccf448Sdan  } {1 {unable to open database file}}
193689ccf448Sdan  db2 close
193789ccf448Sdan  tv delete
193889ccf448Sdan  do_test pager1-21.2 {
193989ccf448Sdan    testvfs tv -iversion 1
194089ccf448Sdan    sqlite3 db2 test.db -vfs tv
194189ccf448Sdan    catchsql { SELECT * FROM ko } db2
194289ccf448Sdan  } {1 {unable to open database file}}
194389ccf448Sdan  db2 close
194489ccf448Sdan  tv delete
19459091f775Sshaneh}
194689ccf448Sdan
194789ccf448Sdan#-------------------------------------------------------------------------
194889ccf448Sdan# Test that a "PRAGMA wal_checkpoint":
194989ccf448Sdan#
195089ccf448Sdan#   pager1-22.1.*: is a no-op on a non-WAL db, and
195189ccf448Sdan#   pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
195289ccf448Sdan#
19535209132aSdanifcapable wal {
195489ccf448Sdan  do_test pager1-22.1.1 {
195589ccf448Sdan    faultsim_delete_and_reopen
195689ccf448Sdan    execsql {
195789ccf448Sdan      CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
195889ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
195989ccf448Sdan    }
196089ccf448Sdan    execsql { PRAGMA wal_checkpoint }
1961bdd9af0fSdan  } {0 -1 -1}
196289ccf448Sdan  do_test pager1-22.2.1 {
196389ccf448Sdan    testvfs tv -default 1
196489ccf448Sdan    tv filter xSync
196589ccf448Sdan    tv script xSyncCb
196689ccf448Sdan    proc xSyncCb {args} {incr ::synccount}
196789ccf448Sdan    set ::synccount 0
196889ccf448Sdan    sqlite3 db test.db
196989ccf448Sdan    execsql {
197089ccf448Sdan      PRAGMA synchronous = off;
197189ccf448Sdan      PRAGMA journal_mode = WAL;
197289ccf448Sdan      INSERT INTO ko DEFAULT VALUES;
197389ccf448Sdan    }
197489ccf448Sdan    execsql { PRAGMA wal_checkpoint }
197589ccf448Sdan    set synccount
197689ccf448Sdan  } {0}
197789ccf448Sdan  db close
197889ccf448Sdan  tv delete
19795209132aSdan}
198089ccf448Sdan
198189ccf448Sdan#-------------------------------------------------------------------------
198289ccf448Sdan# Tests for changing journal mode.
198389ccf448Sdan#
198489ccf448Sdan#   pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
198589ccf448Sdan#                  the journal file is deleted.
198689ccf448Sdan#
198789ccf448Sdan#   pager1-23.2.*: Same test as above, but while a shared lock is held
198889ccf448Sdan#                  on the database file.
198989ccf448Sdan#
199089ccf448Sdan#   pager1-23.3.*: Same test as above, but while a reserved lock is held
199189ccf448Sdan#                  on the database file.
199289ccf448Sdan#
199389ccf448Sdan#   pager1-23.4.*: And, for fun, while holding an exclusive lock.
199489ccf448Sdan#
199589ccf448Sdan#   pager1-23.5.*: Try to set various different journal modes with an
199689ccf448Sdan#                  in-memory database (only MEMORY and OFF should work).
199789ccf448Sdan#
1998d0b0d4dcSdan#   pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
1999d0b0d4dcSdan#                  (doesn't work - in-memory databases always use
2000d0b0d4dcSdan#                  locking_mode=exclusive).
2001d0b0d4dcSdan#
200289ccf448Sdando_test pager1-23.1.1 {
200389ccf448Sdan  faultsim_delete_and_reopen
200489ccf448Sdan  execsql {
200589ccf448Sdan    PRAGMA journal_mode = PERSIST;
200689ccf448Sdan    CREATE TABLE t1(a, b);
200789ccf448Sdan  }
200889ccf448Sdan  file exists test.db-journal
200989ccf448Sdan} {1}
201089ccf448Sdando_test pager1-23.1.2 {
201189ccf448Sdan  execsql { PRAGMA journal_mode = DELETE }
201289ccf448Sdan  file exists test.db-journal
201389ccf448Sdan} {0}
201489ccf448Sdan
201589ccf448Sdando_test pager1-23.2.1 {
201689ccf448Sdan  execsql {
201789ccf448Sdan    PRAGMA journal_mode = PERSIST;
201889ccf448Sdan    INSERT INTO t1 VALUES('Canberra', 'ACT');
201989ccf448Sdan  }
202089ccf448Sdan  db eval { SELECT * FROM t1 } {
202189ccf448Sdan    db eval { PRAGMA journal_mode = DELETE }
202289ccf448Sdan  }
202389ccf448Sdan  execsql { PRAGMA journal_mode }
202489ccf448Sdan} {delete}
202589ccf448Sdando_test pager1-23.2.2 {
202689ccf448Sdan  file exists test.db-journal
202789ccf448Sdan} {0}
202889ccf448Sdan
202989ccf448Sdando_test pager1-23.3.1 {
203089ccf448Sdan  execsql {
203189ccf448Sdan    PRAGMA journal_mode = PERSIST;
203289ccf448Sdan    INSERT INTO t1 VALUES('Darwin', 'NT');
203389ccf448Sdan    BEGIN IMMEDIATE;
203489ccf448Sdan  }
203589ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
203689ccf448Sdan  execsql { PRAGMA journal_mode }
203789ccf448Sdan} {delete}
203889ccf448Sdando_test pager1-23.3.2 {
203989ccf448Sdan  file exists test.db-journal
204089ccf448Sdan} {0}
204189ccf448Sdando_test pager1-23.3.3 {
204289ccf448Sdan  execsql COMMIT
204389ccf448Sdan} {}
204489ccf448Sdan
204589ccf448Sdando_test pager1-23.4.1 {
204689ccf448Sdan  execsql {
204789ccf448Sdan    PRAGMA journal_mode = PERSIST;
204889ccf448Sdan    INSERT INTO t1 VALUES('Adelaide', 'SA');
204989ccf448Sdan    BEGIN EXCLUSIVE;
205089ccf448Sdan  }
205189ccf448Sdan  db eval { PRAGMA journal_mode = DELETE }
205289ccf448Sdan  execsql { PRAGMA journal_mode }
205389ccf448Sdan} {delete}
205489ccf448Sdando_test pager1-23.4.2 {
205589ccf448Sdan  file exists test.db-journal
205689ccf448Sdan} {0}
205789ccf448Sdando_test pager1-23.4.3 {
205889ccf448Sdan  execsql COMMIT
205989ccf448Sdan} {}
206089ccf448Sdan
206189ccf448Sdando_test pager1-23.5.1 {
206289ccf448Sdan  faultsim_delete_and_reopen
206389ccf448Sdan  sqlite3 db :memory:
206489ccf448Sdan} {}
206589ccf448Sdanforeach {tn mode possible} {
206689ccf448Sdan  2  off      1
206789ccf448Sdan  3  memory   1
206889ccf448Sdan  4  persist  0
206989ccf448Sdan  5  delete   0
207089ccf448Sdan  6  wal      0
207189ccf448Sdan  7  truncate 0
207289ccf448Sdan} {
207389ccf448Sdan  do_test pager1-23.5.$tn.1 {
207489ccf448Sdan    execsql "PRAGMA journal_mode = off"
207589ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
207689ccf448Sdan  } [if $possible {list $mode} {list off}]
207789ccf448Sdan  do_test pager1-23.5.$tn.2 {
207889ccf448Sdan    execsql "PRAGMA journal_mode = memory"
207989ccf448Sdan    execsql "PRAGMA journal_mode = $mode"
208089ccf448Sdan  } [if $possible {list $mode} {list memory}]
208189ccf448Sdan}
2082d0b0d4dcSdando_test pager1-23.6.1 {
208389ccf448Sdan  execsql {PRAGMA locking_mode = normal}
208489ccf448Sdan} {exclusive}
2085d0b0d4dcSdando_test pager1-23.6.2 {
208689ccf448Sdan  execsql {PRAGMA locking_mode = exclusive}
208789ccf448Sdan} {exclusive}
2088d0b0d4dcSdando_test pager1-23.6.3 {
208989ccf448Sdan  execsql {PRAGMA locking_mode}
209089ccf448Sdan} {exclusive}
2091d0b0d4dcSdando_test pager1-23.6.4 {
209289ccf448Sdan  execsql {PRAGMA main.locking_mode}
209389ccf448Sdan} {exclusive}
20946b63ab47Sdan
2095d0b0d4dcSdan#-------------------------------------------------------------------------
2096d0b0d4dcSdan#
2097d0b0d4dcSdando_test pager1-24.1.1 {
2098d0b0d4dcSdan  faultsim_delete_and_reopen
2099d0b0d4dcSdan  db func a_string a_string
2100d0b0d4dcSdan  execsql {
2101d0b0d4dcSdan    PRAGMA cache_size = 10;
2102d0b0d4dcSdan    PRAGMA auto_vacuum = FULL;
2103d0b0d4dcSdan    CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
2104d0b0d4dcSdan    CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
2105d0b0d4dcSdan    INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
2106d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2107d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2108d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2109d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
2110d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
2111d0b0d4dcSdan    INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
2112d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2113d0b0d4dcSdan  }
2114d0b0d4dcSdan} {}
2115d0b0d4dcSdando_test pager1-24.1.2 {
2116d0b0d4dcSdan  execsql {
2117d0b0d4dcSdan    BEGIN;
2118d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2119d0b0d4dcSdan  }
2120c396d4afSdan  recursive_select 64 x2
2121d0b0d4dcSdan} {}
2122d0b0d4dcSdando_test pager1-24.1.3 {
2123d0b0d4dcSdan  execsql {
2124d0b0d4dcSdan      UPDATE x1 SET z = a_string(300) WHERE rowid>40;
2125d0b0d4dcSdan    COMMIT;
2126d0b0d4dcSdan    PRAGMA integrity_check;
2127d0b0d4dcSdan    SELECT count(*) FROM x1;
2128d0b0d4dcSdan  }
2129d0b0d4dcSdan} {ok 33}
2130d0b0d4dcSdan
2131d0b0d4dcSdando_test pager1-24.1.4 {
2132d0b0d4dcSdan  execsql {
2133d0b0d4dcSdan    DELETE FROM x1;
2134d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2135d0b0d4dcSdan    BEGIN;
2136d0b0d4dcSdan      DELETE FROM x1 WHERE rowid<32;
2137d0b0d4dcSdan      UPDATE x1 SET z = a_string(299) WHERE rowid>40;
2138d0b0d4dcSdan  }
2139c396d4afSdan  recursive_select 64 x2 {db eval COMMIT}
2140d0b0d4dcSdan  execsql {
2141d0b0d4dcSdan    PRAGMA integrity_check;
2142d0b0d4dcSdan    SELECT count(*) FROM x1;
2143d0b0d4dcSdan  }
2144d0b0d4dcSdan} {ok 33}
2145d0b0d4dcSdan
2146d0b0d4dcSdando_test pager1-24.1.5 {
2147d0b0d4dcSdan  execsql {
2148d0b0d4dcSdan    DELETE FROM x1;
2149d0b0d4dcSdan    INSERT INTO x1 SELECT * FROM x2;
2150d0b0d4dcSdan  }
2151c396d4afSdan  recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
2152d0b0d4dcSdan  execsql { SELECT * FROM x3 }
2153d0b0d4dcSdan} {}
2154d0b0d4dcSdan
2155d0b0d4dcSdan#-------------------------------------------------------------------------
2156d0b0d4dcSdan#
2157d0b0d4dcSdando_test pager1-25-1 {
2158d0b0d4dcSdan  faultsim_delete_and_reopen
2159d0b0d4dcSdan  execsql {
2160d0b0d4dcSdan    BEGIN;
2161d0b0d4dcSdan      SAVEPOINT abc;
2162d0b0d4dcSdan        CREATE TABLE t1(a, b);
2163d0b0d4dcSdan      ROLLBACK TO abc;
2164d0b0d4dcSdan    COMMIT;
2165d0b0d4dcSdan  }
2166d0b0d4dcSdan  db close
2167d0b0d4dcSdan} {}
2168d0b0d4dcSdanbreakpoint
2169d0b0d4dcSdando_test pager1-25-2 {
2170d0b0d4dcSdan  faultsim_delete_and_reopen
2171d0b0d4dcSdan  execsql {
2172d0b0d4dcSdan    SAVEPOINT abc;
2173d0b0d4dcSdan      CREATE TABLE t1(a, b);
2174d0b0d4dcSdan    ROLLBACK TO abc;
2175d0b0d4dcSdan    COMMIT;
2176d0b0d4dcSdan  }
2177d0b0d4dcSdan  db close
2178d0b0d4dcSdan} {}
21796b63ab47Sdan
2180c396d4afSdan#-------------------------------------------------------------------------
2181c396d4afSdan# Sector-size tests.
2182c396d4afSdan#
2183c396d4afSdando_test pager1-26.1 {
2184c396d4afSdan  testvfs tv -default 1
2185c396d4afSdan  tv sectorsize 4096
2186c396d4afSdan  faultsim_delete_and_reopen
2187c396d4afSdan  db func a_string a_string
2188c396d4afSdan  execsql {
2189c396d4afSdan    PRAGMA page_size = 512;
2190c396d4afSdan    CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
2191c396d4afSdan    BEGIN;
2192c396d4afSdan      INSERT INTO tbl VALUES(a_string(25), a_string(600));
2193c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2194c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2195c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2196c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2197c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2198c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2199c396d4afSdan      INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
2200c396d4afSdan    COMMIT;
2201c396d4afSdan  }
2202c396d4afSdan} {}
2203c396d4afSdando_execsql_test pager1-26.1 {
2204c396d4afSdan  UPDATE tbl SET b = a_string(550);
2205c396d4afSdan} {}
2206c396d4afSdandb close
2207c396d4afSdantv delete
2208c396d4afSdan
2209c396d4afSdan#-------------------------------------------------------------------------
221022b328b2Sdan#
2211c396d4afSdando_test pager1.27.1 {
2212c396d4afSdan  faultsim_delete_and_reopen
2213c396d4afSdan  sqlite3_pager_refcounts db
2214c396d4afSdan  execsql {
2215c396d4afSdan    BEGIN;
2216c396d4afSdan      CREATE TABLE t1(a, b);
2217c396d4afSdan  }
2218c396d4afSdan  sqlite3_pager_refcounts db
2219c396d4afSdan  execsql COMMIT
2220c396d4afSdan} {}
2221c396d4afSdan
222222b328b2Sdan#-------------------------------------------------------------------------
222322b328b2Sdan# Test that attempting to open a write-transaction with
222422b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on
222522b328b2Sdan# the same database.
222622b328b2Sdan#
222722b328b2Sdancatch { db close }
22289091f775Sshanehifcapable wal {
222922b328b2Sdan  do_multiclient_test tn {
223022b328b2Sdan    do_test pager1-28.$tn.1 {
223122b328b2Sdan      sql1 {
223222b328b2Sdan        PRAGMA journal_mode = WAL;
223322b328b2Sdan        CREATE TABLE t1(a, b);
223422b328b2Sdan        INSERT INTO t1 VALUES('a', 'b');
223522b328b2Sdan      }
223622b328b2Sdan    } {wal}
223722b328b2Sdan    do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
223822b328b2Sdan
223922b328b2Sdan    do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
224022b328b2Sdan    do_test pager1-28.$tn.4 {
224122b328b2Sdan      csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
224222b328b2Sdan    } {1 {database is locked}}
224322b328b2Sdan    code2 { db2 close ; sqlite3 db2 test.db }
224422b328b2Sdan    do_test pager1-28.$tn.4 {
224522b328b2Sdan      sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
224622b328b2Sdan    } {}
224722b328b2Sdan  }
22489091f775Sshaneh}
22495653e4daSdan
22505653e4daSdan#-------------------------------------------------------------------------
22515653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager
22525653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a
22535653e4daSdan# RESERVED lock on the database file, this step is skipped.
22545653e4daSdan#
22555653e4daSdando_multiclient_test tn {
22565653e4daSdan  do_test pager1-28.$tn.1 {
22575653e4daSdan    sql1 {
22585653e4daSdan      PRAGMA journal_mode = PERSIST;
22595653e4daSdan      CREATE TABLE t1(a, b);
22605653e4daSdan      INSERT INTO t1 VALUES('a', 'b');
22615653e4daSdan    }
22625653e4daSdan  } {persist}
22635653e4daSdan  do_test pager1-28.$tn.2 { file exists test.db-journal } 1
22645653e4daSdan  do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
22655653e4daSdan  do_test pager1-28.$tn.4 { file exists test.db-journal } 0
22665653e4daSdan
22675653e4daSdan  do_test pager1-28.$tn.5 {
22685653e4daSdan    sql1 {
22695653e4daSdan      PRAGMA journal_mode = PERSIST;
22705653e4daSdan      INSERT INTO t1 VALUES('c', 'd');
22715653e4daSdan    }
22725653e4daSdan  } {persist}
22735653e4daSdan  do_test pager1-28.$tn.6 { file exists test.db-journal } 1
22745653e4daSdan  do_test pager1-28.$tn.7 {
22755653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
22765653e4daSdan  } {}
22775653e4daSdan  do_test pager1-28.$tn.8  { file exists test.db-journal } 1
22785653e4daSdan  do_test pager1-28.$tn.9  { sql1 { PRAGMA journal_mode = DELETE } } delete
22795653e4daSdan  do_test pager1-28.$tn.10 { file exists test.db-journal } 1
22805653e4daSdan
22815653e4daSdan  do_test pager1-28.$tn.11 { sql2 COMMIT } {}
22825653e4daSdan  do_test pager1-28.$tn.12 { file exists test.db-journal } 0
22835653e4daSdan
22845653e4daSdan  do_test pager1-28-$tn.13 {
22855653e4daSdan    code1 { set channel [db incrblob -readonly t1 a 2] }
22865653e4daSdan    sql1 {
22875653e4daSdan      PRAGMA journal_mode = PERSIST;
22885653e4daSdan      INSERT INTO t1 VALUES('g', 'h');
22895653e4daSdan    }
22905653e4daSdan  } {persist}
22915653e4daSdan  do_test pager1-28.$tn.14 { file exists test.db-journal } 1
22925653e4daSdan  do_test pager1-28.$tn.15 {
22935653e4daSdan    sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
22945653e4daSdan  } {}
22955653e4daSdan  do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
22965653e4daSdan  do_test pager1-28.$tn.17 { file exists test.db-journal } 1
22975653e4daSdan
22985653e4daSdan  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
22995653e4daSdan  do_test pager1-28-$tn.18 { code1 { read $channel } } c
23005653e4daSdan  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
23015653e4daSdan  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
23025653e4daSdan}
23035653e4daSdan
23041879b088Sdando_test pager1-29.1 {
23051879b088Sdan  faultsim_delete_and_reopen
23061879b088Sdan  execsql {
23071879b088Sdan    PRAGMA page_size = 1024;
23081879b088Sdan    PRAGMA auto_vacuum = full;
23091879b088Sdan    PRAGMA locking_mode=exclusive;
23101879b088Sdan    CREATE TABLE t1(a, b);
23111879b088Sdan    INSERT INTO t1 VALUES(1, 2);
23121879b088Sdan  }
23131879b088Sdan  file size test.db
23141879b088Sdan} [expr 1024*3]
23151879b088Sdando_test pager1-29.2 {
23161879b088Sdan  execsql {
23171879b088Sdan    PRAGMA page_size = 4096;
23181879b088Sdan    VACUUM;
23191879b088Sdan  }
23201879b088Sdan  file size test.db
23211879b088Sdan} [expr 4096*3]
23221879b088Sdan
2323e08c2066Sdan#-------------------------------------------------------------------------
2324e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in
2325e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system
2326e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while
2327e08c2066Sdan# doing this is not released.
2328e08c2066Sdan#
2329e08c2066Sdando_test pager1-30.1 {
2330e08c2066Sdan  db close
2331fda06befSmistachkin  delete_file test.db
2332fda06befSmistachkin  delete_file test.db-journal
2333e08c2066Sdan  set fd [open test.db-journal w]
2334e08c2066Sdan  seek $fd [expr 512+1032*2]
2335e08c2066Sdan  puts -nonewline $fd x
2336e08c2066Sdan  close $fd
2337e08c2066Sdan
2338e08c2066Sdan  sqlite3 db test.db
2339e08c2066Sdan  execsql {
2340e08c2066Sdan    PRAGMA locking_mode=EXCLUSIVE;
2341e08c2066Sdan    SELECT count(*) FROM sqlite_master;
2342e08c2066Sdan    PRAGMA lock_status;
2343e08c2066Sdan  }
2344e08c2066Sdan} {exclusive 0 main reserved temp closed}
2345e08c2066Sdan
2346e08c2066Sdan#-------------------------------------------------------------------------
2347e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal
2348e08c2066Sdan# file can still be rolled back. This is required for backward compatibility -
2349e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero.
2350e08c2066Sdan#
235133f5379cSdanif {$tcl_platform(platform)=="unix"} {
2352e08c2066Sdando_test pager1-31.1 {
2353e08c2066Sdan  faultsim_delete_and_reopen
2354e08c2066Sdan  execsql {
2355e08c2066Sdan    PRAGMA cache_size = 10;
2356e08c2066Sdan    PRAGMA page_size = 1024;
2357e08c2066Sdan    CREATE TABLE t1(x, y, UNIQUE(x, y));
2358e08c2066Sdan    INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
2359e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2360e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2361e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2362e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2363e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2364e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2365e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2366e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2367e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2368e08c2066Sdan    INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
2369e08c2066Sdan    BEGIN;
2370e08c2066Sdan      UPDATE t1 SET y = randomblob(1499);
2371e08c2066Sdan  }
2372fda06befSmistachkin  copy_file test.db test.db2
2373fda06befSmistachkin  copy_file test.db-journal test.db2-journal
2374e08c2066Sdan
2375e08c2066Sdan  hexio_write test.db2-journal 24 00000000
2376e08c2066Sdan  sqlite3 db2 test.db2
2377e08c2066Sdan  execsql { PRAGMA integrity_check } db2
2378e08c2066Sdan} {ok}
237933f5379cSdan}
2380e08c2066Sdan
238131e80976Sdrh#-------------------------------------------------------------------------
238231e80976Sdrh# Test that a database file can be "pre-hinted" to a certain size and that
238331e80976Sdrh# subsequent spilling of the pager cache does not result in the database
238431e80976Sdrh# file being shrunk.
238531e80976Sdrh#
238631e80976Sdrhcatch {db close}
238731e80976Sdrhforcedelete test.db
238831e80976Sdrh
238931e80976Sdrhdo_test pager1-32.1 {
239031e80976Sdrh  sqlite3 db test.db
239131e80976Sdrh  execsql {
239231e80976Sdrh    CREATE TABLE t1(x, y);
239331e80976Sdrh  }
239431e80976Sdrh  db close
239531e80976Sdrh  sqlite3 db test.db
239631e80976Sdrh  execsql {
239731e80976Sdrh    BEGIN;
239831e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
239931e80976Sdrh  }
24002f7820d8Sdrh  file_control_chunksize_test db main 1024
240131e80976Sdrh  file_control_sizehint_test db main 20971520; # 20MB
240231e80976Sdrh  execsql {
240331e80976Sdrh    PRAGMA cache_size = 10;
240431e80976Sdrh    INSERT INTO t1 VALUES(1, randomblob(10000));
240531e80976Sdrh    INSERT INTO t1 VALUES(2, randomblob(10000));
240631e80976Sdrh    INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
240731e80976Sdrh    INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
240831e80976Sdrh    INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
240931e80976Sdrh    INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
241031e80976Sdrh    SELECT count(*) FROM t1;
241131e80976Sdrh    COMMIT;
241231e80976Sdrh  }
241331e80976Sdrh  db close
241431e80976Sdrh  file size test.db
241531e80976Sdrh} {20971520}
241631e80976Sdrh
241731e80976Sdrh# Cleanup 20MB file left by the previous test.
241831e80976Sdrhforcedelete test.db
24195653e4daSdan
2420d353331aSdanfinish_test
2421