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# 46*d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size" 47*d353331aSdan# 48*d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST" 49*d353331aSdan# 50*d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF" 51ec6ffc1aSdan# 52b0ac3e3aSdan 5353f04f3bSdanset a_string_counter 1 5453f04f3bSdanproc a_string {n} { 5553f04f3bSdan global a_string_counter 5653f04f3bSdan incr a_string_counter 5753f04f3bSdan string range [string repeat "${a_string_counter}." $n] 1 $n 5853f04f3bSdan} 5953f04f3bSdandb func a_string a_string 6053f04f3bSdan 61a4a9095eSdando_multiclient_test tn { 62e91a54e1Sdan 63e91a54e1Sdan # Create and populate a database table using connection [db]. Check 64e91a54e1Sdan # that connections [db2] and [db3] can see the schema and content. 65e91a54e1Sdan # 66e91a54e1Sdan do_test pager1-$tn.1 { 67e91a54e1Sdan sql1 { 68e91a54e1Sdan CREATE TABLE t1(a PRIMARY KEY, b); 69e91a54e1Sdan CREATE INDEX i1 ON t1(b); 70*d353331aSdan INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); 71e91a54e1Sdan } 72e91a54e1Sdan } {} 73e91a54e1Sdan do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two} 74e91a54e1Sdan do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two} 75e91a54e1Sdan 76e91a54e1Sdan # Open a transaction and add a row using [db]. This puts [db] in 77e91a54e1Sdan # RESERVED state. Check that connections [db2] and [db3] can still 78e91a54e1Sdan # read the database content as it was before the transaction was 79e91a54e1Sdan # opened. [db] should see the inserted row. 80e91a54e1Sdan # 81e91a54e1Sdan do_test pager1-$tn.4 { 82e91a54e1Sdan sql1 { 83e91a54e1Sdan BEGIN; 84e91a54e1Sdan INSERT INTO t1 VALUES(3, 'three'); 85e91a54e1Sdan } 86e91a54e1Sdan } {} 87e91a54e1Sdan do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two} 88e91a54e1Sdan do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three} 89e91a54e1Sdan 90e91a54e1Sdan # [db] still has an open write transaction. Check that this prevents 91e91a54e1Sdan # other connections (specifically [db2]) from writing to the database. 92e91a54e1Sdan # 93e91a54e1Sdan # Even if [db2] opens a transaction first, it may not write to the 94e91a54e1Sdan # database. After the attempt to write the db within a transaction, 95e91a54e1Sdan # [db2] is left with an open transaction, but not a read-lock on 96e91a54e1Sdan # the main database. So it does not prevent [db] from committing. 97e91a54e1Sdan # 98e91a54e1Sdan do_test pager1-$tn.8 { 99e91a54e1Sdan csql2 { UPDATE t1 SET a = a + 10 } 100e91a54e1Sdan } {1 {database is locked}} 101e91a54e1Sdan do_test pager1-$tn.9 { 102e91a54e1Sdan csql2 { 103e91a54e1Sdan BEGIN; 104e91a54e1Sdan UPDATE t1 SET a = a + 10; 105e91a54e1Sdan } 106e91a54e1Sdan } {1 {database is locked}} 107e91a54e1Sdan 108e91a54e1Sdan # Have [db] commit its transactions. Check the other connections can 109e91a54e1Sdan # now see the new database content. 110e91a54e1Sdan # 111e91a54e1Sdan do_test pager1-$tn.10 { sql1 { COMMIT } } {} 112e91a54e1Sdan do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three} 113e91a54e1Sdan do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 114e91a54e1Sdan do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 115e91a54e1Sdan 116e91a54e1Sdan # Check that, as noted above, [db2] really did keep an open transaction 117e91a54e1Sdan # after the attempt to write the database failed. 118e91a54e1Sdan # 119e91a54e1Sdan do_test pager1-$tn.14 { 120e91a54e1Sdan csql2 { BEGIN } 121e91a54e1Sdan } {1 {cannot start a transaction within a transaction}} 122e91a54e1Sdan do_test pager1-$tn.15 { sql2 { ROLLBACK } } {} 123e91a54e1Sdan 124e91a54e1Sdan # Have [db2] open a transaction and take a read-lock on the database. 125e91a54e1Sdan # Check that this prevents [db] from writing to the database (outside 126e91a54e1Sdan # of any transaction). After this fails, check that [db3] can read 127e91a54e1Sdan # the db (showing that [db] did not take a PENDING lock etc.) 128e91a54e1Sdan # 129e91a54e1Sdan do_test pager1-$tn.15 { 130e91a54e1Sdan sql2 { BEGIN; SELECT * FROM t1; } 131e91a54e1Sdan } {1 one 2 two 3 three} 132e91a54e1Sdan do_test pager1-$tn.16 { 133e91a54e1Sdan csql1 { UPDATE t1 SET a = a + 10 } 134e91a54e1Sdan } {1 {database is locked}} 135e91a54e1Sdan do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 136e91a54e1Sdan 137e91a54e1Sdan # This time, have [db] open a transaction before writing the database. 138e91a54e1Sdan # This works - [db] gets a RESERVED lock which does not conflict with 139e91a54e1Sdan # the SHARED lock [db2] is holding. 140e91a54e1Sdan # 141e91a54e1Sdan do_test pager1-$tn.18 { 142e91a54e1Sdan sql1 { 143e91a54e1Sdan BEGIN; 144e91a54e1Sdan UPDATE t1 SET a = a + 10; 145e91a54e1Sdan } 146e91a54e1Sdan } {} 147e91a54e1Sdan do_test pager1-$tn-19 { 148e91a54e1Sdan sql1 { PRAGMA lock_status } 149e91a54e1Sdan } {main reserved temp closed} 150e91a54e1Sdan do_test pager1-$tn-20 { 151e91a54e1Sdan sql2 { PRAGMA lock_status } 152e91a54e1Sdan } {main shared temp closed} 153e91a54e1Sdan 154e91a54e1Sdan # Check that all connections can still read the database. Only [db] sees 155e91a54e1Sdan # the updated content (as the transaction has not been committed yet). 156e91a54e1Sdan # 157e91a54e1Sdan do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three} 158e91a54e1Sdan do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 159e91a54e1Sdan do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 160e91a54e1Sdan 161e91a54e1Sdan # Because [db2] still has the SHARED lock, [db] is unable to commit the 162e91a54e1Sdan # transaction. If it tries, an error is returned and the connection 163e91a54e1Sdan # upgrades to a PENDING lock. 164e91a54e1Sdan # 165e91a54e1Sdan # Once this happens, [db] can read the database and see the new content, 166e91a54e1Sdan # [db2] (still holding SHARED) can still read the old content, but [db3] 167e91a54e1Sdan # (not holding any lock) is prevented by [db]'s PENDING from reading 168e91a54e1Sdan # the database. 169e91a54e1Sdan # 170e91a54e1Sdan do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}} 171e91a54e1Sdan do_test pager1-$tn-25 { 172e91a54e1Sdan sql1 { PRAGMA lock_status } 173e91a54e1Sdan } {main pending temp closed} 174e91a54e1Sdan do_test pager1-$tn.26 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three} 175e91a54e1Sdan do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 176e91a54e1Sdan do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}} 177e91a54e1Sdan 178e91a54e1Sdan # Have [db2] commit its read transaction, releasing the SHARED lock it 179e91a54e1Sdan # is holding. Now, neither [db2] nor [db3] may read the database (as [db] 180e91a54e1Sdan # is still holding a PENDING). 181e91a54e1Sdan # 182e91a54e1Sdan do_test pager1-$tn.29 { sql2 { COMMIT } } {} 183e91a54e1Sdan do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}} 184e91a54e1Sdan do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}} 185e91a54e1Sdan 186e91a54e1Sdan # [db] is now able to commit the transaction. Once the transaction is 187e91a54e1Sdan # committed, all three connections can read the new content. 188e91a54e1Sdan # 189e91a54e1Sdan do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {} 190e91a54e1Sdan do_test pager1-$tn.26 { sql1 { COMMIT } } {} 191e91a54e1Sdan do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three} 192e91a54e1Sdan do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three} 193e91a54e1Sdan do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three} 194*d353331aSdan 195*d353331aSdan # Install a busy-handler for connection [db]. 196*d353331aSdan # 197*d353331aSdan set ::nbusy [list] 198*d353331aSdan proc busy {n} { 199*d353331aSdan lappend ::nbusy $n 200*d353331aSdan if {$n>5} { sql2 COMMIT } 201*d353331aSdan return 0 202*d353331aSdan } 203*d353331aSdan db busy busy 204*d353331aSdan 205*d353331aSdan do_test pager1-$tn.29 { 206*d353331aSdan sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') } 207*d353331aSdan } {} 208*d353331aSdan do_test pager1-$tn.30 { 209*d353331aSdan sql2 { BEGIN ; SELECT * FROM t1 } 210*d353331aSdan } {21 one 22 two 23 three} 211*d353331aSdan do_test pager1-$tn.31 { sql1 COMMIT } {} 212*d353331aSdan do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6} 213e91a54e1Sdan} 214e91a54e1Sdan 21553f04f3bSdan#------------------------------------------------------------------------- 21653f04f3bSdan# Savepoint related test cases. 21753f04f3bSdan# 218dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file 219dca321aeSdan# to grow. 220dca321aeSdan# 221273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part 222273f3f0dSdan# of a savepoint rollback. 223273f3f0dSdan# 2240e986f51Sdando_test pager1-3.1.1 { 225b0ac3e3aSdan faultsim_delete_and_reopen 226b0ac3e3aSdan execsql { 227b0ac3e3aSdan CREATE TABLE t1(a PRIMARY KEY, b); 228b0ac3e3aSdan CREATE TABLE counter( 229b0ac3e3aSdan i CHECK (i<5), 230b0ac3e3aSdan u CHECK (u<10) 231b0ac3e3aSdan ); 232b0ac3e3aSdan INSERT INTO counter VALUES(0, 0); 233b0ac3e3aSdan CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN 234b0ac3e3aSdan UPDATE counter SET i = i+1; 235b0ac3e3aSdan END; 236b0ac3e3aSdan CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN 237b0ac3e3aSdan UPDATE counter SET u = u+1; 238b0ac3e3aSdan END; 239b0ac3e3aSdan } 240b0ac3e3aSdan execsql { SELECT * FROM counter } 241b0ac3e3aSdan} {0 0} 242b0ac3e3aSdan 2430e986f51Sdando_execsql_test pager1-3.1.2 { 244*d353331aSdan PRAGMA cache_size = 10; 245b0ac3e3aSdan BEGIN; 246b0ac3e3aSdan INSERT INTO t1 VALUES(1, randomblob(1500)); 247b0ac3e3aSdan INSERT INTO t1 VALUES(2, randomblob(1500)); 248b0ac3e3aSdan INSERT INTO t1 VALUES(3, randomblob(1500)); 249b0ac3e3aSdan SELECT * FROM counter; 250b0ac3e3aSdan} {3 0} 2510e986f51Sdando_catchsql_test pager1-3.1.3 { 252b0ac3e3aSdan INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1 253b0ac3e3aSdan} {1 {constraint failed}} 254b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} 255b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} 256b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {} 257b0ac3e3aSdan 258273f3f0dSdanforeach {tn sql tcl} { 259*d353331aSdan 7 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } { 260273f3f0dSdan testvfs tv -default 1 261273f3f0dSdan tv devchar safe_append 262273f3f0dSdan } 263*d353331aSdan 8 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } { 264*d353331aSdan testvfs tv -default 1 265*d353331aSdan tv devchar sequential 266*d353331aSdan } 267*d353331aSdan 9 { PRAGMA synchronous = FULL } { } 268*d353331aSdan 10 { PRAGMA synchronous = NORMAL } { } 269*d353331aSdan 11 { PRAGMA synchronous = OFF } { } 270*d353331aSdan 12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { } 271*d353331aSdan 13 { PRAGMA synchronous = FULL } { 272*d353331aSdan testvfs tv -default 1 273*d353331aSdan tv devchar sequential 274*d353331aSdan } 275273f3f0dSdan} { 276273f3f0dSdan do_test pager1-3.$tn.1 { 277273f3f0dSdan eval $tcl 278dca321aeSdan faultsim_delete_and_reopen 279dca321aeSdan db func a_string a_string 280273f3f0dSdan execsql $sql 281dca321aeSdan execsql { 282dca321aeSdan PRAGMA auto_vacuum = 2; 283dca321aeSdan PRAGMA cache_size = 10; 284dca321aeSdan CREATE TABLE z(x INTEGER PRIMARY KEY, y); 285dca321aeSdan BEGIN; 286dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 287dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 2 288dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 4 289dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 8 290dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 16 291dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 32 292dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 64 293dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 128 294dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 256 295dca321aeSdan COMMIT; 296dca321aeSdan } 297dca321aeSdan execsql { PRAGMA auto_vacuum } 298dca321aeSdan } {2} 299273f3f0dSdan do_execsql_test pager1-3.$tn.2 { 300dca321aeSdan BEGIN; 301dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 302dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 303dca321aeSdan SAVEPOINT one; 304273f3f0dSdan UPDATE z SET y = NULL WHERE x>256; 305dca321aeSdan PRAGMA incremental_vacuum; 306dca321aeSdan SELECT count(*) FROM z WHERE x < 100; 307dca321aeSdan ROLLBACK TO one; 308dca321aeSdan COMMIT; 309dca321aeSdan } {99} 310dca321aeSdan 311273f3f0dSdan do_execsql_test pager1-3.$tn.3 { 312273f3f0dSdan BEGIN; 313273f3f0dSdan SAVEPOINT one; 314273f3f0dSdan UPDATE z SET y = y||x; 315273f3f0dSdan ROLLBACK TO one; 316273f3f0dSdan COMMIT; 317273f3f0dSdan SELECT count(*) FROM z; 318273f3f0dSdan } {258} 319273f3f0dSdan 320273f3f0dSdan do_execsql_test pager1-3.$tn.4 { 321273f3f0dSdan SAVEPOINT one; 322273f3f0dSdan UPDATE z SET y = y||x; 323273f3f0dSdan ROLLBACK TO one; 324273f3f0dSdan } {} 325273f3f0dSdan do_execsql_test pager1-3.$tn.5 { 326273f3f0dSdan SELECT count(*) FROM z; 327273f3f0dSdan RELEASE one; 328273f3f0dSdan PRAGMA integrity_check; 329273f3f0dSdan } {258 ok} 330273f3f0dSdan 331273f3f0dSdan db close 332273f3f0dSdan catch { tv delete } 333273f3f0dSdan} 334273f3f0dSdan 33553f04f3bSdan#------------------------------------------------------------------------- 33653f04f3bSdan# Hot journal rollback related test cases. 33753f04f3bSdan# 33853f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid 33953f04f3bSdan# journal files. 34053f04f3bSdan# 34153f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a 34253f04f3bSdan# hot-journal file appears to be corrupt (checksum does not 34353f04f3bSdan# compute) the associated journal is rolled back (and no 34453f04f3bSdan# xAccess() call to check for the presence of any master 34553f04f3bSdan# journal file is made). 34653f04f3bSdan# 347de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the 348de4996e2Sdan# page-size or sector-size in the journal header appear to 349de4996e2Sdan# be invalid (too large, too small or not a power of 2). 350de4996e2Sdan# 351e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master 352e08341c6Sdan# journal pointer generated in various "PRAGMA synchronous" 353e08341c6Sdan# modes. 354e08341c6Sdan# 355e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a 356e08341c6Sdan# journal-record for which the checksum fails. 357e08341c6Sdan# 358ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a 359ec6ffc1aSdan# master journal pointer, the master journal file is deleted 360ec6ffc1aSdan# after all the hot-journals that refer to it are deleted. 361ec6ffc1aSdan# 36253f04f3bSdando_test pager1.4.1.1 { 36353f04f3bSdan faultsim_delete_and_reopen 36453f04f3bSdan execsql { 36553f04f3bSdan CREATE TABLE x(y, z); 36653f04f3bSdan INSERT INTO x VALUES(1, 2); 36753f04f3bSdan } 36853f04f3bSdan set fd [open test.db-journal w] 36953f04f3bSdan puts -nonewline $fd "helloworld" 37053f04f3bSdan close $fd 37153f04f3bSdan file exists test.db-journal 37253f04f3bSdan} {1} 37353f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2} 37453f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0} 37553f04f3bSdan 37653f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite 37753f04f3bSdan# deletes the master-journal to commit a multi-file transaction. 37853f04f3bSdan# 37953f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets 38053f04f3bSdan# up the file system to contain two databases, two hot-journal files and 38153f04f3bSdan# a master-journal. 38253f04f3bSdan# 38353f04f3bSdando_test pager1.4.2.1 { 38453f04f3bSdan testvfs tstvfs -default 1 38553f04f3bSdan tstvfs filter xDelete 38653f04f3bSdan tstvfs script xDeleteCallback 38753f04f3bSdan proc xDeleteCallback {method file args} { 38853f04f3bSdan set file [file tail $file] 38953f04f3bSdan if { [string match *mj* $file] } { faultsim_save } 39053f04f3bSdan } 39153f04f3bSdan faultsim_delete_and_reopen 39253f04f3bSdan db func a_string a_string 39353f04f3bSdan execsql { 39453f04f3bSdan ATTACH 'test.db2' AS aux; 39553f04f3bSdan PRAGMA journal_mode = DELETE; 39653f04f3bSdan PRAGMA main.cache_size = 10; 39753f04f3bSdan PRAGMA aux.cache_size = 10; 39853f04f3bSdan CREATE TABLE t1(a UNIQUE, b UNIQUE); 39953f04f3bSdan CREATE TABLE aux.t2(a UNIQUE, b UNIQUE); 40053f04f3bSdan INSERT INTO t1 VALUES(a_string(200), a_string(300)); 40153f04f3bSdan INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 40253f04f3bSdan INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 40353f04f3bSdan INSERT INTO t2 SELECT * FROM t1; 40453f04f3bSdan BEGIN; 40553f04f3bSdan INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; 40653f04f3bSdan INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; 40753f04f3bSdan INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; 40853f04f3bSdan INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; 40953f04f3bSdan REPLACE INTO t2 SELECT * FROM t1; 41053f04f3bSdan COMMIT; 41153f04f3bSdan } 41253f04f3bSdan db close 41353f04f3bSdan tstvfs delete 41453f04f3bSdan} {} 41553f04f3bSdando_test pager1.4.2.2 { 41653f04f3bSdan faultsim_restore_and_reopen 41753f04f3bSdan execsql { 41853f04f3bSdan SELECT count(*) FROM t1; 41953f04f3bSdan PRAGMA integrity_check; 42053f04f3bSdan } 42153f04f3bSdan} {4 ok} 42253f04f3bSdando_test pager1.4.2.3 { 42353f04f3bSdan faultsim_restore_and_reopen 42453f04f3bSdan foreach f [glob test.db-mj*] { file delete -force $f } 42553f04f3bSdan execsql { 42653f04f3bSdan SELECT count(*) FROM t1; 42753f04f3bSdan PRAGMA integrity_check; 42853f04f3bSdan } 42953f04f3bSdan} {64 ok} 43053f04f3bSdando_test pager1.4.2.4 { 43153f04f3bSdan faultsim_restore_and_reopen 43253f04f3bSdan hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 43353f04f3bSdan execsql { 43453f04f3bSdan SELECT count(*) FROM t1; 43553f04f3bSdan PRAGMA integrity_check; 43653f04f3bSdan } 43753f04f3bSdan} {4 ok} 43853f04f3bSdando_test pager1.4.2.5 { 43953f04f3bSdan faultsim_restore_and_reopen 44053f04f3bSdan hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 44153f04f3bSdan foreach f [glob test.db-mj*] { file delete -force $f } 44253f04f3bSdan execsql { 44353f04f3bSdan SELECT count(*) FROM t1; 44453f04f3bSdan PRAGMA integrity_check; 44553f04f3bSdan } 44653f04f3bSdan} {4 ok} 44753f04f3bSdan 448de4996e2Sdando_test pager1.4.3.1 { 449de4996e2Sdan testvfs tstvfs -default 1 450de4996e2Sdan tstvfs filter xSync 451de4996e2Sdan tstvfs script xSyncCallback 452de4996e2Sdan proc xSyncCallback {method file args} { 453de4996e2Sdan set file [file tail $file] 454de4996e2Sdan if { 0==[string match *journal $file] } { faultsim_save } 455de4996e2Sdan } 456de4996e2Sdan faultsim_delete_and_reopen 457de4996e2Sdan execsql { 458de4996e2Sdan PRAGMA journal_mode = DELETE; 459de4996e2Sdan CREATE TABLE t1(a, b); 460de4996e2Sdan INSERT INTO t1 VALUES(1, 2); 461de4996e2Sdan INSERT INTO t1 VALUES(3, 4); 462de4996e2Sdan } 463de4996e2Sdan db close 464de4996e2Sdan tstvfs delete 465de4996e2Sdan} {} 466de4996e2Sdan 467de4996e2Sdanforeach {tn ofst value result} { 468de4996e2Sdan 2 20 31 {1 2 3 4} 469de4996e2Sdan 3 20 32 {1 2 3 4} 470de4996e2Sdan 4 20 33 {1 2 3 4} 471de4996e2Sdan 5 20 65536 {1 2 3 4} 472de4996e2Sdan 6 20 131072 {1 2 3 4} 473de4996e2Sdan 474de4996e2Sdan 7 24 511 {1 2 3 4} 475de4996e2Sdan 8 24 513 {1 2 3 4} 476de4996e2Sdan 9 24 65536 {1 2 3 4} 477de4996e2Sdan 478de4996e2Sdan 10 32 65536 {1 2} 479de4996e2Sdan} { 480de4996e2Sdan do_test pager1.4.3.$tn { 481de4996e2Sdan faultsim_restore_and_reopen 482de4996e2Sdan hexio_write test.db-journal $ofst [format %.8x $value] 483de4996e2Sdan execsql { SELECT * FROM t1 } 484de4996e2Sdan } $result 485de4996e2Sdan} 486de4996e2Sdandb close 487de4996e2Sdan 488e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal 489e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the 490e08341c6Sdan# file-system is saved just before the xDelete() call to remove the 491e08341c6Sdan# master journal file from the file-system. 492e08341c6Sdan# 493e08341c6Sdantestvfs tv -default 1 494e08341c6Sdantv script copy_on_mj_delete 495e08341c6Sdanset ::mj_filename_length 0 496e08341c6Sdanproc copy_on_mj_delete {method filename args} { 497e08341c6Sdan if {[string match *mj* [file tail $filename]]} { 498e08341c6Sdan set ::mj_filename_length [string length $filename] 499e08341c6Sdan faultsim_save 500e08341c6Sdan } 501e08341c6Sdan return SQLITE_OK 502e08341c6Sdan} 503e08341c6Sdan 504e08341c6Sdanset pwd [pwd] 505e08341c6Sdanforeach {tn1 tcl} { 506e08341c6Sdan 1 { set prefix "test.db" } 507e08341c6Sdan 2 { 508e08341c6Sdan # This test depends on the underlying VFS being able to open paths 509e08341c6Sdan # 512 bytes in length. The idea is to create a hot-journal file that 510e08341c6Sdan # contains a master-journal pointer so large that it could contain 511e08341c6Sdan # a valid page record (if the file page-size is 512 bytes). So as to 512e08341c6Sdan # make sure SQLite doesn't get confused by this. 513e08341c6Sdan # 514e08341c6Sdan set nPadding [expr 511 - $::mj_filename_length] 515e08341c6Sdan 516e08341c6Sdan # We cannot just create a really long database file name to open, as 517e08341c6Sdan # Linux limits a single component of a path to 255 bytes by default 518e08341c6Sdan # (and presumably other systems have limits too). So create a directory 519e08341c6Sdan # hierarchy to work in. 520e08341c6Sdan # 521e08341c6Sdan set dirname "d123456789012345678901234567890/" 522e08341c6Sdan set nDir [expr $nPadding / 32] 523e08341c6Sdan if { $nDir } { 524e08341c6Sdan set p [string repeat $dirname $nDir] 525e08341c6Sdan file mkdir $p 526e08341c6Sdan cd $p 527e08341c6Sdan } 528e08341c6Sdan 529e08341c6Sdan set padding [string repeat x [expr $nPadding %32]] 530e08341c6Sdan set prefix "test.db${padding}" 531e08341c6Sdan } 532e08341c6Sdan} { 533e08341c6Sdan eval $tcl 534e08341c6Sdan foreach {tn2 sql} { 535e08341c6Sdan o { 536e08341c6Sdan PRAGMA main.synchronous=OFF; 537e08341c6Sdan PRAGMA aux.synchronous=OFF; 538e08341c6Sdan } 539e08341c6Sdan o512 { 540e08341c6Sdan PRAGMA main.synchronous=OFF; 541e08341c6Sdan PRAGMA aux.synchronous=OFF; 542e08341c6Sdan PRAGMA main.page_size = 512; 543e08341c6Sdan PRAGMA aux.page_size = 512; 544e08341c6Sdan } 545e08341c6Sdan n { 546e08341c6Sdan PRAGMA main.synchronous=NORMAL; 547e08341c6Sdan PRAGMA aux.synchronous=NORMAL; 548e08341c6Sdan } 549e08341c6Sdan f { 550e08341c6Sdan PRAGMA main.synchronous=FULL; 551e08341c6Sdan PRAGMA aux.synchronous=FULL; 552e08341c6Sdan } 553e08341c6Sdan } { 554e08341c6Sdan 555e08341c6Sdan set tn "${tn1}.${tn2}" 556e08341c6Sdan 557e08341c6Sdan # Set up a connection to have two databases, test.db (main) and 558e08341c6Sdan # test.db2 (aux). Then run a multi-file transaction on them. The 559e08341c6Sdan # VFS will snapshot the file-system just before the master-journal 560e08341c6Sdan # file is deleted to commit the transaction. 561e08341c6Sdan # 562e08341c6Sdan tv filter xDelete 563e08341c6Sdan do_test pager1-4.4.$tn.1 { 564e08341c6Sdan faultsim_delete_and_reopen $prefix 565e08341c6Sdan execsql " 566e08341c6Sdan ATTACH '${prefix}2' AS aux; 567e08341c6Sdan $sql 568e08341c6Sdan CREATE TABLE a(x); 569e08341c6Sdan CREATE TABLE aux.b(x); 570e08341c6Sdan INSERT INTO a VALUES('double-you'); 571e08341c6Sdan INSERT INTO a VALUES('why'); 572e08341c6Sdan INSERT INTO a VALUES('zed'); 573e08341c6Sdan INSERT INTO b VALUES('won'); 574e08341c6Sdan INSERT INTO b VALUES('too'); 575e08341c6Sdan INSERT INTO b VALUES('free'); 576e08341c6Sdan " 577e08341c6Sdan execsql { 578e08341c6Sdan BEGIN; 579e08341c6Sdan INSERT INTO a SELECT * FROM b WHERE rowid<=3; 580e08341c6Sdan INSERT INTO b SELECT * FROM a WHERE rowid<=3; 581e08341c6Sdan COMMIT; 582e08341c6Sdan } 583e08341c6Sdan } {} 584e08341c6Sdan tv filter {} 585e08341c6Sdan 586e08341c6Sdan # Check that the transaction was committed successfully. 587e08341c6Sdan # 588e08341c6Sdan do_execsql_test pager1-4.4.$tn.2 { 589e08341c6Sdan SELECT * FROM a 590e08341c6Sdan } {double-you why zed won too free} 591e08341c6Sdan do_execsql_test pager1-4.4.$tn.3 { 592e08341c6Sdan SELECT * FROM b 593e08341c6Sdan } {won too free double-you why zed} 594e08341c6Sdan 595e08341c6Sdan # Restore the file-system and reopen the databases. Check that it now 596e08341c6Sdan # appears that the transaction was not committed (because the file-system 597e08341c6Sdan # was restored to the state where it had not been). 598e08341c6Sdan # 599e08341c6Sdan do_test pager1-4.4.$tn.4 { 600e08341c6Sdan faultsim_restore_and_reopen $prefix 601e08341c6Sdan execsql "ATTACH '${prefix}2' AS aux" 602e08341c6Sdan } {} 603e08341c6Sdan do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed} 604e08341c6Sdan do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free} 605e08341c6Sdan 606e08341c6Sdan # Restore the file-system again. This time, before reopening the databases, 607e08341c6Sdan # delete the master-journal file from the file-system. It now appears that 608e08341c6Sdan # the transaction was committed (no master-journal file == no rollback). 609e08341c6Sdan # 610e08341c6Sdan do_test pager1-4.4.$tn.7 { 611e08341c6Sdan faultsim_restore_and_reopen $prefix 612e08341c6Sdan foreach f [glob ${prefix}-mj*] { file delete -force $f } 613e08341c6Sdan execsql "ATTACH '${prefix}2' AS aux" 614e08341c6Sdan } {} 615e08341c6Sdan do_execsql_test pager1-4.4.$tn.8 { 616e08341c6Sdan SELECT * FROM a 617e08341c6Sdan } {double-you why zed won too free} 618e08341c6Sdan do_execsql_test pager1-4.4.$tn.9 { 619e08341c6Sdan SELECT * FROM b 620e08341c6Sdan } {won too free double-you why zed} 621e08341c6Sdan } 622e08341c6Sdan 623e08341c6Sdan cd $pwd 624e08341c6Sdan} 625e08341c6Sdandb close 626e08341c6Sdantv delete 6270e986f51Sdanfile delete -force $dirname 6280e986f51Sdan 6290e986f51Sdan 6300e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a 6310e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly 6320e986f51Sdan# two database pages (and page 1 - the change counter). 6330e986f51Sdan# 6340e986f51Sdantestvfs tv -default 1 6350e986f51Sdantv sectorsize 512 6360e986f51Sdantv script copy_on_journal_delete 6370e986f51Sdantv filter xDelete 6380e986f51Sdanset ::mj_filename_length 0 6390e986f51Sdanproc copy_on_journal_delete {method filename args} { 6400e986f51Sdan if {[string match *journal $filename]} faultsim_save 6410e986f51Sdan return SQLITE_OK 6420e986f51Sdan} 6430e986f51Sdanfaultsim_delete_and_reopen 6440e986f51Sdando_execsql_test pager1.4.5.1 { 6450e986f51Sdan PRAGMA page_size = 1024; 6460e986f51Sdan CREATE TABLE t1(a, b); 6470e986f51Sdan CREATE TABLE t2(a, b); 6480e986f51Sdan INSERT INTO t1 VALUES('I', 'II'); 6490e986f51Sdan INSERT INTO t2 VALUES('III', 'IV'); 6500e986f51Sdan BEGIN; 6510e986f51Sdan INSERT INTO t1 VALUES(1, 2); 6520e986f51Sdan INSERT INTO t2 VALUES(3, 4); 6530e986f51Sdan COMMIT; 6540e986f51Sdan} {} 6550e986f51Sdantv filter {} 6560e986f51Sdan 6570e986f51Sdan# Check the transaction was committed: 6580e986f51Sdan# 6590e986f51Sdando_execsql_test pager1.4.5.2 { 6600e986f51Sdan SELECT * FROM t1; 6610e986f51Sdan SELECT * FROM t2; 6620e986f51Sdan} {I II 1 2 III IV 3 4} 6630e986f51Sdan 664ec6ffc1aSdan# Now try four tests: 6650e986f51Sdan# 6660e986f51Sdan# pager1-4.5.3: Restore the file-system. Check that the whole transaction 6670e986f51Sdan# is rolled back. 6680e986f51Sdan# 6690e986f51Sdan# pager1-4.5.4: Restore the file-system. Corrupt the first record in the 6700e986f51Sdan# journal. Check the transaction is not rolled back. 6710e986f51Sdan# 6720e986f51Sdan# pager1-4.5.5: Restore the file-system. Corrupt the second record in the 6730e986f51Sdan# journal. Check that the first record in the transaction is 6740e986f51Sdan# played back, but not the second. 6750e986f51Sdan# 67610f5a50eSdan# pager1-4.5.6: Restore the file-system. Try to open the database with a 67710f5a50eSdan# readonly connection. This should fail, as a read-only 67810f5a50eSdan# connection cannot roll back the database file. 67910f5a50eSdan# 6800e986f51Sdanfaultsim_restore_and_reopen 6810e986f51Sdando_execsql_test pager1.4.5.3 { 6820e986f51Sdan SELECT * FROM t1; 6830e986f51Sdan SELECT * FROM t2; 6840e986f51Sdan} {I II III IV} 6850e986f51Sdanfaultsim_restore_and_reopen 6860e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF 6870e986f51Sdando_execsql_test pager1.4.5.4 { 6880e986f51Sdan SELECT * FROM t1; 6890e986f51Sdan SELECT * FROM t2; 6900e986f51Sdan} {I II 1 2 III IV 3 4} 6910e986f51Sdanfaultsim_restore_and_reopen 6920e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF 6930e986f51Sdando_execsql_test pager1.4.5.5 { 6940e986f51Sdan SELECT * FROM t1; 6950e986f51Sdan SELECT * FROM t2; 6960e986f51Sdan} {I II III IV 3 4} 6970e986f51Sdan 69810f5a50eSdanfaultsim_restore_and_reopen 69910f5a50eSdandb close 70010f5a50eSdansqlite3 db test.db -readonly 1 70110f5a50eSdando_catchsql_test pager1.4.5.6 { 70210f5a50eSdan SELECT * FROM t1; 70310f5a50eSdan SELECT * FROM t2; 70410f5a50eSdan} {1 {disk I/O error}} 705ec6ffc1aSdandb close 706ec6ffc1aSdan 707ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name 708ec6ffc1aSdan# of the master journal file in $::mj_filename. 709ec6ffc1aSdan# 710ec6ffc1aSdantv script copy_on_mj_delete 711ec6ffc1aSdantv filter xDelete 712ec6ffc1aSdanproc copy_on_mj_delete {method filename args} { 713ec6ffc1aSdan if {[string match *mj* [file tail $filename]]} { 714ec6ffc1aSdan set ::mj_filename $filename 715ec6ffc1aSdan faultsim_save 716ec6ffc1aSdan } 717ec6ffc1aSdan return SQLITE_OK 718ec6ffc1aSdan} 719ec6ffc1aSdando_test pager1.4.6.1 { 720ec6ffc1aSdan faultsim_delete_and_reopen 721ec6ffc1aSdan execsql { 722ec6ffc1aSdan ATTACH 'test.db2' AS two; 723ec6ffc1aSdan CREATE TABLE t1(a, b); 724ec6ffc1aSdan CREATE TABLE two.t2(a, b); 725ec6ffc1aSdan INSERT INTO t1 VALUES(1, 't1.1'); 726ec6ffc1aSdan INSERT INTO t2 VALUES(1, 't2.1'); 727ec6ffc1aSdan BEGIN; 728ec6ffc1aSdan UPDATE t1 SET b = 't1.2'; 729ec6ffc1aSdan UPDATE t2 SET b = 't2.2'; 730ec6ffc1aSdan COMMIT; 731ec6ffc1aSdan } 732ec6ffc1aSdan tv filter {} 733ec6ffc1aSdan db close 734ec6ffc1aSdan} {} 735ec6ffc1aSdan 736ec6ffc1aSdanfaultsim_restore_and_reopen 737ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 } {1 t1.1} 738ec6ffc1aSdando_test pager1.4.6.3 { file exists $::mj_filename } {1} 739ec6ffc1aSdando_execsql_test pager1.4.6.4 { 740ec6ffc1aSdan ATTACH 'test.db2' AS two; 741ec6ffc1aSdan SELECT * FROM t2; 742ec6ffc1aSdan} {1 t2.1} 743ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0} 744ec6ffc1aSdan 745ec6ffc1aSdanfaultsim_restore_and_reopen 746ec6ffc1aSdandb close 747ec6ffc1aSdando_test pager1.4.6.8 { 748ec6ffc1aSdan set ::mj_filename1 $::mj_filename 749ec6ffc1aSdan tv filter xDelete 750ec6ffc1aSdan sqlite3 db test.db2 751ec6ffc1aSdan execsql { 752ec6ffc1aSdan ATTACH 'test.db3' AS three; 753ec6ffc1aSdan CREATE TABLE three.t3(a, b); 754ec6ffc1aSdan INSERT INTO t3 VALUES(1, 't3.1'); 755ec6ffc1aSdan BEGIN; 756ec6ffc1aSdan UPDATE t2 SET b = 't2.3'; 757ec6ffc1aSdan UPDATE t3 SET b = 't3.3'; 758ec6ffc1aSdan COMMIT; 759ec6ffc1aSdan } 760ec6ffc1aSdan expr {$::mj_filename1 != $::mj_filename} 761ec6ffc1aSdan} {1} 762ec6ffc1aSdanfaultsim_restore_and_reopen 763ec6ffc1aSdantv filter {} 764ec6ffc1aSdan 765ec6ffc1aSdan# The file-system now contains: 766ec6ffc1aSdan# 767ec6ffc1aSdan# * three databases 768ec6ffc1aSdan# * three hot-journal files 769ec6ffc1aSdan# * two master-journal files. 770ec6ffc1aSdan# 771ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to 772ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with 773ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from 774ec6ffc1aSdan# test.db should delete $::mj_filename1. 775ec6ffc1aSdan# 776ec6ffc1aSdando_test pager1.4.6.9 { 777ec6ffc1aSdan lsort [glob test.db*] 778ec6ffc1aSdan} [lsort [list \ 779ec6ffc1aSdan test.db test.db2 test.db3 \ 780ec6ffc1aSdan test.db-journal test.db2-journal test.db3-journal \ 781ec6ffc1aSdan [file tail $::mj_filename] [file tail $::mj_filename1] 782ec6ffc1aSdan]] 783ec6ffc1aSdan 784ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and 785ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to 786ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should 787ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1. 788ec6ffc1aSdan# 789ec6ffc1aSdando_test pager1.4.6.10 { file exists $::mj_filename } {1} 790ec6ffc1aSdando_test pager1.4.6.11 { file exists $::mj_filename1 } {1} 791ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1} 792ec6ffc1aSdando_test pager1.4.6.13 { file exists $::mj_filename } {1} 793ec6ffc1aSdando_test pager1.4.6.14 { file exists $::mj_filename1 } {0} 794ec6ffc1aSdan 795ec6ffc1aSdando_execsql_test pager1.4.6.12 { 796ec6ffc1aSdan ATTACH 'test.db2' AS two; 797ec6ffc1aSdan SELECT * FROM t2; 798ec6ffc1aSdan} {1 t2.1} 799ec6ffc1aSdando_test pager1.4.6.13 { file exists $::mj_filename } {1} 800ec6ffc1aSdando_execsql_test pager1.4.6.14 { 801ec6ffc1aSdan ATTACH 'test.db3' AS three; 802ec6ffc1aSdan SELECT * FROM t3; 803ec6ffc1aSdan} {1 t3.1} 804ec6ffc1aSdando_test pager1.4.6.15 { file exists $::mj_filename } {0} 80510f5a50eSdan 8060e986f51Sdandb close 8070e986f51Sdantv delete 808e08341c6Sdan 809de4996e2Sdan#------------------------------------------------------------------------- 810146ed78bSdan# The following tests deal with multi-file commits. 811de4996e2Sdan# 812146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because 813146ed78bSdan# another connection is holding a SHARED lock on one of the 814146ed78bSdan# files. After the SHARED lock is removed, the COMMIT succeeds. 815146ed78bSdan# 816146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory. 817146ed78bSdan# 818146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory. 819146ed78bSdan# 820146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file 821146ed78bSdan# name is added to a journal file immediately after the last 822146ed78bSdan# journal record. But with synchronous=full, extra unused space 823146ed78bSdan# is allocated between the last journal record and the 824146ed78bSdan# master-journal file name so that the master-journal file 825146ed78bSdan# name does not lie on the same sector as the last journal file 826146ed78bSdan# record. 827146ed78bSdan# 828e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is 829e08341c6Sdan# truncated to zero bytes when a multi-file transaction is 830e08341c6Sdan# committed (instead of the first couple of bytes being zeroed). 831e08341c6Sdan# 832146ed78bSdan# 833146ed78bSdando_test pager1-5.1.1 { 834146ed78bSdan faultsim_delete_and_reopen 835146ed78bSdan execsql { 836146ed78bSdan ATTACH 'test.db2' AS aux; 837146ed78bSdan CREATE TABLE t1(a, b); 838146ed78bSdan CREATE TABLE aux.t2(a, b); 839146ed78bSdan INSERT INTO t1 VALUES(17, 'Lenin'); 840146ed78bSdan INSERT INTO t1 VALUES(22, 'Stalin'); 841146ed78bSdan INSERT INTO t1 VALUES(53, 'Khrushchev'); 842146ed78bSdan } 843146ed78bSdan} {} 844146ed78bSdando_test pager1-5.1.2 { 845146ed78bSdan execsql { 846146ed78bSdan BEGIN; 847146ed78bSdan INSERT INTO t1 VALUES(64, 'Brezhnev'); 848146ed78bSdan INSERT INTO t2 SELECT * FROM t1; 849146ed78bSdan } 850146ed78bSdan sqlite3 db2 test.db2 851146ed78bSdan execsql { 852146ed78bSdan BEGIN; 853146ed78bSdan SELECT * FROM t2; 854146ed78bSdan } db2 855146ed78bSdan} {} 856146ed78bSdando_test pager1-5.1.3 { 857146ed78bSdan catchsql COMMIT 858146ed78bSdan} {1 {database is locked}} 859146ed78bSdando_test pager1-5.1.4 { 860146ed78bSdan execsql COMMIT db2 861146ed78bSdan execsql COMMIT 862146ed78bSdan execsql { SELECT * FROM t2 } db2 863146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev} 864146ed78bSdando_test pager1-5.1.5 { 865146ed78bSdan db2 close 866146ed78bSdan} {} 867146ed78bSdan 868146ed78bSdando_test pager1-5.2.1 { 869146ed78bSdan execsql { 870146ed78bSdan PRAGMA journal_mode = memory; 871146ed78bSdan BEGIN; 872146ed78bSdan INSERT INTO t1 VALUES(84, 'Andropov'); 873146ed78bSdan INSERT INTO t2 VALUES(84, 'Andropov'); 874146ed78bSdan COMMIT; 875146ed78bSdan } 876146ed78bSdan} {memory} 877146ed78bSdando_test pager1-5.3.1 { 878146ed78bSdan execsql { 879146ed78bSdan PRAGMA journal_mode = off; 880146ed78bSdan BEGIN; 881146ed78bSdan INSERT INTO t1 VALUES(85, 'Gorbachev'); 882146ed78bSdan INSERT INTO t2 VALUES(85, 'Gorbachev'); 883146ed78bSdan COMMIT; 884146ed78bSdan } 885146ed78bSdan} {off} 886146ed78bSdan 887146ed78bSdando_test pager1-5.4.1 { 888146ed78bSdan db close 889146ed78bSdan testvfs tv 890146ed78bSdan sqlite3 db test.db -vfs tv 891146ed78bSdan execsql { ATTACH 'test.db2' AS aux } 892146ed78bSdan 893146ed78bSdan tv filter xDelete 894146ed78bSdan tv script max_journal_size 895146ed78bSdan tv sectorsize 512 896146ed78bSdan set ::max_journal 0 897146ed78bSdan proc max_journal_size {method args} { 898146ed78bSdan set sz 0 899146ed78bSdan catch { set sz [file size test.db-journal] } 900146ed78bSdan if {$sz > $::max_journal} { 901146ed78bSdan set ::max_journal $sz 902146ed78bSdan } 903146ed78bSdan return SQLITE_OK 904146ed78bSdan } 905146ed78bSdan execsql { 906146ed78bSdan PRAGMA journal_mode = DELETE; 907146ed78bSdan PRAGMA synchronous = NORMAL; 908146ed78bSdan BEGIN; 909146ed78bSdan INSERT INTO t1 VALUES(85, 'Gorbachev'); 910146ed78bSdan INSERT INTO t2 VALUES(85, 'Gorbachev'); 911146ed78bSdan COMMIT; 912146ed78bSdan } 913146ed78bSdan set ::max_journal 914146ed78bSdan} [expr 2615+[string length [pwd]]] 915146ed78bSdando_test pager1-5.4.2 { 916146ed78bSdan set ::max_journal 0 917146ed78bSdan execsql { 918146ed78bSdan PRAGMA synchronous = full; 919146ed78bSdan BEGIN; 920146ed78bSdan DELETE FROM t1 WHERE b = 'Lenin'; 921146ed78bSdan DELETE FROM t2 WHERE b = 'Lenin'; 922146ed78bSdan COMMIT; 923146ed78bSdan } 924146ed78bSdan set ::max_journal 925146ed78bSdan} [expr 3111+[string length [pwd]]] 926146ed78bSdandb close 927146ed78bSdantv delete 928146ed78bSdan 929146ed78bSdando_test pager1-5.5.1 { 930146ed78bSdan sqlite3 db test.db 931146ed78bSdan execsql { 932146ed78bSdan ATTACH 'test.db2' AS aux; 933146ed78bSdan PRAGMA journal_mode = PERSIST; 934146ed78bSdan CREATE TABLE t3(a, b); 935146ed78bSdan INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1; 936146ed78bSdan UPDATE t3 SET b = randomblob(1500); 937146ed78bSdan } 938146ed78bSdan expr [file size test.db-journal] > 15000 939146ed78bSdan} {1} 940146ed78bSdando_test pager1-5.5.2 { 941146ed78bSdan execsql { 942146ed78bSdan PRAGMA synchronous = full; 943146ed78bSdan BEGIN; 944146ed78bSdan DELETE FROM t1 WHERE b = 'Stalin'; 945146ed78bSdan DELETE FROM t2 WHERE b = 'Stalin'; 946146ed78bSdan COMMIT; 947146ed78bSdan } 948146ed78bSdan file size test.db-journal 949146ed78bSdan} {0} 950146ed78bSdan 951146ed78bSdan 952146ed78bSdan#------------------------------------------------------------------------- 953146ed78bSdan# The following tests work with "PRAGMA max_page_count" 954146ed78bSdan# 955146ed78bSdando_test pager1-6.1 { 956146ed78bSdan faultsim_delete_and_reopen 957146ed78bSdan execsql { 958146ed78bSdan PRAGMA max_page_count = 10; 959146ed78bSdan CREATE TABLE t2(a, b); 960146ed78bSdan CREATE TABLE t3(a, b); 961146ed78bSdan CREATE TABLE t4(a, b); 962146ed78bSdan CREATE TABLE t5(a, b); 963146ed78bSdan CREATE TABLE t6(a, b); 964146ed78bSdan CREATE TABLE t7(a, b); 965146ed78bSdan CREATE TABLE t8(a, b); 966146ed78bSdan CREATE TABLE t9(a, b); 967146ed78bSdan CREATE TABLE t10(a, b); 968146ed78bSdan } 969146ed78bSdan} {10} 970*d353331aSdando_catchsql_test pager1-6.2 { 971*d353331aSdan CREATE TABLE t11(a, b) 972146ed78bSdan} {1 {database or disk is full}} 973*d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count } {10} 974*d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15} 975*d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b) } {} 976*d353331aSdando_execsql_test pager1-6.7 { 977*d353331aSdan BEGIN; 978*d353331aSdan INSERT INTO t11 VALUES(1, 2); 979*d353331aSdan PRAGMA max_page_count = 13; 980*d353331aSdan} {13} 981*d353331aSdando_execsql_test pager1-6.8 { 982*d353331aSdan INSERT INTO t11 VALUES(3, 4); 983*d353331aSdan PRAGMA max_page_count = 10; 984*d353331aSdan} {11} 985*d353331aSdando_execsql_test pager1-6.9 { COMMIT } {} 986de4996e2Sdan 987153eda0aSdan 988153eda0aSdan#------------------------------------------------------------------------- 989153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and 990153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE". 991153eda0aSdan# 992153eda0aSdan# Each test is specified with 5 variables. As follows: 993153eda0aSdan# 994153eda0aSdan# $tn: Test Number. Used as part of the [do_test] test names. 995153eda0aSdan# $sql: SQL to execute. 996153eda0aSdan# $res: Expected result of executing $sql. 997153eda0aSdan# $js: The expected size of the journal file, in bytes, after executing 998153eda0aSdan# the SQL script. Or -1 if the journal is not expected to exist. 999153eda0aSdan# $ws: The expected size of the WAL file, in bytes, after executing 1000153eda0aSdan# the SQL script. Or -1 if the WAL is not expected to exist. 1001153eda0aSdan# 100238e1a279Sdanifcapable wal { 1003153eda0aSdan faultsim_delete_and_reopen 1004153eda0aSdan foreach {tn sql res js ws} [subst { 1005153eda0aSdan 1006153eda0aSdan 1 { 1007153eda0aSdan CREATE TABLE t1(a, b); 1008153eda0aSdan PRAGMA auto_vacuum=OFF; 1009153eda0aSdan PRAGMA synchronous=NORMAL; 1010153eda0aSdan PRAGMA page_size=1024; 1011153eda0aSdan PRAGMA locking_mode=EXCLUSIVE; 1012153eda0aSdan PRAGMA journal_mode=TRUNCATE; 1013153eda0aSdan INSERT INTO t1 VALUES(1, 2); 1014153eda0aSdan } {exclusive truncate} 0 -1 1015153eda0aSdan 1016153eda0aSdan 2 { 1017153eda0aSdan BEGIN IMMEDIATE; 1018153eda0aSdan SELECT * FROM t1; 1019153eda0aSdan COMMIT; 1020153eda0aSdan } {1 2} 0 -1 1021153eda0aSdan 1022153eda0aSdan 3 { 1023153eda0aSdan BEGIN; 1024153eda0aSdan SELECT * FROM t1; 1025153eda0aSdan COMMIT; 1026153eda0aSdan } {1 2} 0 -1 1027153eda0aSdan 1028153eda0aSdan 4 { PRAGMA journal_mode = WAL } wal -1 -1 1029153eda0aSdan 5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024] 1030153eda0aSdan 6 { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024] 1031153eda0aSdan 7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024] 1032153eda0aSdan 1033153eda0aSdan 8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1 1034153eda0aSdan 9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1 1035153eda0aSdan 10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1 1036153eda0aSdan 1037153eda0aSdan }] { 1038153eda0aSdan do_execsql_test pager1-7.1.$tn.1 $sql $res 1039153eda0aSdan catch { set J -1 ; set J [file size test.db-journal] } 1040153eda0aSdan catch { set W -1 ; set W [file size test.db-wal] } 1041153eda0aSdan do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws] 1042153eda0aSdan } 104338e1a279Sdan} 1044153eda0aSdan 1045*d353331aSdan#------------------------------------------------------------------------- 1046*d353331aSdan# The following tests, pager1-8.*, test that the special filenames 1047*d353331aSdan# ":memory:" and "" open temporary databases. 1048*d353331aSdan# 10490e986f51Sdanforeach {tn filename} { 10500e986f51Sdan 1 :memory: 10510e986f51Sdan 2 "" 10520e986f51Sdan} { 10530e986f51Sdan do_test pager1-8.$tn.1 { 1054153eda0aSdan faultsim_delete_and_reopen 1055153eda0aSdan db close 10560e986f51Sdan sqlite3 db $filename 1057153eda0aSdan execsql { 1058153eda0aSdan CREATE TABLE x1(x); 1059153eda0aSdan INSERT INTO x1 VALUES('Charles'); 1060153eda0aSdan INSERT INTO x1 VALUES('James'); 1061153eda0aSdan INSERT INTO x1 VALUES('Mary'); 1062153eda0aSdan SELECT * FROM x1; 1063153eda0aSdan } 1064153eda0aSdan } {Charles James Mary} 10650e986f51Sdan 10660e986f51Sdan do_test pager1-8.$tn.2 { 10670e986f51Sdan sqlite3 db2 $filename 10680e986f51Sdan catchsql { SELECT * FROM x1 } db2 1069153eda0aSdan } {1 {no such table: x1}} 1070153eda0aSdan 10710e986f51Sdan do_execsql_test pager1-8.$tn.3 { 10720e986f51Sdan BEGIN; 10730e986f51Sdan INSERT INTO x1 VALUES('William'); 10740e986f51Sdan INSERT INTO x1 VALUES('Anne'); 10750e986f51Sdan ROLLBACK; 10760e986f51Sdan } {} 10770e986f51Sdan} 10780e986f51Sdan 1079dca321aeSdan#------------------------------------------------------------------------- 1080dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between 1081dca321aeSdan# the pager and the backup API. Test cases: 1082dca321aeSdan# 1083dca321aeSdan# pager1-9.1.*: Test that a backup completes successfully even if the 1084dca321aeSdan# source db is written to during the backup op. 1085dca321aeSdan# 1086dca321aeSdan# pager1-9.2.*: Test that a backup completes successfully even if the 1087dca321aeSdan# source db is written to and then rolled back during a 1088dca321aeSdan# backup operation. 1089dca321aeSdan# 1090dca321aeSdando_test pager1-9.0.1 { 1091dca321aeSdan faultsim_delete_and_reopen 1092dca321aeSdan db func a_string a_string 1093dca321aeSdan execsql { 1094dca321aeSdan PRAGMA cache_size = 10; 1095dca321aeSdan BEGIN; 1096dca321aeSdan CREATE TABLE ab(a, b, UNIQUE(a, b)); 1097dca321aeSdan INSERT INTO ab VALUES( a_string(200), a_string(300) ); 1098dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1099dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1100dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1101dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1102dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1103dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1104dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1105dca321aeSdan COMMIT; 1106dca321aeSdan } 1107dca321aeSdan} {} 1108dca321aeSdando_test pager1-9.0.2 { 1109dca321aeSdan sqlite3 db2 test.db2 1110dca321aeSdan db2 eval { PRAGMA cache_size = 10 } 1111dca321aeSdan sqlite3_backup B db2 main db main 1112dca321aeSdan list [B step 10000] [B finish] 1113dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1114dca321aeSdando_test pager1-9.0.3 { 1115dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1116dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1117dca321aeSdan 1118dca321aeSdando_test pager1-9.1.1 { 1119dca321aeSdan execsql { UPDATE ab SET a = a_string(201) } 1120dca321aeSdan sqlite3_backup B db2 main db main 1121dca321aeSdan B step 30 1122dca321aeSdan} {SQLITE_OK} 1123dca321aeSdando_test pager1-9.1.2 { 1124dca321aeSdan execsql { UPDATE ab SET b = a_string(301) } 1125dca321aeSdan list [B step 10000] [B finish] 1126dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1127dca321aeSdando_test pager1-9.1.3 { 1128dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1129dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1130dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128} 1131dca321aeSdan 1132dca321aeSdando_test pager1-9.2.1 { 1133dca321aeSdan execsql { UPDATE ab SET a = a_string(202) } 1134dca321aeSdan sqlite3_backup B db2 main db main 1135dca321aeSdan B step 30 1136dca321aeSdan} {SQLITE_OK} 1137dca321aeSdando_test pager1-9.2.2 { 1138dca321aeSdan execsql { 1139dca321aeSdan BEGIN; 1140dca321aeSdan UPDATE ab SET b = a_string(301); 1141dca321aeSdan ROLLBACK; 1142dca321aeSdan } 1143dca321aeSdan list [B step 10000] [B finish] 1144dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1145dca321aeSdando_test pager1-9.2.3 { 1146dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1147dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1148dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128} 1149ec6ffc1aSdandb close 1150ec6ffc1aSdandb2 close 1151ec6ffc1aSdan 1152ec6ffc1aSdan#------------------------------------------------------------------------- 1153ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the 1154ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes. 1155ec6ffc1aSdan# 1156ec6ffc1aSdantestvfs tv -default 1 1157ec6ffc1aSdanforeach sectorsize { 1158ec6ffc1aSdan 32 64 128 256 512 1024 2048 1159ec6ffc1aSdan 4096 8192 16384 32768 65536 131072 262144 1160ec6ffc1aSdan} { 1161ec6ffc1aSdan tv sectorsize $sectorsize 1162ec6ffc1aSdan set eff $sectorsize 1163ec6ffc1aSdan if {$sectorsize < 512} { set eff 512 } 1164ec6ffc1aSdan if {$sectorsize > 65536} { set eff 65536 } 1165ec6ffc1aSdan 1166ec6ffc1aSdan do_test pager1-10.$sectorsize { 1167ec6ffc1aSdan faultsim_delete_and_reopen 1168ec6ffc1aSdan execsql { 1169ec6ffc1aSdan PRAGMA journal_mode = PERSIST; 1170ec6ffc1aSdan PRAGMA page_size = 1024; 1171ec6ffc1aSdan CREATE TABLE t1(a, b); 1172ec6ffc1aSdan } 1173ec6ffc1aSdan file size test.db-journal 1174ec6ffc1aSdan } [expr $sectorsize > 65536 ? 65536 : $sectorsize] 1175ec6ffc1aSdan} 1176ec6ffc1aSdandb close 1177ec6ffc1aSdantv delete 1178ec6ffc1aSdan 1179ec6ffc1aSdantestvfs tv -default 1 1180ec6ffc1aSdanfaultsim_delete_and_reopen 1181ec6ffc1aSdandb func a_string a_string 1182ec6ffc1aSdando_execsql_test pager1-11.1 { 1183ec6ffc1aSdan PRAGMA cache_size = 10; 1184ec6ffc1aSdan BEGIN; 1185ec6ffc1aSdan CREATE TABLE zz(top PRIMARY KEY); 1186ec6ffc1aSdan INSERT INTO zz VALUES(a_string(222)); 1187ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1188ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1189ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1190ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1191ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1192ec6ffc1aSdan COMMIT; 1193ec6ffc1aSdan BEGIN; 1194ec6ffc1aSdan UPDATE zz SET top = a_string(345); 1195ec6ffc1aSdan} {} 1196ec6ffc1aSdan 1197ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR } 1198ec6ffc1aSdantv script lockout 1199ec6ffc1aSdantv filter {xWrite xTruncate xSync} 1200ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}} 1201ec6ffc1aSdan 1202ec6ffc1aSdantv script {} 1203ec6ffc1aSdando_test pager1-11.3 { 1204ec6ffc1aSdan sqlite3 db2 test.db 1205ec6ffc1aSdan execsql { 1206ec6ffc1aSdan PRAGMA journal_mode = TRUNCATE; 1207ec6ffc1aSdan PRAGMA integrity_check; 1208ec6ffc1aSdan } db2 1209ec6ffc1aSdan} {truncate ok} 1210ec6ffc1aSdando_test pager1-11.4 { 1211ec6ffc1aSdan db2 close 1212ec6ffc1aSdan file size test.db-journal 1213ec6ffc1aSdan} {0} 1214ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} 1215f9b4419dSdandb close 1216f9b4419dSdantv delete 1217ec6ffc1aSdan 1218f9b4419dSdan#------------------------------------------------------------------------- 1219f9b4419dSdan# Test "PRAGMA page_size" 1220f9b4419dSdan# 1221f9b4419dSdanforeach pagesize { 1222f9b4419dSdan 512 1024 2048 4096 8192 16384 32768 1223f9b4419dSdan} { 1224f9b4419dSdan faultsim_delete_and_reopen 1225f9b4419dSdan 1226f9b4419dSdan do_test pager1-12.$pagesize.1 { 1227f9b4419dSdan sqlite3 db2 test.db 1228f9b4419dSdan execsql " 1229f9b4419dSdan PRAGMA page_size = $pagesize; 1230f9b4419dSdan CREATE VIEW v AS SELECT * FROM sqlite_master; 1231f9b4419dSdan " db2 1232f9b4419dSdan file size test.db 1233f9b4419dSdan } $pagesize 1234f9b4419dSdan do_test pager1-12.$pagesize.2 { 1235f9b4419dSdan sqlite3 db2 test.db 1236f9b4419dSdan execsql { 1237f9b4419dSdan SELECT count(*) FROM v; 1238f9b4419dSdan PRAGMA main.page_size; 1239f9b4419dSdan } db2 1240f9b4419dSdan } [list 1 $pagesize] 1241f9b4419dSdan do_test pager1-12.$pagesize.3 { 1242f9b4419dSdan execsql { 1243f9b4419dSdan SELECT count(*) FROM v; 1244f9b4419dSdan PRAGMA main.page_size; 1245f9b4419dSdan } 1246f9b4419dSdan } [list 1 $pagesize] 1247f9b4419dSdan db2 close 1248f9b4419dSdan} 1249dca321aeSdan 1250*d353331aSdan#------------------------------------------------------------------------- 1251*d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases. 1252*d353331aSdan# 1253*d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent 1254*d353331aSdan# journal mode: If the journal associated with a transaction 1255*d353331aSdan# is smaller than the journal file (because a previous 1256*d353331aSdan# transaction left a very large non-hot journal file in the 1257*d353331aSdan# file-system), then SQLite has to be careful that there is 1258*d353331aSdan# not a journal-header left over from a previous transaction 1259*d353331aSdan# immediately following the journal content just written. 1260*d353331aSdan# If there is, and the process crashes so that the journal 1261*d353331aSdan# becomes a hot-journal and must be rolled back by another 1262*d353331aSdan# process, there is a danger that the other process may roll 1263*d353331aSdan# back the aborted transaction, then continue copying data 1264*d353331aSdan# from an older transaction from the remainder of the journal. 1265*d353331aSdan# See the syncJournal() function for details. 1266*d353331aSdan# 1267*d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into 1268*d353331aSdan# the mix to make the integrity-check more likely to catch 1269*d353331aSdan# errors. 1270*d353331aSdan# 1271*d353331aSdantestvfs tv -default 1 1272*d353331aSdantv script xSyncCb 1273*d353331aSdantv filter xSync 1274*d353331aSdanproc xSyncCb {method filename args} { 1275*d353331aSdan set t [file tail $filename] 1276*d353331aSdan if {$t == "test.db"} faultsim_save 1277*d353331aSdan return SQLITE_OK 1278*d353331aSdan} 1279*d353331aSdanfaultsim_delete_and_reopen 1280*d353331aSdandb func a_string a_string 1281e91a54e1Sdan 1282*d353331aSdan# The UPDATE statement at the end of this test case creates a really big 1283*d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains 1284*d353331aSdan# frequent journal headers. 1285*d353331aSdan# 1286*d353331aSdando_execsql_test pager1-13.1.1 { 1287*d353331aSdan PRAGMA page_size = 1024; 1288*d353331aSdan PRAGMA journal_mode = PERSIST; 1289*d353331aSdan PRAGMA cache_size = 10; 1290*d353331aSdan BEGIN; 1291*d353331aSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); 1292*d353331aSdan INSERT INTO t1 VALUES(NULL, a_string(400)); 1293*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 2 */ 1294*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 4 */ 1295*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 8 */ 1296*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 16 */ 1297*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 32 */ 1298*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 64 */ 1299*d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 128 */ 1300*d353331aSdan COMMIT; 1301*d353331aSdan UPDATE t1 SET b = a_string(400); 1302*d353331aSdan} {persist} 1303*d353331aSdan 1304*d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one) 1305*d353331aSdan# of these will write just enough content that one of the old headers created 1306*d353331aSdan# by the transaction in the block above lies immediately after the content 1307*d353331aSdan# journalled by the current transaction. 1308*d353331aSdan# 1309*d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1310*d353331aSdan do_execsql_test pager1-13.1.2.$nUp.1 { 1311*d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1312*d353331aSdan } {} 1313*d353331aSdan do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok} 1314*d353331aSdan 1315*d353331aSdan # Try to access the snapshot of the file-system. 1316*d353331aSdan # 1317*d353331aSdan sqlite3 db2 sv_test.db 1318*d353331aSdan do_test pager1-13.1.2.$nUp.3 { 1319*d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1320*d353331aSdan } [expr {128*400 - ($nUp-1)}] 1321*d353331aSdan do_test pager1-13.1.2.$nUp.4 { 1322*d353331aSdan execsql { PRAGMA integrity_check } db2 1323*d353331aSdan } {ok} 1324*d353331aSdan db2 close 1325*d353331aSdan} 1326*d353331aSdan 1327*d353331aSdan# Same test as above. But this time with an index on the table. 1328*d353331aSdan# 1329*d353331aSdando_execsql_test pager1-13.2.1 { 1330*d353331aSdan CREATE INDEX i1 ON t1(b); 1331*d353331aSdan UPDATE t1 SET b = a_string(400); 1332*d353331aSdan} {} 1333*d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1334*d353331aSdan do_execsql_test pager1-13.2.2.$nUp.1 { 1335*d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1336*d353331aSdan } {} 1337*d353331aSdan do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok} 1338*d353331aSdan sqlite3 db2 sv_test.db 1339*d353331aSdan do_test pager1-13.2.2.$nUp.3 { 1340*d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1341*d353331aSdan } [expr {128*400 - ($nUp-1)}] 1342*d353331aSdan do_test pager1-13.2.2.$nUp.4 { 1343*d353331aSdan execsql { PRAGMA integrity_check } db2 1344*d353331aSdan } {ok} 1345*d353331aSdan db2 close 1346*d353331aSdan} 1347*d353331aSdan 1348*d353331aSdandb close 1349*d353331aSdantv delete 1350*d353331aSdan 1351*d353331aSdan#------------------------------------------------------------------------- 1352*d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases. 1353*d353331aSdan# 1354*d353331aSdanfaultsim_delete_and_reopen 1355*d353331aSdando_execsql_test pager1-14.1.1 { 1356*d353331aSdan PRAGMA journal_mode = OFF; 1357*d353331aSdan CREATE TABLE t1(a, b); 1358*d353331aSdan BEGIN; 1359*d353331aSdan INSERT INTO t1 VALUES(1, 2); 1360*d353331aSdan COMMIT; 1361*d353331aSdan SELECT * FROM t1; 1362*d353331aSdan} {off 1 2} 1363*d353331aSdando_catchsql_test pager1-14.1.2 { 1364*d353331aSdan BEGIN; 1365*d353331aSdan INSERT INTO t1 VALUES(3, 4); 1366*d353331aSdan ROLLBACK; 1367*d353331aSdan} {0 {}} 1368*d353331aSdando_execsql_test pager1-14.1.3 { 1369*d353331aSdan SELECT * FROM t1; 1370*d353331aSdan} {1 2 3 4} 1371*d353331aSdando_catchsql_test pager1-14.1.4 { 1372*d353331aSdan BEGIN; 1373*d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1374*d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1375*d353331aSdan} {1 {PRIMARY KEY must be unique}} 1376*d353331aSdando_execsql_test pager1-14.1.5 { 1377*d353331aSdan COMMIT; 1378*d353331aSdan SELECT * FROM t1; 1379*d353331aSdan} {1 2 3 4 2 2 4 4} 1380*d353331aSdan 1381*d353331aSdanfinish_test 1382