xref: /sqlite-3.40.0/test/pager1.test (revision ec6ffc1a)
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#
43*ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to
44*ec6ffc1aSdan#              64KB.
45*ec6ffc1aSdan#
46*ec6ffc1aSdan#
47b0ac3e3aSdan
4853f04f3bSdanset a_string_counter 1
4953f04f3bSdanproc a_string {n} {
5053f04f3bSdan  global a_string_counter
5153f04f3bSdan  incr a_string_counter
5253f04f3bSdan  string range [string repeat "${a_string_counter}." $n] 1 $n
5353f04f3bSdan}
5453f04f3bSdandb func a_string a_string
5553f04f3bSdan
56a4a9095eSdando_multiclient_test tn {
57e91a54e1Sdan
58e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
59e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
60e91a54e1Sdan  #
61e91a54e1Sdan  do_test pager1-$tn.1 {
62e91a54e1Sdan    sql1 {
63e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
64e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
65e91a54e1Sdan      INSERT INTO t1 VALUES(1, 'one');
66e91a54e1Sdan      INSERT INTO t1 VALUES(2, 'two');
67e91a54e1Sdan    }
68e91a54e1Sdan  } {}
69e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
70e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
71e91a54e1Sdan
72e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
73e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
74e91a54e1Sdan  # read the database content as it was before the transaction was
75e91a54e1Sdan  # opened. [db] should see the inserted row.
76e91a54e1Sdan  #
77e91a54e1Sdan  do_test pager1-$tn.4 {
78e91a54e1Sdan    sql1 {
79e91a54e1Sdan      BEGIN;
80e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
81e91a54e1Sdan    }
82e91a54e1Sdan  } {}
83e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
84e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
85e91a54e1Sdan
86e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
87e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
88e91a54e1Sdan  #
89e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
90e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
91e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
92e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
93e91a54e1Sdan  #
94e91a54e1Sdan  do_test pager1-$tn.8 {
95e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
96e91a54e1Sdan  } {1 {database is locked}}
97e91a54e1Sdan  do_test pager1-$tn.9 {
98e91a54e1Sdan    csql2 {
99e91a54e1Sdan      BEGIN;
100e91a54e1Sdan      UPDATE t1 SET a = a + 10;
101e91a54e1Sdan    }
102e91a54e1Sdan  } {1 {database is locked}}
103e91a54e1Sdan
104e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
105e91a54e1Sdan  # now see the new database content.
106e91a54e1Sdan  #
107e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
108e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
109e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
110e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
111e91a54e1Sdan
112e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
113e91a54e1Sdan  # after the attempt to write the database failed.
114e91a54e1Sdan  #
115e91a54e1Sdan  do_test pager1-$tn.14 {
116e91a54e1Sdan    csql2 { BEGIN }
117e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
118e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
119e91a54e1Sdan
120e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
121e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
122e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
123e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
124e91a54e1Sdan  #
125e91a54e1Sdan  do_test pager1-$tn.15 {
126e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
127e91a54e1Sdan  } {1 one 2 two 3 three}
128e91a54e1Sdan  do_test pager1-$tn.16 {
129e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
130e91a54e1Sdan  } {1 {database is locked}}
131e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
132e91a54e1Sdan
133e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
134e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
135e91a54e1Sdan  # the SHARED lock [db2] is holding.
136e91a54e1Sdan  #
137e91a54e1Sdan  do_test pager1-$tn.18 {
138e91a54e1Sdan    sql1 {
139e91a54e1Sdan      BEGIN;
140e91a54e1Sdan      UPDATE t1 SET a = a + 10;
141e91a54e1Sdan    }
142e91a54e1Sdan  } {}
143e91a54e1Sdan  do_test pager1-$tn-19 {
144e91a54e1Sdan    sql1 { PRAGMA lock_status }
145e91a54e1Sdan  } {main reserved temp closed}
146e91a54e1Sdan  do_test pager1-$tn-20 {
147e91a54e1Sdan    sql2 { PRAGMA lock_status }
148e91a54e1Sdan  } {main shared temp closed}
149e91a54e1Sdan
150e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
151e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
152e91a54e1Sdan  #
153e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
154e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
155e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
156e91a54e1Sdan
157e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
158e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
159e91a54e1Sdan  # upgrades to a PENDING lock.
160e91a54e1Sdan  #
161e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
162e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
163e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
164e91a54e1Sdan  # the database.
165e91a54e1Sdan  #
166e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
167e91a54e1Sdan  do_test pager1-$tn-25 {
168e91a54e1Sdan    sql1 { PRAGMA lock_status }
169e91a54e1Sdan  } {main pending temp closed}
170e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
171e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
172e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
173e91a54e1Sdan
174e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
175e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
176e91a54e1Sdan  # is still holding a PENDING).
177e91a54e1Sdan  #
178e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
179e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
180e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
181e91a54e1Sdan
182e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
183e91a54e1Sdan  # committed, all three connections can read the new content.
184e91a54e1Sdan  #
185e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
186e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
187e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
188e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
189e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
190e91a54e1Sdan}
191e91a54e1Sdan
19253f04f3bSdan#-------------------------------------------------------------------------
19353f04f3bSdan# Savepoint related test cases.
19453f04f3bSdan#
195dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file
196dca321aeSdan#                 to grow.
197dca321aeSdan#
1980e986f51Sdando_test pager1-3.1.1 {
199b0ac3e3aSdan  faultsim_delete_and_reopen
200b0ac3e3aSdan  execsql {
201b0ac3e3aSdan    CREATE TABLE t1(a PRIMARY KEY, b);
202b0ac3e3aSdan    CREATE TABLE counter(
203b0ac3e3aSdan      i CHECK (i<5),
204b0ac3e3aSdan      u CHECK (u<10)
205b0ac3e3aSdan    );
206b0ac3e3aSdan    INSERT INTO counter VALUES(0, 0);
207b0ac3e3aSdan    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
208b0ac3e3aSdan      UPDATE counter SET i = i+1;
209b0ac3e3aSdan    END;
210b0ac3e3aSdan    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
211b0ac3e3aSdan      UPDATE counter SET u = u+1;
212b0ac3e3aSdan    END;
213b0ac3e3aSdan  }
214b0ac3e3aSdan  execsql { SELECT * FROM counter }
215b0ac3e3aSdan} {0 0}
216b0ac3e3aSdan
2170e986f51Sdando_execsql_test pager1-3.1.2 {
218b0ac3e3aSdan  BEGIN;
219b0ac3e3aSdan    INSERT INTO t1 VALUES(1, randomblob(1500));
220b0ac3e3aSdan    INSERT INTO t1 VALUES(2, randomblob(1500));
221b0ac3e3aSdan    INSERT INTO t1 VALUES(3, randomblob(1500));
222b0ac3e3aSdan    SELECT * FROM counter;
223b0ac3e3aSdan} {3 0}
2240e986f51Sdando_catchsql_test pager1-3.1.3 {
225b0ac3e3aSdan    INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
226b0ac3e3aSdan} {1 {constraint failed}}
227b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
228b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
229b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {}
230b0ac3e3aSdan
231dca321aeSdando_test pager1-3.2.1 {
232dca321aeSdan  faultsim_delete_and_reopen
233dca321aeSdan  db func a_string a_string
234dca321aeSdan  execsql {
235dca321aeSdan    PRAGMA auto_vacuum = 2;
236dca321aeSdan    PRAGMA cache_size = 10;
237dca321aeSdan    CREATE TABLE z(x INTEGER PRIMARY KEY, y);
238dca321aeSdan    BEGIN;
239dca321aeSdan      INSERT INTO z VALUES(NULL, a_string(800));
240dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   2
241dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   4
242dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     --   8
243dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  16
244dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  32
245dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     --  64
246dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 128
247dca321aeSdan      INSERT INTO z SELECT NULL, a_string(800) FROM z;     -- 256
248dca321aeSdan    COMMIT;
249dca321aeSdan  }
250dca321aeSdan  execsql { PRAGMA auto_vacuum }
251dca321aeSdan} {2}
252dca321aeSdando_execsql_test pager1-3.2.2 {
253dca321aeSdan  BEGIN;
254dca321aeSdan    INSERT INTO z VALUES(NULL, a_string(800));
255dca321aeSdan    INSERT INTO z VALUES(NULL, a_string(800));
256dca321aeSdan    SAVEPOINT one;
257dca321aeSdan      DELETE FROM z WHERE x>256;
258dca321aeSdan      PRAGMA incremental_vacuum;
259dca321aeSdan      SELECT count(*) FROM z WHERE x < 100;
260dca321aeSdan    ROLLBACK TO one;
261dca321aeSdan  COMMIT;
262dca321aeSdan} {99}
263dca321aeSdan
26453f04f3bSdan#-------------------------------------------------------------------------
26553f04f3bSdan# Hot journal rollback related test cases.
26653f04f3bSdan#
26753f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid
26853f04f3bSdan#               journal files.
26953f04f3bSdan#
27053f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a
27153f04f3bSdan#               hot-journal file appears to be corrupt (checksum does not
27253f04f3bSdan#               compute) the associated journal is rolled back (and no
27353f04f3bSdan#               xAccess() call to check for the presence of any master
27453f04f3bSdan#               journal file is made).
27553f04f3bSdan#
276de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
277de4996e2Sdan#               page-size or sector-size in the journal header appear to
278de4996e2Sdan#               be invalid (too large, too small or not a power of 2).
279de4996e2Sdan#
280e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master
281e08341c6Sdan#               journal pointer generated in various "PRAGMA synchronous"
282e08341c6Sdan#               modes.
283e08341c6Sdan#
284e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
285e08341c6Sdan#               journal-record for which the checksum fails.
286e08341c6Sdan#
287*ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a
288*ec6ffc1aSdan#               master journal pointer, the master journal file is deleted
289*ec6ffc1aSdan#               after all the hot-journals that refer to it are deleted.
290*ec6ffc1aSdan#
29153f04f3bSdando_test pager1.4.1.1 {
29253f04f3bSdan  faultsim_delete_and_reopen
29353f04f3bSdan  execsql {
29453f04f3bSdan    CREATE TABLE x(y, z);
29553f04f3bSdan    INSERT INTO x VALUES(1, 2);
29653f04f3bSdan  }
29753f04f3bSdan  set fd [open test.db-journal w]
29853f04f3bSdan  puts -nonewline $fd "helloworld"
29953f04f3bSdan  close $fd
30053f04f3bSdan  file exists test.db-journal
30153f04f3bSdan} {1}
30253f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
30353f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0}
30453f04f3bSdan
30553f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite
30653f04f3bSdan# deletes the master-journal to commit a multi-file transaction.
30753f04f3bSdan#
30853f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
30953f04f3bSdan# up the file system to contain two databases, two hot-journal files and
31053f04f3bSdan# a master-journal.
31153f04f3bSdan#
31253f04f3bSdando_test pager1.4.2.1 {
31353f04f3bSdan  testvfs tstvfs -default 1
31453f04f3bSdan  tstvfs filter xDelete
31553f04f3bSdan  tstvfs script xDeleteCallback
31653f04f3bSdan  proc xDeleteCallback {method file args} {
31753f04f3bSdan    set file [file tail $file]
31853f04f3bSdan    if { [string match *mj* $file] } { faultsim_save }
31953f04f3bSdan  }
32053f04f3bSdan  faultsim_delete_and_reopen
32153f04f3bSdan  db func a_string a_string
32253f04f3bSdan  execsql {
32353f04f3bSdan    ATTACH 'test.db2' AS aux;
32453f04f3bSdan    PRAGMA journal_mode = DELETE;
32553f04f3bSdan    PRAGMA main.cache_size = 10;
32653f04f3bSdan    PRAGMA aux.cache_size = 10;
32753f04f3bSdan    CREATE TABLE t1(a UNIQUE, b UNIQUE);
32853f04f3bSdan    CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
32953f04f3bSdan    INSERT INTO t1 VALUES(a_string(200), a_string(300));
33053f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
33153f04f3bSdan    INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
33253f04f3bSdan    INSERT INTO t2 SELECT * FROM t1;
33353f04f3bSdan    BEGIN;
33453f04f3bSdan      INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
33553f04f3bSdan      INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
33653f04f3bSdan      INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
33753f04f3bSdan      INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
33853f04f3bSdan      REPLACE INTO t2 SELECT * FROM t1;
33953f04f3bSdan    COMMIT;
34053f04f3bSdan  }
34153f04f3bSdan  db close
34253f04f3bSdan  tstvfs delete
34353f04f3bSdan} {}
34453f04f3bSdando_test pager1.4.2.2 {
34553f04f3bSdan  faultsim_restore_and_reopen
34653f04f3bSdan  execsql {
34753f04f3bSdan    SELECT count(*) FROM t1;
34853f04f3bSdan    PRAGMA integrity_check;
34953f04f3bSdan  }
35053f04f3bSdan} {4 ok}
35153f04f3bSdando_test pager1.4.2.3 {
35253f04f3bSdan  faultsim_restore_and_reopen
35353f04f3bSdan  foreach f [glob test.db-mj*] { file delete -force $f }
35453f04f3bSdan  execsql {
35553f04f3bSdan    SELECT count(*) FROM t1;
35653f04f3bSdan    PRAGMA integrity_check;
35753f04f3bSdan  }
35853f04f3bSdan} {64 ok}
35953f04f3bSdando_test pager1.4.2.4 {
36053f04f3bSdan  faultsim_restore_and_reopen
36153f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
36253f04f3bSdan  execsql {
36353f04f3bSdan    SELECT count(*) FROM t1;
36453f04f3bSdan    PRAGMA integrity_check;
36553f04f3bSdan  }
36653f04f3bSdan} {4 ok}
36753f04f3bSdando_test pager1.4.2.5 {
36853f04f3bSdan  faultsim_restore_and_reopen
36953f04f3bSdan  hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456
37053f04f3bSdan  foreach f [glob test.db-mj*] { file delete -force $f }
37153f04f3bSdan  execsql {
37253f04f3bSdan    SELECT count(*) FROM t1;
37353f04f3bSdan    PRAGMA integrity_check;
37453f04f3bSdan  }
37553f04f3bSdan} {4 ok}
37653f04f3bSdan
377de4996e2Sdando_test pager1.4.3.1 {
378de4996e2Sdan  testvfs tstvfs -default 1
379de4996e2Sdan  tstvfs filter xSync
380de4996e2Sdan  tstvfs script xSyncCallback
381de4996e2Sdan  proc xSyncCallback {method file args} {
382de4996e2Sdan    set file [file tail $file]
383de4996e2Sdan    if { 0==[string match *journal $file] } { faultsim_save }
384de4996e2Sdan  }
385de4996e2Sdan  faultsim_delete_and_reopen
386de4996e2Sdan  execsql {
387de4996e2Sdan    PRAGMA journal_mode = DELETE;
388de4996e2Sdan    CREATE TABLE t1(a, b);
389de4996e2Sdan    INSERT INTO t1 VALUES(1, 2);
390de4996e2Sdan    INSERT INTO t1 VALUES(3, 4);
391de4996e2Sdan  }
392de4996e2Sdan  db close
393de4996e2Sdan  tstvfs delete
394de4996e2Sdan} {}
395de4996e2Sdan
396de4996e2Sdanforeach {tn ofst value result} {
397de4996e2Sdan          2   20    31       {1 2 3 4}
398de4996e2Sdan          3   20    32       {1 2 3 4}
399de4996e2Sdan          4   20    33       {1 2 3 4}
400de4996e2Sdan          5   20    65536    {1 2 3 4}
401de4996e2Sdan          6   20    131072   {1 2 3 4}
402de4996e2Sdan
403de4996e2Sdan          7   24    511      {1 2 3 4}
404de4996e2Sdan          8   24    513      {1 2 3 4}
405de4996e2Sdan          9   24    65536    {1 2 3 4}
406de4996e2Sdan
407de4996e2Sdan         10   32    65536    {1 2}
408de4996e2Sdan} {
409de4996e2Sdan  do_test pager1.4.3.$tn {
410de4996e2Sdan    faultsim_restore_and_reopen
411de4996e2Sdan    hexio_write test.db-journal $ofst [format %.8x $value]
412de4996e2Sdan    execsql { SELECT * FROM t1 }
413de4996e2Sdan  } $result
414de4996e2Sdan}
415de4996e2Sdandb close
416de4996e2Sdan
417e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal
418e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the
419e08341c6Sdan# file-system is saved just before the xDelete() call to remove the
420e08341c6Sdan# master journal file from the file-system.
421e08341c6Sdan#
422e08341c6Sdantestvfs tv -default 1
423e08341c6Sdantv script copy_on_mj_delete
424e08341c6Sdanset ::mj_filename_length 0
425e08341c6Sdanproc copy_on_mj_delete {method filename args} {
426e08341c6Sdan  if {[string match *mj* [file tail $filename]]} {
427e08341c6Sdan    set ::mj_filename_length [string length $filename]
428e08341c6Sdan    faultsim_save
429e08341c6Sdan  }
430e08341c6Sdan  return SQLITE_OK
431e08341c6Sdan}
432e08341c6Sdan
433e08341c6Sdanset pwd [pwd]
434e08341c6Sdanforeach {tn1 tcl} {
435e08341c6Sdan  1 { set prefix "test.db" }
436e08341c6Sdan  2 {
437e08341c6Sdan    # This test depends on the underlying VFS being able to open paths
438e08341c6Sdan    # 512 bytes in length. The idea is to create a hot-journal file that
439e08341c6Sdan    # contains a master-journal pointer so large that it could contain
440e08341c6Sdan    # a valid page record (if the file page-size is 512 bytes). So as to
441e08341c6Sdan    # make sure SQLite doesn't get confused by this.
442e08341c6Sdan    #
443e08341c6Sdan    set nPadding [expr 511 - $::mj_filename_length]
444e08341c6Sdan
445e08341c6Sdan    # We cannot just create a really long database file name to open, as
446e08341c6Sdan    # Linux limits a single component of a path to 255 bytes by default
447e08341c6Sdan    # (and presumably other systems have limits too). So create a directory
448e08341c6Sdan    # hierarchy to work in.
449e08341c6Sdan    #
450e08341c6Sdan    set dirname "d123456789012345678901234567890/"
451e08341c6Sdan    set nDir [expr $nPadding / 32]
452e08341c6Sdan    if { $nDir } {
453e08341c6Sdan      set p [string repeat $dirname $nDir]
454e08341c6Sdan      file mkdir $p
455e08341c6Sdan      cd $p
456e08341c6Sdan    }
457e08341c6Sdan
458e08341c6Sdan    set padding [string repeat x [expr $nPadding %32]]
459e08341c6Sdan    set prefix "test.db${padding}"
460e08341c6Sdan  }
461e08341c6Sdan} {
462e08341c6Sdan  eval $tcl
463e08341c6Sdan  foreach {tn2 sql} {
464e08341c6Sdan    o {
465e08341c6Sdan      PRAGMA main.synchronous=OFF;
466e08341c6Sdan      PRAGMA aux.synchronous=OFF;
467e08341c6Sdan    }
468e08341c6Sdan    o512 {
469e08341c6Sdan      PRAGMA main.synchronous=OFF;
470e08341c6Sdan      PRAGMA aux.synchronous=OFF;
471e08341c6Sdan      PRAGMA main.page_size = 512;
472e08341c6Sdan      PRAGMA aux.page_size = 512;
473e08341c6Sdan    }
474e08341c6Sdan    n {
475e08341c6Sdan      PRAGMA main.synchronous=NORMAL;
476e08341c6Sdan      PRAGMA aux.synchronous=NORMAL;
477e08341c6Sdan    }
478e08341c6Sdan    f {
479e08341c6Sdan      PRAGMA main.synchronous=FULL;
480e08341c6Sdan      PRAGMA aux.synchronous=FULL;
481e08341c6Sdan    }
482e08341c6Sdan  } {
483e08341c6Sdan
484e08341c6Sdan    set tn "${tn1}.${tn2}"
485e08341c6Sdan
486e08341c6Sdan    # Set up a connection to have two databases, test.db (main) and
487e08341c6Sdan    # test.db2 (aux). Then run a multi-file transaction on them. The
488e08341c6Sdan    # VFS will snapshot the file-system just before the master-journal
489e08341c6Sdan    # file is deleted to commit the transaction.
490e08341c6Sdan    #
491e08341c6Sdan    tv filter xDelete
492e08341c6Sdan    do_test pager1-4.4.$tn.1 {
493e08341c6Sdan      faultsim_delete_and_reopen $prefix
494e08341c6Sdan      execsql "
495e08341c6Sdan        ATTACH '${prefix}2' AS aux;
496e08341c6Sdan        $sql
497e08341c6Sdan        CREATE TABLE a(x);
498e08341c6Sdan        CREATE TABLE aux.b(x);
499e08341c6Sdan        INSERT INTO a VALUES('double-you');
500e08341c6Sdan        INSERT INTO a VALUES('why');
501e08341c6Sdan        INSERT INTO a VALUES('zed');
502e08341c6Sdan        INSERT INTO b VALUES('won');
503e08341c6Sdan        INSERT INTO b VALUES('too');
504e08341c6Sdan        INSERT INTO b VALUES('free');
505e08341c6Sdan      "
506e08341c6Sdan      execsql {
507e08341c6Sdan        BEGIN;
508e08341c6Sdan          INSERT INTO a SELECT * FROM b WHERE rowid<=3;
509e08341c6Sdan          INSERT INTO b SELECT * FROM a WHERE rowid<=3;
510e08341c6Sdan        COMMIT;
511e08341c6Sdan      }
512e08341c6Sdan    } {}
513e08341c6Sdan    tv filter {}
514e08341c6Sdan
515e08341c6Sdan    # Check that the transaction was committed successfully.
516e08341c6Sdan    #
517e08341c6Sdan    do_execsql_test pager1-4.4.$tn.2 {
518e08341c6Sdan      SELECT * FROM a
519e08341c6Sdan    } {double-you why zed won too free}
520e08341c6Sdan    do_execsql_test pager1-4.4.$tn.3 {
521e08341c6Sdan      SELECT * FROM b
522e08341c6Sdan    } {won too free double-you why zed}
523e08341c6Sdan
524e08341c6Sdan    # Restore the file-system and reopen the databases. Check that it now
525e08341c6Sdan    # appears that the transaction was not committed (because the file-system
526e08341c6Sdan    # was restored to the state where it had not been).
527e08341c6Sdan    #
528e08341c6Sdan    do_test pager1-4.4.$tn.4 {
529e08341c6Sdan      faultsim_restore_and_reopen $prefix
530e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
531e08341c6Sdan    } {}
532e08341c6Sdan    do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
533e08341c6Sdan    do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
534e08341c6Sdan
535e08341c6Sdan    # Restore the file-system again. This time, before reopening the databases,
536e08341c6Sdan    # delete the master-journal file from the file-system. It now appears that
537e08341c6Sdan    # the transaction was committed (no master-journal file == no rollback).
538e08341c6Sdan    #
539e08341c6Sdan    do_test pager1-4.4.$tn.7 {
540e08341c6Sdan      faultsim_restore_and_reopen $prefix
541e08341c6Sdan      foreach f [glob ${prefix}-mj*] { file delete -force $f }
542e08341c6Sdan      execsql "ATTACH '${prefix}2' AS aux"
543e08341c6Sdan    } {}
544e08341c6Sdan    do_execsql_test pager1-4.4.$tn.8 {
545e08341c6Sdan      SELECT * FROM a
546e08341c6Sdan    } {double-you why zed won too free}
547e08341c6Sdan    do_execsql_test pager1-4.4.$tn.9 {
548e08341c6Sdan      SELECT * FROM b
549e08341c6Sdan    } {won too free double-you why zed}
550e08341c6Sdan  }
551e08341c6Sdan
552e08341c6Sdan  cd $pwd
553e08341c6Sdan}
554e08341c6Sdandb close
555e08341c6Sdantv delete
5560e986f51Sdanfile delete -force $dirname
5570e986f51Sdan
5580e986f51Sdan
5590e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a
5600e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly
5610e986f51Sdan# two database pages (and page 1 - the change counter).
5620e986f51Sdan#
5630e986f51Sdantestvfs tv -default 1
5640e986f51Sdantv sectorsize 512
5650e986f51Sdantv script copy_on_journal_delete
5660e986f51Sdantv filter xDelete
5670e986f51Sdanset ::mj_filename_length 0
5680e986f51Sdanproc copy_on_journal_delete {method filename args} {
5690e986f51Sdan  if {[string match *journal $filename]} faultsim_save
5700e986f51Sdan  return SQLITE_OK
5710e986f51Sdan}
5720e986f51Sdanfaultsim_delete_and_reopen
5730e986f51Sdando_execsql_test pager1.4.5.1 {
5740e986f51Sdan  PRAGMA page_size = 1024;
5750e986f51Sdan  CREATE TABLE t1(a, b);
5760e986f51Sdan  CREATE TABLE t2(a, b);
5770e986f51Sdan  INSERT INTO t1 VALUES('I', 'II');
5780e986f51Sdan  INSERT INTO t2 VALUES('III', 'IV');
5790e986f51Sdan  BEGIN;
5800e986f51Sdan    INSERT INTO t1 VALUES(1, 2);
5810e986f51Sdan    INSERT INTO t2 VALUES(3, 4);
5820e986f51Sdan  COMMIT;
5830e986f51Sdan} {}
5840e986f51Sdantv filter {}
5850e986f51Sdan
5860e986f51Sdan# Check the transaction was committed:
5870e986f51Sdan#
5880e986f51Sdando_execsql_test pager1.4.5.2 {
5890e986f51Sdan  SELECT * FROM t1;
5900e986f51Sdan  SELECT * FROM t2;
5910e986f51Sdan} {I II 1 2 III IV 3 4}
5920e986f51Sdan
593*ec6ffc1aSdan# Now try four tests:
5940e986f51Sdan#
5950e986f51Sdan#  pager1-4.5.3: Restore the file-system. Check that the whole transaction
5960e986f51Sdan#                is rolled back.
5970e986f51Sdan#
5980e986f51Sdan#  pager1-4.5.4: Restore the file-system. Corrupt the first record in the
5990e986f51Sdan#                journal. Check the transaction is not rolled back.
6000e986f51Sdan#
6010e986f51Sdan#  pager1-4.5.5: Restore the file-system. Corrupt the second record in the
6020e986f51Sdan#                journal. Check that the first record in the transaction is
6030e986f51Sdan#                played back, but not the second.
6040e986f51Sdan#
60510f5a50eSdan#  pager1-4.5.6: Restore the file-system. Try to open the database with a
60610f5a50eSdan#                readonly connection. This should fail, as a read-only
60710f5a50eSdan#                connection cannot roll back the database file.
60810f5a50eSdan#
6090e986f51Sdanfaultsim_restore_and_reopen
6100e986f51Sdando_execsql_test pager1.4.5.3 {
6110e986f51Sdan  SELECT * FROM t1;
6120e986f51Sdan  SELECT * FROM t2;
6130e986f51Sdan} {I II III IV}
6140e986f51Sdanfaultsim_restore_and_reopen
6150e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
6160e986f51Sdando_execsql_test pager1.4.5.4 {
6170e986f51Sdan  SELECT * FROM t1;
6180e986f51Sdan  SELECT * FROM t2;
6190e986f51Sdan} {I II 1 2 III IV 3 4}
6200e986f51Sdanfaultsim_restore_and_reopen
6210e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
6220e986f51Sdando_execsql_test pager1.4.5.5 {
6230e986f51Sdan  SELECT * FROM t1;
6240e986f51Sdan  SELECT * FROM t2;
6250e986f51Sdan} {I II III IV 3 4}
6260e986f51Sdan
62710f5a50eSdanfaultsim_restore_and_reopen
62810f5a50eSdandb close
62910f5a50eSdansqlite3 db test.db -readonly 1
63010f5a50eSdando_catchsql_test pager1.4.5.6 {
63110f5a50eSdan  SELECT * FROM t1;
63210f5a50eSdan  SELECT * FROM t2;
63310f5a50eSdan} {1 {disk I/O error}}
634*ec6ffc1aSdandb close
635*ec6ffc1aSdan
636*ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name
637*ec6ffc1aSdan# of the master journal file in $::mj_filename.
638*ec6ffc1aSdan#
639*ec6ffc1aSdantv script copy_on_mj_delete
640*ec6ffc1aSdantv filter xDelete
641*ec6ffc1aSdanproc copy_on_mj_delete {method filename args} {
642*ec6ffc1aSdan  if {[string match *mj* [file tail $filename]]} {
643*ec6ffc1aSdan    set ::mj_filename $filename
644*ec6ffc1aSdan    faultsim_save
645*ec6ffc1aSdan  }
646*ec6ffc1aSdan  return SQLITE_OK
647*ec6ffc1aSdan}
648*ec6ffc1aSdando_test pager1.4.6.1 {
649*ec6ffc1aSdan  faultsim_delete_and_reopen
650*ec6ffc1aSdan  execsql {
651*ec6ffc1aSdan    ATTACH 'test.db2' AS two;
652*ec6ffc1aSdan    CREATE TABLE t1(a, b);
653*ec6ffc1aSdan    CREATE TABLE two.t2(a, b);
654*ec6ffc1aSdan    INSERT INTO t1 VALUES(1, 't1.1');
655*ec6ffc1aSdan    INSERT INTO t2 VALUES(1, 't2.1');
656*ec6ffc1aSdan    BEGIN;
657*ec6ffc1aSdan      UPDATE t1 SET b = 't1.2';
658*ec6ffc1aSdan      UPDATE t2 SET b = 't2.2';
659*ec6ffc1aSdan    COMMIT;
660*ec6ffc1aSdan  }
661*ec6ffc1aSdan  tv filter {}
662*ec6ffc1aSdan  db close
663*ec6ffc1aSdan} {}
664*ec6ffc1aSdan
665*ec6ffc1aSdanfaultsim_restore_and_reopen
666*ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 }           {1 t1.1}
667*ec6ffc1aSdando_test         pager1.4.6.3 { file exists $::mj_filename } {1}
668*ec6ffc1aSdando_execsql_test pager1.4.6.4 {
669*ec6ffc1aSdan  ATTACH 'test.db2' AS two;
670*ec6ffc1aSdan  SELECT * FROM t2;
671*ec6ffc1aSdan} {1 t2.1}
672*ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0}
673*ec6ffc1aSdan
674*ec6ffc1aSdanfaultsim_restore_and_reopen
675*ec6ffc1aSdandb close
676*ec6ffc1aSdando_test pager1.4.6.8 {
677*ec6ffc1aSdan  set ::mj_filename1 $::mj_filename
678*ec6ffc1aSdan  tv filter xDelete
679*ec6ffc1aSdan  sqlite3 db test.db2
680*ec6ffc1aSdan  execsql {
681*ec6ffc1aSdan    ATTACH 'test.db3' AS three;
682*ec6ffc1aSdan    CREATE TABLE three.t3(a, b);
683*ec6ffc1aSdan    INSERT INTO t3 VALUES(1, 't3.1');
684*ec6ffc1aSdan    BEGIN;
685*ec6ffc1aSdan      UPDATE t2 SET b = 't2.3';
686*ec6ffc1aSdan      UPDATE t3 SET b = 't3.3';
687*ec6ffc1aSdan    COMMIT;
688*ec6ffc1aSdan  }
689*ec6ffc1aSdan  expr {$::mj_filename1 != $::mj_filename}
690*ec6ffc1aSdan} {1}
691*ec6ffc1aSdanfaultsim_restore_and_reopen
692*ec6ffc1aSdantv filter {}
693*ec6ffc1aSdan
694*ec6ffc1aSdan# The file-system now contains:
695*ec6ffc1aSdan#
696*ec6ffc1aSdan#   * three databases
697*ec6ffc1aSdan#   * three hot-journal files
698*ec6ffc1aSdan#   * two master-journal files.
699*ec6ffc1aSdan#
700*ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to
701*ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with
702*ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from
703*ec6ffc1aSdan# test.db should delete $::mj_filename1.
704*ec6ffc1aSdan#
705*ec6ffc1aSdando_test pager1.4.6.9 {
706*ec6ffc1aSdan  lsort [glob test.db*]
707*ec6ffc1aSdan} [lsort [list                                           \
708*ec6ffc1aSdan  test.db test.db2 test.db3                              \
709*ec6ffc1aSdan  test.db-journal test.db2-journal test.db3-journal      \
710*ec6ffc1aSdan  [file tail $::mj_filename] [file tail $::mj_filename1]
711*ec6ffc1aSdan]]
712*ec6ffc1aSdan
713*ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and
714*ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to
715*ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should
716*ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1.
717*ec6ffc1aSdan#
718*ec6ffc1aSdando_test         pager1.4.6.10 { file exists $::mj_filename  } {1}
719*ec6ffc1aSdando_test         pager1.4.6.11 { file exists $::mj_filename1 } {1}
720*ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
721*ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename  } {1}
722*ec6ffc1aSdando_test         pager1.4.6.14 { file exists $::mj_filename1 } {0}
723*ec6ffc1aSdan
724*ec6ffc1aSdando_execsql_test pager1.4.6.12 {
725*ec6ffc1aSdan  ATTACH 'test.db2' AS two;
726*ec6ffc1aSdan  SELECT * FROM t2;
727*ec6ffc1aSdan} {1 t2.1}
728*ec6ffc1aSdando_test         pager1.4.6.13 { file exists $::mj_filename }  {1}
729*ec6ffc1aSdando_execsql_test pager1.4.6.14 {
730*ec6ffc1aSdan  ATTACH 'test.db3' AS three;
731*ec6ffc1aSdan  SELECT * FROM t3;
732*ec6ffc1aSdan} {1 t3.1}
733*ec6ffc1aSdando_test         pager1.4.6.15 { file exists $::mj_filename }  {0}
73410f5a50eSdan
7350e986f51Sdandb close
7360e986f51Sdantv delete
737e08341c6Sdan
738de4996e2Sdan#-------------------------------------------------------------------------
739146ed78bSdan# The following tests deal with multi-file commits.
740de4996e2Sdan#
741146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because
742146ed78bSdan#               another connection is holding a SHARED lock on one of the
743146ed78bSdan#               files. After the SHARED lock is removed, the COMMIT succeeds.
744146ed78bSdan#
745146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory.
746146ed78bSdan#
747146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory.
748146ed78bSdan#
749146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
750146ed78bSdan#               name is added to a journal file immediately after the last
751146ed78bSdan#               journal record. But with synchronous=full, extra unused space
752146ed78bSdan#               is allocated between the last journal record and the
753146ed78bSdan#               master-journal file name so that the master-journal file
754146ed78bSdan#               name does not lie on the same sector as the last journal file
755146ed78bSdan#               record.
756146ed78bSdan#
757e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
758e08341c6Sdan#               truncated to zero bytes when a multi-file transaction is
759e08341c6Sdan#               committed (instead of the first couple of bytes being zeroed).
760e08341c6Sdan#
761146ed78bSdan#
762146ed78bSdando_test pager1-5.1.1 {
763146ed78bSdan  faultsim_delete_and_reopen
764146ed78bSdan  execsql {
765146ed78bSdan    ATTACH 'test.db2' AS aux;
766146ed78bSdan    CREATE TABLE t1(a, b);
767146ed78bSdan    CREATE TABLE aux.t2(a, b);
768146ed78bSdan    INSERT INTO t1 VALUES(17, 'Lenin');
769146ed78bSdan    INSERT INTO t1 VALUES(22, 'Stalin');
770146ed78bSdan    INSERT INTO t1 VALUES(53, 'Khrushchev');
771146ed78bSdan  }
772146ed78bSdan} {}
773146ed78bSdando_test pager1-5.1.2 {
774146ed78bSdan  execsql {
775146ed78bSdan    BEGIN;
776146ed78bSdan      INSERT INTO t1 VALUES(64, 'Brezhnev');
777146ed78bSdan      INSERT INTO t2 SELECT * FROM t1;
778146ed78bSdan  }
779146ed78bSdan  sqlite3 db2 test.db2
780146ed78bSdan  execsql {
781146ed78bSdan    BEGIN;
782146ed78bSdan      SELECT * FROM t2;
783146ed78bSdan  } db2
784146ed78bSdan} {}
785146ed78bSdando_test pager1-5.1.3 {
786146ed78bSdan  catchsql COMMIT
787146ed78bSdan} {1 {database is locked}}
788146ed78bSdando_test pager1-5.1.4 {
789146ed78bSdan  execsql COMMIT db2
790146ed78bSdan  execsql COMMIT
791146ed78bSdan  execsql { SELECT * FROM t2 } db2
792146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
793146ed78bSdando_test pager1-5.1.5 {
794146ed78bSdan  db2 close
795146ed78bSdan} {}
796146ed78bSdan
797146ed78bSdando_test pager1-5.2.1 {
798146ed78bSdan  execsql {
799146ed78bSdan    PRAGMA journal_mode = memory;
800146ed78bSdan    BEGIN;
801146ed78bSdan      INSERT INTO t1 VALUES(84, 'Andropov');
802146ed78bSdan      INSERT INTO t2 VALUES(84, 'Andropov');
803146ed78bSdan    COMMIT;
804146ed78bSdan  }
805146ed78bSdan} {memory}
806146ed78bSdando_test pager1-5.3.1 {
807146ed78bSdan  execsql {
808146ed78bSdan    PRAGMA journal_mode = off;
809146ed78bSdan    BEGIN;
810146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
811146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
812146ed78bSdan    COMMIT;
813146ed78bSdan  }
814146ed78bSdan} {off}
815146ed78bSdan
816146ed78bSdando_test pager1-5.4.1 {
817146ed78bSdan  db close
818146ed78bSdan  testvfs tv
819146ed78bSdan  sqlite3 db test.db -vfs tv
820146ed78bSdan  execsql { ATTACH 'test.db2' AS aux }
821146ed78bSdan
822146ed78bSdan  tv filter xDelete
823146ed78bSdan  tv script max_journal_size
824146ed78bSdan  tv sectorsize 512
825146ed78bSdan  set ::max_journal 0
826146ed78bSdan  proc max_journal_size {method args} {
827146ed78bSdan    set sz 0
828146ed78bSdan    catch { set sz [file size test.db-journal] }
829146ed78bSdan    if {$sz > $::max_journal} {
830146ed78bSdan      set ::max_journal $sz
831146ed78bSdan    }
832146ed78bSdan    return SQLITE_OK
833146ed78bSdan  }
834146ed78bSdan  execsql {
835146ed78bSdan    PRAGMA journal_mode = DELETE;
836146ed78bSdan    PRAGMA synchronous = NORMAL;
837146ed78bSdan    BEGIN;
838146ed78bSdan      INSERT INTO t1 VALUES(85, 'Gorbachev');
839146ed78bSdan      INSERT INTO t2 VALUES(85, 'Gorbachev');
840146ed78bSdan    COMMIT;
841146ed78bSdan  }
842146ed78bSdan  set ::max_journal
843146ed78bSdan} [expr 2615+[string length [pwd]]]
844146ed78bSdando_test pager1-5.4.2 {
845146ed78bSdan  set ::max_journal 0
846146ed78bSdan  execsql {
847146ed78bSdan    PRAGMA synchronous = full;
848146ed78bSdan    BEGIN;
849146ed78bSdan      DELETE FROM t1 WHERE b = 'Lenin';
850146ed78bSdan      DELETE FROM t2 WHERE b = 'Lenin';
851146ed78bSdan    COMMIT;
852146ed78bSdan  }
853146ed78bSdan  set ::max_journal
854146ed78bSdan} [expr 3111+[string length [pwd]]]
855146ed78bSdandb close
856146ed78bSdantv delete
857146ed78bSdan
858146ed78bSdando_test pager1-5.5.1 {
859146ed78bSdan  sqlite3 db test.db
860146ed78bSdan  execsql {
861146ed78bSdan    ATTACH 'test.db2' AS aux;
862146ed78bSdan    PRAGMA journal_mode = PERSIST;
863146ed78bSdan    CREATE TABLE t3(a, b);
864146ed78bSdan    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
865146ed78bSdan    UPDATE t3 SET b = randomblob(1500);
866146ed78bSdan  }
867146ed78bSdan  expr [file size test.db-journal] > 15000
868146ed78bSdan} {1}
869146ed78bSdando_test pager1-5.5.2 {
870146ed78bSdan  execsql {
871146ed78bSdan    PRAGMA synchronous = full;
872146ed78bSdan    BEGIN;
873146ed78bSdan      DELETE FROM t1 WHERE b = 'Stalin';
874146ed78bSdan      DELETE FROM t2 WHERE b = 'Stalin';
875146ed78bSdan    COMMIT;
876146ed78bSdan  }
877146ed78bSdan  file size test.db-journal
878146ed78bSdan} {0}
879146ed78bSdan
880146ed78bSdan
881146ed78bSdan#-------------------------------------------------------------------------
882146ed78bSdan# The following tests work with "PRAGMA max_page_count"
883146ed78bSdan#
884146ed78bSdando_test pager1-6.1 {
885146ed78bSdan  faultsim_delete_and_reopen
886146ed78bSdan  execsql {
887146ed78bSdan    PRAGMA max_page_count = 10;
888146ed78bSdan    CREATE TABLE t2(a, b);
889146ed78bSdan    CREATE TABLE t3(a, b);
890146ed78bSdan    CREATE TABLE t4(a, b);
891146ed78bSdan    CREATE TABLE t5(a, b);
892146ed78bSdan    CREATE TABLE t6(a, b);
893146ed78bSdan    CREATE TABLE t7(a, b);
894146ed78bSdan    CREATE TABLE t8(a, b);
895146ed78bSdan    CREATE TABLE t9(a, b);
896146ed78bSdan    CREATE TABLE t10(a, b);
897146ed78bSdan  }
898146ed78bSdan} {10}
899146ed78bSdando_test pager1-6.2 {
900146ed78bSdan  catchsql {
901146ed78bSdan    CREATE TABLE t11(a, b);
902146ed78bSdan  }
903146ed78bSdan} {1 {database or disk is full}}
904de4996e2Sdan
905153eda0aSdan
906153eda0aSdan#-------------------------------------------------------------------------
907153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
908153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE".
909153eda0aSdan#
910153eda0aSdan# Each test is specified with 5 variables. As follows:
911153eda0aSdan#
912153eda0aSdan#   $tn:  Test Number. Used as part of the [do_test] test names.
913153eda0aSdan#   $sql: SQL to execute.
914153eda0aSdan#   $res: Expected result of executing $sql.
915153eda0aSdan#   $js:  The expected size of the journal file, in bytes, after executing
916153eda0aSdan#         the SQL script. Or -1 if the journal is not expected to exist.
917153eda0aSdan#   $ws:  The expected size of the WAL file, in bytes, after executing
918153eda0aSdan#         the SQL script. Or -1 if the WAL is not expected to exist.
919153eda0aSdan#
920153eda0aSdanfaultsim_delete_and_reopen
921153eda0aSdanforeach {tn sql res js ws} [subst {
922153eda0aSdan
923153eda0aSdan  1  {
924153eda0aSdan    CREATE TABLE t1(a, b);
925153eda0aSdan    PRAGMA auto_vacuum=OFF;
926153eda0aSdan    PRAGMA synchronous=NORMAL;
927153eda0aSdan    PRAGMA page_size=1024;
928153eda0aSdan    PRAGMA locking_mode=EXCLUSIVE;
929153eda0aSdan    PRAGMA journal_mode=TRUNCATE;
930153eda0aSdan    INSERT INTO t1 VALUES(1, 2);
931153eda0aSdan  } {exclusive truncate} 0 -1
932153eda0aSdan
933153eda0aSdan  2  {
934153eda0aSdan    BEGIN IMMEDIATE;
935153eda0aSdan      SELECT * FROM t1;
936153eda0aSdan    COMMIT;
937153eda0aSdan  } {1 2} 0 -1
938153eda0aSdan
939153eda0aSdan  3  {
940153eda0aSdan    BEGIN;
941153eda0aSdan      SELECT * FROM t1;
942153eda0aSdan    COMMIT;
943153eda0aSdan  } {1 2} 0 -1
944153eda0aSdan
945153eda0aSdan  4  { PRAGMA journal_mode = WAL }    wal    -1 -1
946153eda0aSdan  5  { INSERT INTO t1 VALUES(3, 4) }  {}     -1 [wal_file_size 1 1024]
947153eda0aSdan  6  { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024]
948153eda0aSdan  7  { INSERT INTO t1 VALUES(5, 6); } {}     -1 [wal_file_size 2 1024]
949153eda0aSdan
950153eda0aSdan  8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
951153eda0aSdan  9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
952153eda0aSdan  10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
953153eda0aSdan
954153eda0aSdan}] {
955153eda0aSdan  do_execsql_test pager1-7.1.$tn.1 $sql $res
956153eda0aSdan  catch { set J -1 ; set J [file size test.db-journal] }
957153eda0aSdan  catch { set W -1 ; set W [file size test.db-wal] }
958153eda0aSdan  do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
959153eda0aSdan}
960153eda0aSdan
9610e986f51Sdanforeach {tn filename} {
9620e986f51Sdan  1 :memory:
9630e986f51Sdan  2 ""
9640e986f51Sdan} {
9650e986f51Sdan  do_test pager1-8.$tn.1 {
966153eda0aSdan    faultsim_delete_and_reopen
967153eda0aSdan    db close
9680e986f51Sdan    sqlite3 db $filename
969153eda0aSdan    execsql {
970153eda0aSdan      CREATE TABLE x1(x);
971153eda0aSdan      INSERT INTO x1 VALUES('Charles');
972153eda0aSdan      INSERT INTO x1 VALUES('James');
973153eda0aSdan      INSERT INTO x1 VALUES('Mary');
974153eda0aSdan      SELECT * FROM x1;
975153eda0aSdan    }
976153eda0aSdan  } {Charles James Mary}
9770e986f51Sdan
9780e986f51Sdan  do_test pager1-8.$tn.2 {
9790e986f51Sdan    sqlite3 db2 $filename
9800e986f51Sdan    catchsql { SELECT * FROM x1 } db2
981153eda0aSdan  } {1 {no such table: x1}}
982153eda0aSdan
9830e986f51Sdan  do_execsql_test pager1-8.$tn.3 {
9840e986f51Sdan    BEGIN;
9850e986f51Sdan      INSERT INTO x1 VALUES('William');
9860e986f51Sdan      INSERT INTO x1 VALUES('Anne');
9870e986f51Sdan    ROLLBACK;
9880e986f51Sdan  } {}
9890e986f51Sdan}
9900e986f51Sdan
991dca321aeSdan#-------------------------------------------------------------------------
992dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between
993dca321aeSdan# the pager and the backup API. Test cases:
994dca321aeSdan#
995dca321aeSdan#   pager1-9.1.*: Test that a backup completes successfully even if the
996dca321aeSdan#                 source db is written to during the backup op.
997dca321aeSdan#
998dca321aeSdan#   pager1-9.2.*: Test that a backup completes successfully even if the
999dca321aeSdan#                 source db is written to and then rolled back during a
1000dca321aeSdan#                 backup operation.
1001dca321aeSdan#
1002dca321aeSdando_test pager1-9.0.1 {
1003dca321aeSdan  faultsim_delete_and_reopen
1004dca321aeSdan  db func a_string a_string
1005dca321aeSdan  execsql {
1006dca321aeSdan    PRAGMA cache_size = 10;
1007dca321aeSdan    BEGIN;
1008dca321aeSdan      CREATE TABLE ab(a, b, UNIQUE(a, b));
1009dca321aeSdan      INSERT INTO ab VALUES( a_string(200), a_string(300) );
1010dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1011dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1012dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1013dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1014dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1015dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1016dca321aeSdan      INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
1017dca321aeSdan    COMMIT;
1018dca321aeSdan  }
1019dca321aeSdan} {}
1020dca321aeSdando_test pager1-9.0.2 {
1021dca321aeSdan  sqlite3 db2 test.db2
1022dca321aeSdan  db2 eval { PRAGMA cache_size = 10 }
1023dca321aeSdan  sqlite3_backup B db2 main db main
1024dca321aeSdan  list [B step 10000] [B finish]
1025dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1026dca321aeSdando_test pager1-9.0.3 {
1027dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1028dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1029dca321aeSdan
1030dca321aeSdando_test pager1-9.1.1 {
1031dca321aeSdan  execsql { UPDATE ab SET a = a_string(201) }
1032dca321aeSdan  sqlite3_backup B db2 main db main
1033dca321aeSdan  B step 30
1034dca321aeSdan} {SQLITE_OK}
1035dca321aeSdando_test pager1-9.1.2 {
1036dca321aeSdan  execsql { UPDATE ab SET b = a_string(301) }
1037dca321aeSdan  list [B step 10000] [B finish]
1038dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1039dca321aeSdando_test pager1-9.1.3 {
1040dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1041dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1042dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
1043dca321aeSdan
1044dca321aeSdando_test pager1-9.2.1 {
1045dca321aeSdan  execsql { UPDATE ab SET a = a_string(202) }
1046dca321aeSdan  sqlite3_backup B db2 main db main
1047dca321aeSdan  B step 30
1048dca321aeSdan} {SQLITE_OK}
1049dca321aeSdando_test pager1-9.2.2 {
1050dca321aeSdan  execsql {
1051dca321aeSdan    BEGIN;
1052dca321aeSdan      UPDATE ab SET b = a_string(301);
1053dca321aeSdan    ROLLBACK;
1054dca321aeSdan  }
1055dca321aeSdan  list [B step 10000] [B finish]
1056dca321aeSdan} {SQLITE_DONE SQLITE_OK}
1057dca321aeSdando_test pager1-9.2.3 {
1058dca321aeSdan db one {SELECT md5sum(a, b) FROM ab}
1059dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}]
1060dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
1061*ec6ffc1aSdandb close
1062*ec6ffc1aSdandb2 close
1063*ec6ffc1aSdan
1064*ec6ffc1aSdan#-------------------------------------------------------------------------
1065*ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the
1066*ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes.
1067*ec6ffc1aSdan#
1068*ec6ffc1aSdantestvfs tv -default 1
1069*ec6ffc1aSdanforeach sectorsize {
1070*ec6ffc1aSdan    32   64   128   256   512   1024   2048
1071*ec6ffc1aSdan    4096 8192 16384 32768 65536 131072 262144
1072*ec6ffc1aSdan} {
1073*ec6ffc1aSdan  tv sectorsize $sectorsize
1074*ec6ffc1aSdan  set eff $sectorsize
1075*ec6ffc1aSdan  if {$sectorsize < 512}   { set eff 512 }
1076*ec6ffc1aSdan  if {$sectorsize > 65536} { set eff 65536 }
1077*ec6ffc1aSdan
1078*ec6ffc1aSdan  do_test pager1-10.$sectorsize {
1079*ec6ffc1aSdan    faultsim_delete_and_reopen
1080*ec6ffc1aSdan    execsql {
1081*ec6ffc1aSdan      PRAGMA journal_mode = PERSIST;
1082*ec6ffc1aSdan      PRAGMA page_size = 1024;
1083*ec6ffc1aSdan      CREATE TABLE t1(a, b);
1084*ec6ffc1aSdan    }
1085*ec6ffc1aSdan    file size test.db-journal
1086*ec6ffc1aSdan  } [expr $sectorsize > 65536 ? 65536 : $sectorsize]
1087*ec6ffc1aSdan}
1088*ec6ffc1aSdandb close
1089*ec6ffc1aSdantv delete
1090*ec6ffc1aSdan
1091*ec6ffc1aSdantestvfs tv -default 1
1092*ec6ffc1aSdanfaultsim_delete_and_reopen
1093*ec6ffc1aSdandb func a_string a_string
1094*ec6ffc1aSdando_execsql_test pager1-11.1 {
1095*ec6ffc1aSdan  PRAGMA cache_size = 10;
1096*ec6ffc1aSdan  BEGIN;
1097*ec6ffc1aSdan    CREATE TABLE zz(top PRIMARY KEY);
1098*ec6ffc1aSdan    INSERT INTO zz VALUES(a_string(222));
1099*ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1100*ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1101*ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1102*ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1103*ec6ffc1aSdan    INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
1104*ec6ffc1aSdan  COMMIT;
1105*ec6ffc1aSdan  BEGIN;
1106*ec6ffc1aSdan    UPDATE zz SET top = a_string(345);
1107*ec6ffc1aSdan} {}
1108*ec6ffc1aSdan
1109*ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR }
1110*ec6ffc1aSdantv script lockout
1111*ec6ffc1aSdantv filter {xWrite xTruncate xSync}
1112*ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
1113*ec6ffc1aSdan
1114*ec6ffc1aSdantv script {}
1115*ec6ffc1aSdando_test pager1-11.3 {
1116*ec6ffc1aSdan  sqlite3 db2 test.db
1117*ec6ffc1aSdan  execsql {
1118*ec6ffc1aSdan    PRAGMA journal_mode = TRUNCATE;
1119*ec6ffc1aSdan    PRAGMA integrity_check;
1120*ec6ffc1aSdan  } db2
1121*ec6ffc1aSdan} {truncate ok}
1122*ec6ffc1aSdando_test pager1-11.4 {
1123*ec6ffc1aSdan  db2 close
1124*ec6ffc1aSdan  file size test.db-journal
1125*ec6ffc1aSdan} {0}
1126*ec6ffc1aSdanbreakpoint
1127*ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
1128*ec6ffc1aSdan
1129dca321aeSdan
1130e91a54e1Sdanfinish_test
1131e91a54e1Sdan
1132