1e91a54e1Sdan# 2010 June 15 2e91a54e1Sdan# 3e91a54e1Sdan# The author disclaims copyright to this source code. In place of 4e91a54e1Sdan# a legal notice, here is a blessing: 5e91a54e1Sdan# 6e91a54e1Sdan# May you do good and not evil. 7e91a54e1Sdan# May you find forgiveness for yourself and forgive others. 8e91a54e1Sdan# May you share freely, never taking more than you give. 9e91a54e1Sdan# 10e91a54e1Sdan#*********************************************************************** 11e91a54e1Sdan# 12e91a54e1Sdan 13e91a54e1Sdanset testdir [file dirname $argv0] 14e91a54e1Sdansource $testdir/tester.tcl 15e91a54e1Sdansource $testdir/lock_common.tcl 16e91a54e1Sdansource $testdir/malloc_common.tcl 17153eda0aSdansource $testdir/wal_common.tcl 1868928b6cSdan 1968928b6cSdan# Do not use a codec for tests in this file, as the database file is 2068928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command). 2168928b6cSdan# 2268928b6cSdando_not_use_codec 23e91a54e1Sdan 24b0ac3e3aSdan# 25b0ac3e3aSdan# pager1-1.*: Test inter-process locking (clients in multiple processes). 26b0ac3e3aSdan# 27b0ac3e3aSdan# pager1-2.*: Test intra-process locking (multiple clients in this process). 28b0ac3e3aSdan# 29b0ac3e3aSdan# pager1-3.*: Savepoint related tests. 30b0ac3e3aSdan# 311f4cb65aSdan# pager1-4.*: Hot-journal related tests. 321f4cb65aSdan# 33de4996e2Sdan# pager1-5.*: Cases related to multi-file commits. 34de4996e2Sdan# 35146ed78bSdan# pager1-6.*: Cases related to "PRAGMA max_page_count" 36146ed78bSdan# 37153eda0aSdan# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE" 38153eda0aSdan# 390e986f51Sdan# pager1-8.*: Cases using temporary and in-memory databases. 400e986f51Sdan# 41dca321aeSdan# pager1-9.*: Tests related to the backup API. 42dca321aeSdan# 43ec6ffc1aSdan# pager1-10.*: Test that the assumed file-system sector-size is limited to 44ec6ffc1aSdan# 64KB. 45ec6ffc1aSdan# 46d353331aSdan# pager1-12.*: Tests involving "PRAGMA page_size" 47d353331aSdan# 48d353331aSdan# pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST" 49d353331aSdan# 50d353331aSdan# pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF" 51ec6ffc1aSdan# 52c8ce3972Sdan# pager1-15.*: Varying sqlite3_vfs.szOsFile 53c8ce3972Sdan# 54c8ce3972Sdan# pager1-16.*: Varying sqlite3_vfs.mxPathname 55c8ce3972Sdan# 56c8ce3972Sdan# pager1-17.*: Tests related to "PRAGMA omit_readlock" 57c8ce3972Sdan# 58c8ce3972Sdan# pager1-18.*: Test that the pager layer responds correctly if the b-tree 59c8ce3972Sdan# requests an invalid page number (due to db corruption). 60c8ce3972Sdan# 61b0ac3e3aSdan 62c396d4afSdanproc recursive_select {id table {script {}}} { 63c396d4afSdan set cnt 0 64c396d4afSdan db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" { 65c396d4afSdan recursive_select $rowid $table $script 66c396d4afSdan incr cnt 67c396d4afSdan } 68c396d4afSdan if {$cnt==0} { eval $script } 69c396d4afSdan} 70c396d4afSdan 7153f04f3bSdanset a_string_counter 1 7253f04f3bSdanproc a_string {n} { 7353f04f3bSdan global a_string_counter 7453f04f3bSdan incr a_string_counter 7553f04f3bSdan string range [string repeat "${a_string_counter}." $n] 1 $n 7653f04f3bSdan} 7753f04f3bSdandb func a_string a_string 7853f04f3bSdan 79a4a9095eSdando_multiclient_test tn { 80e91a54e1Sdan 81e91a54e1Sdan # Create and populate a database table using connection [db]. Check 82e91a54e1Sdan # that connections [db2] and [db3] can see the schema and content. 83e91a54e1Sdan # 84e91a54e1Sdan do_test pager1-$tn.1 { 85e91a54e1Sdan sql1 { 86e91a54e1Sdan CREATE TABLE t1(a PRIMARY KEY, b); 87e91a54e1Sdan CREATE INDEX i1 ON t1(b); 88d353331aSdan INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); 89e91a54e1Sdan } 90e91a54e1Sdan } {} 91e91a54e1Sdan do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two} 92e91a54e1Sdan do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two} 93e91a54e1Sdan 94e91a54e1Sdan # Open a transaction and add a row using [db]. This puts [db] in 95e91a54e1Sdan # RESERVED state. Check that connections [db2] and [db3] can still 96e91a54e1Sdan # read the database content as it was before the transaction was 97e91a54e1Sdan # opened. [db] should see the inserted row. 98e91a54e1Sdan # 99e91a54e1Sdan do_test pager1-$tn.4 { 100e91a54e1Sdan sql1 { 101e91a54e1Sdan BEGIN; 102e91a54e1Sdan INSERT INTO t1 VALUES(3, 'three'); 103e91a54e1Sdan } 104e91a54e1Sdan } {} 105e91a54e1Sdan do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two} 106e91a54e1Sdan do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three} 107e91a54e1Sdan 108e91a54e1Sdan # [db] still has an open write transaction. Check that this prevents 109e91a54e1Sdan # other connections (specifically [db2]) from writing to the database. 110e91a54e1Sdan # 111e91a54e1Sdan # Even if [db2] opens a transaction first, it may not write to the 112e91a54e1Sdan # database. After the attempt to write the db within a transaction, 113e91a54e1Sdan # [db2] is left with an open transaction, but not a read-lock on 114e91a54e1Sdan # the main database. So it does not prevent [db] from committing. 115e91a54e1Sdan # 116e91a54e1Sdan do_test pager1-$tn.8 { 117e91a54e1Sdan csql2 { UPDATE t1 SET a = a + 10 } 118e91a54e1Sdan } {1 {database is locked}} 119e91a54e1Sdan do_test pager1-$tn.9 { 120e91a54e1Sdan csql2 { 121e91a54e1Sdan BEGIN; 122e91a54e1Sdan UPDATE t1 SET a = a + 10; 123e91a54e1Sdan } 124e91a54e1Sdan } {1 {database is locked}} 125e91a54e1Sdan 126e91a54e1Sdan # Have [db] commit its transactions. Check the other connections can 127e91a54e1Sdan # now see the new database content. 128e91a54e1Sdan # 129e91a54e1Sdan do_test pager1-$tn.10 { sql1 { COMMIT } } {} 130e91a54e1Sdan do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three} 131e91a54e1Sdan do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 132e91a54e1Sdan do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 133e91a54e1Sdan 134e91a54e1Sdan # Check that, as noted above, [db2] really did keep an open transaction 135e91a54e1Sdan # after the attempt to write the database failed. 136e91a54e1Sdan # 137e91a54e1Sdan do_test pager1-$tn.14 { 138e91a54e1Sdan csql2 { BEGIN } 139e91a54e1Sdan } {1 {cannot start a transaction within a transaction}} 140e91a54e1Sdan do_test pager1-$tn.15 { sql2 { ROLLBACK } } {} 141e91a54e1Sdan 142e91a54e1Sdan # Have [db2] open a transaction and take a read-lock on the database. 143e91a54e1Sdan # Check that this prevents [db] from writing to the database (outside 144e91a54e1Sdan # of any transaction). After this fails, check that [db3] can read 145e91a54e1Sdan # the db (showing that [db] did not take a PENDING lock etc.) 146e91a54e1Sdan # 147e91a54e1Sdan do_test pager1-$tn.15 { 148e91a54e1Sdan sql2 { BEGIN; SELECT * FROM t1; } 149e91a54e1Sdan } {1 one 2 two 3 three} 150e91a54e1Sdan do_test pager1-$tn.16 { 151e91a54e1Sdan csql1 { UPDATE t1 SET a = a + 10 } 152e91a54e1Sdan } {1 {database is locked}} 153e91a54e1Sdan do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 154e91a54e1Sdan 155e91a54e1Sdan # This time, have [db] open a transaction before writing the database. 156e91a54e1Sdan # This works - [db] gets a RESERVED lock which does not conflict with 157e91a54e1Sdan # the SHARED lock [db2] is holding. 158e91a54e1Sdan # 159e91a54e1Sdan do_test pager1-$tn.18 { 160e91a54e1Sdan sql1 { 161e91a54e1Sdan BEGIN; 162e91a54e1Sdan UPDATE t1 SET a = a + 10; 163e91a54e1Sdan } 164e91a54e1Sdan } {} 165e91a54e1Sdan do_test pager1-$tn-19 { 166e91a54e1Sdan sql1 { PRAGMA lock_status } 167e91a54e1Sdan } {main reserved temp closed} 168e91a54e1Sdan do_test pager1-$tn-20 { 169e91a54e1Sdan sql2 { PRAGMA lock_status } 170e91a54e1Sdan } {main shared temp closed} 171e91a54e1Sdan 172e91a54e1Sdan # Check that all connections can still read the database. Only [db] sees 173e91a54e1Sdan # the updated content (as the transaction has not been committed yet). 174e91a54e1Sdan # 175e91a54e1Sdan do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three} 176e91a54e1Sdan do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 177e91a54e1Sdan do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 178e91a54e1Sdan 179e91a54e1Sdan # Because [db2] still has the SHARED lock, [db] is unable to commit the 180e91a54e1Sdan # transaction. If it tries, an error is returned and the connection 181e91a54e1Sdan # upgrades to a PENDING lock. 182e91a54e1Sdan # 183e91a54e1Sdan # Once this happens, [db] can read the database and see the new content, 184e91a54e1Sdan # [db2] (still holding SHARED) can still read the old content, but [db3] 185e91a54e1Sdan # (not holding any lock) is prevented by [db]'s PENDING from reading 186e91a54e1Sdan # the database. 187e91a54e1Sdan # 188e91a54e1Sdan do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}} 189e91a54e1Sdan do_test pager1-$tn-25 { 190e91a54e1Sdan sql1 { PRAGMA lock_status } 191e91a54e1Sdan } {main pending temp closed} 192e91a54e1Sdan do_test pager1-$tn.26 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three} 193e91a54e1Sdan do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 194e91a54e1Sdan do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}} 195e91a54e1Sdan 196e91a54e1Sdan # Have [db2] commit its read transaction, releasing the SHARED lock it 197e91a54e1Sdan # is holding. Now, neither [db2] nor [db3] may read the database (as [db] 198e91a54e1Sdan # is still holding a PENDING). 199e91a54e1Sdan # 200e91a54e1Sdan do_test pager1-$tn.29 { sql2 { COMMIT } } {} 201e91a54e1Sdan do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}} 202e91a54e1Sdan do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}} 203e91a54e1Sdan 204e91a54e1Sdan # [db] is now able to commit the transaction. Once the transaction is 205e91a54e1Sdan # committed, all three connections can read the new content. 206e91a54e1Sdan # 207e91a54e1Sdan do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {} 208e91a54e1Sdan do_test pager1-$tn.26 { sql1 { COMMIT } } {} 209e91a54e1Sdan do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three} 210e91a54e1Sdan do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three} 211e91a54e1Sdan do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three} 212d353331aSdan 213d353331aSdan # Install a busy-handler for connection [db]. 214d353331aSdan # 215d353331aSdan set ::nbusy [list] 216d353331aSdan proc busy {n} { 217d353331aSdan lappend ::nbusy $n 218d353331aSdan if {$n>5} { sql2 COMMIT } 219d353331aSdan return 0 220d353331aSdan } 221d353331aSdan db busy busy 222d353331aSdan 223d353331aSdan do_test pager1-$tn.29 { 224d353331aSdan sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') } 225d353331aSdan } {} 226d353331aSdan do_test pager1-$tn.30 { 227d353331aSdan sql2 { BEGIN ; SELECT * FROM t1 } 228d353331aSdan } {21 one 22 two 23 three} 229d353331aSdan do_test pager1-$tn.31 { sql1 COMMIT } {} 230d353331aSdan do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6} 231e91a54e1Sdan} 232e91a54e1Sdan 23353f04f3bSdan#------------------------------------------------------------------------- 23453f04f3bSdan# Savepoint related test cases. 23553f04f3bSdan# 236dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file 237dca321aeSdan# to grow. 238dca321aeSdan# 239273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part 240273f3f0dSdan# of a savepoint rollback. 241273f3f0dSdan# 2420e986f51Sdando_test pager1-3.1.1 { 243b0ac3e3aSdan faultsim_delete_and_reopen 244b0ac3e3aSdan execsql { 245b0ac3e3aSdan CREATE TABLE t1(a PRIMARY KEY, b); 246b0ac3e3aSdan CREATE TABLE counter( 247b0ac3e3aSdan i CHECK (i<5), 248b0ac3e3aSdan u CHECK (u<10) 249b0ac3e3aSdan ); 250b0ac3e3aSdan INSERT INTO counter VALUES(0, 0); 251b0ac3e3aSdan CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN 252b0ac3e3aSdan UPDATE counter SET i = i+1; 253b0ac3e3aSdan END; 254b0ac3e3aSdan CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN 255b0ac3e3aSdan UPDATE counter SET u = u+1; 256b0ac3e3aSdan END; 257b0ac3e3aSdan } 258b0ac3e3aSdan execsql { SELECT * FROM counter } 259b0ac3e3aSdan} {0 0} 260b0ac3e3aSdan 2610e986f51Sdando_execsql_test pager1-3.1.2 { 262d353331aSdan PRAGMA cache_size = 10; 263b0ac3e3aSdan BEGIN; 264b0ac3e3aSdan INSERT INTO t1 VALUES(1, randomblob(1500)); 265b0ac3e3aSdan INSERT INTO t1 VALUES(2, randomblob(1500)); 266b0ac3e3aSdan INSERT INTO t1 VALUES(3, randomblob(1500)); 267b0ac3e3aSdan SELECT * FROM counter; 268b0ac3e3aSdan} {3 0} 2690e986f51Sdando_catchsql_test pager1-3.1.3 { 270b0ac3e3aSdan INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1 271b0ac3e3aSdan} {1 {constraint failed}} 272b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} 273b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} 274b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {} 275b0ac3e3aSdan 276273f3f0dSdanforeach {tn sql tcl} { 277d353331aSdan 7 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } { 278273f3f0dSdan testvfs tv -default 1 279273f3f0dSdan tv devchar safe_append 280273f3f0dSdan } 281d353331aSdan 8 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } { 282d353331aSdan testvfs tv -default 1 283d353331aSdan tv devchar sequential 284d353331aSdan } 285d353331aSdan 9 { PRAGMA synchronous = FULL } { } 286d353331aSdan 10 { PRAGMA synchronous = NORMAL } { } 287d353331aSdan 11 { PRAGMA synchronous = OFF } { } 288d353331aSdan 12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { } 289d353331aSdan 13 { PRAGMA synchronous = FULL } { 290d353331aSdan testvfs tv -default 1 291d353331aSdan tv devchar sequential 292d353331aSdan } 2936b63ab47Sdan 14 { PRAGMA locking_mode = EXCLUSIVE } { 2946b63ab47Sdan } 295273f3f0dSdan} { 296273f3f0dSdan do_test pager1-3.$tn.1 { 297273f3f0dSdan eval $tcl 298dca321aeSdan faultsim_delete_and_reopen 299dca321aeSdan db func a_string a_string 300273f3f0dSdan execsql $sql 301dca321aeSdan execsql { 302dca321aeSdan PRAGMA auto_vacuum = 2; 303dca321aeSdan PRAGMA cache_size = 10; 304dca321aeSdan CREATE TABLE z(x INTEGER PRIMARY KEY, y); 305dca321aeSdan BEGIN; 306dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 307dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 2 308dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 4 309dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 8 310dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 16 311dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 32 312dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 64 313dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 128 314dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 256 315dca321aeSdan COMMIT; 316dca321aeSdan } 317dca321aeSdan execsql { PRAGMA auto_vacuum } 318dca321aeSdan } {2} 319273f3f0dSdan do_execsql_test pager1-3.$tn.2 { 320dca321aeSdan BEGIN; 321dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 322dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 323dca321aeSdan SAVEPOINT one; 324273f3f0dSdan UPDATE z SET y = NULL WHERE x>256; 325dca321aeSdan PRAGMA incremental_vacuum; 326dca321aeSdan SELECT count(*) FROM z WHERE x < 100; 327dca321aeSdan ROLLBACK TO one; 328dca321aeSdan COMMIT; 329dca321aeSdan } {99} 330dca321aeSdan 331273f3f0dSdan do_execsql_test pager1-3.$tn.3 { 332273f3f0dSdan BEGIN; 333273f3f0dSdan SAVEPOINT one; 334273f3f0dSdan UPDATE z SET y = y||x; 335273f3f0dSdan ROLLBACK TO one; 336273f3f0dSdan COMMIT; 337273f3f0dSdan SELECT count(*) FROM z; 338273f3f0dSdan } {258} 339273f3f0dSdan 340273f3f0dSdan do_execsql_test pager1-3.$tn.4 { 341273f3f0dSdan SAVEPOINT one; 342273f3f0dSdan UPDATE z SET y = y||x; 343273f3f0dSdan ROLLBACK TO one; 344273f3f0dSdan } {} 345273f3f0dSdan do_execsql_test pager1-3.$tn.5 { 346273f3f0dSdan SELECT count(*) FROM z; 347273f3f0dSdan RELEASE one; 348273f3f0dSdan PRAGMA integrity_check; 349273f3f0dSdan } {258 ok} 350273f3f0dSdan 35178f1e538Sdan do_execsql_test pager1-3.$tn.6 { 35278f1e538Sdan SAVEPOINT one; 35378f1e538Sdan RELEASE one; 35478f1e538Sdan } {} 35578f1e538Sdan 356273f3f0dSdan db close 357273f3f0dSdan catch { tv delete } 358273f3f0dSdan} 359273f3f0dSdan 36053f04f3bSdan#------------------------------------------------------------------------- 36153f04f3bSdan# Hot journal rollback related test cases. 36253f04f3bSdan# 36353f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid 36453f04f3bSdan# journal files. 36553f04f3bSdan# 36653f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a 36753f04f3bSdan# hot-journal file appears to be corrupt (checksum does not 36853f04f3bSdan# compute) the associated journal is rolled back (and no 36953f04f3bSdan# xAccess() call to check for the presence of any master 37053f04f3bSdan# journal file is made). 37153f04f3bSdan# 372de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the 373de4996e2Sdan# page-size or sector-size in the journal header appear to 374de4996e2Sdan# be invalid (too large, too small or not a power of 2). 375de4996e2Sdan# 376e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master 377e08341c6Sdan# journal pointer generated in various "PRAGMA synchronous" 378e08341c6Sdan# modes. 379e08341c6Sdan# 380e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a 381e08341c6Sdan# journal-record for which the checksum fails. 382e08341c6Sdan# 383ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a 384ec6ffc1aSdan# master journal pointer, the master journal file is deleted 385ec6ffc1aSdan# after all the hot-journals that refer to it are deleted. 386ec6ffc1aSdan# 387c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can 388c8ce3972Sdan# open it for reading only, the database cannot be accessed and 389c8ce3972Sdan# SQLITE_CANTOPEN is returned. 390c8ce3972Sdan# 39153f04f3bSdando_test pager1.4.1.1 { 39253f04f3bSdan faultsim_delete_and_reopen 39353f04f3bSdan execsql { 39453f04f3bSdan CREATE TABLE x(y, z); 39553f04f3bSdan INSERT INTO x VALUES(1, 2); 39653f04f3bSdan } 39753f04f3bSdan set fd [open test.db-journal w] 39853f04f3bSdan puts -nonewline $fd "helloworld" 39953f04f3bSdan close $fd 40053f04f3bSdan file exists test.db-journal 40153f04f3bSdan} {1} 40253f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2} 40353f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0} 40453f04f3bSdan 40553f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite 40653f04f3bSdan# deletes the master-journal to commit a multi-file transaction. 40753f04f3bSdan# 40853f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets 40953f04f3bSdan# up the file system to contain two databases, two hot-journal files and 41053f04f3bSdan# a master-journal. 41153f04f3bSdan# 41253f04f3bSdando_test pager1.4.2.1 { 41353f04f3bSdan testvfs tstvfs -default 1 41453f04f3bSdan tstvfs filter xDelete 41553f04f3bSdan tstvfs script xDeleteCallback 41653f04f3bSdan proc xDeleteCallback {method file args} { 41753f04f3bSdan set file [file tail $file] 41853f04f3bSdan if { [string match *mj* $file] } { faultsim_save } 41953f04f3bSdan } 42053f04f3bSdan faultsim_delete_and_reopen 42153f04f3bSdan db func a_string a_string 42253f04f3bSdan execsql { 42353f04f3bSdan ATTACH 'test.db2' AS aux; 42453f04f3bSdan PRAGMA journal_mode = DELETE; 42553f04f3bSdan PRAGMA main.cache_size = 10; 42653f04f3bSdan PRAGMA aux.cache_size = 10; 42753f04f3bSdan CREATE TABLE t1(a UNIQUE, b UNIQUE); 42853f04f3bSdan CREATE TABLE aux.t2(a UNIQUE, b UNIQUE); 42953f04f3bSdan INSERT INTO t1 VALUES(a_string(200), a_string(300)); 43053f04f3bSdan INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 43153f04f3bSdan INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 43253f04f3bSdan INSERT INTO t2 SELECT * FROM t1; 43353f04f3bSdan BEGIN; 43453f04f3bSdan INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; 43553f04f3bSdan INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; 43653f04f3bSdan INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; 43753f04f3bSdan INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; 43853f04f3bSdan REPLACE INTO t2 SELECT * FROM t1; 43953f04f3bSdan COMMIT; 44053f04f3bSdan } 44153f04f3bSdan db close 44253f04f3bSdan tstvfs delete 44353f04f3bSdan} {} 444b2f20bfcSshaneh 445b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} { 44653f04f3bSdando_test pager1.4.2.2 { 44753f04f3bSdan faultsim_restore_and_reopen 44853f04f3bSdan execsql { 44953f04f3bSdan SELECT count(*) FROM t1; 45053f04f3bSdan PRAGMA integrity_check; 45153f04f3bSdan } 45253f04f3bSdan} {4 ok} 45353f04f3bSdando_test pager1.4.2.3 { 45453f04f3bSdan faultsim_restore_and_reopen 455*fda06befSmistachkin foreach f [glob test.db-mj*] { forcedelete $f } 45653f04f3bSdan execsql { 45753f04f3bSdan SELECT count(*) FROM t1; 45853f04f3bSdan PRAGMA integrity_check; 45953f04f3bSdan } 46053f04f3bSdan} {64 ok} 46153f04f3bSdando_test pager1.4.2.4 { 46253f04f3bSdan faultsim_restore_and_reopen 46353f04f3bSdan hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 46453f04f3bSdan execsql { 46553f04f3bSdan SELECT count(*) FROM t1; 46653f04f3bSdan PRAGMA integrity_check; 46753f04f3bSdan } 46853f04f3bSdan} {4 ok} 46953f04f3bSdando_test pager1.4.2.5 { 47053f04f3bSdan faultsim_restore_and_reopen 47153f04f3bSdan hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 472*fda06befSmistachkin foreach f [glob test.db-mj*] { forcedelete $f } 47353f04f3bSdan execsql { 47453f04f3bSdan SELECT count(*) FROM t1; 47553f04f3bSdan PRAGMA integrity_check; 47653f04f3bSdan } 47753f04f3bSdan} {4 ok} 478b2f20bfcSshaneh} 47953f04f3bSdan 480de4996e2Sdando_test pager1.4.3.1 { 481de4996e2Sdan testvfs tstvfs -default 1 482de4996e2Sdan tstvfs filter xSync 483de4996e2Sdan tstvfs script xSyncCallback 484de4996e2Sdan proc xSyncCallback {method file args} { 485de4996e2Sdan set file [file tail $file] 486de4996e2Sdan if { 0==[string match *journal $file] } { faultsim_save } 487de4996e2Sdan } 488de4996e2Sdan faultsim_delete_and_reopen 489de4996e2Sdan execsql { 490de4996e2Sdan PRAGMA journal_mode = DELETE; 491de4996e2Sdan CREATE TABLE t1(a, b); 492de4996e2Sdan INSERT INTO t1 VALUES(1, 2); 493de4996e2Sdan INSERT INTO t1 VALUES(3, 4); 494de4996e2Sdan } 495de4996e2Sdan db close 496de4996e2Sdan tstvfs delete 497de4996e2Sdan} {} 498de4996e2Sdan 499de4996e2Sdanforeach {tn ofst value result} { 500de4996e2Sdan 2 20 31 {1 2 3 4} 501de4996e2Sdan 3 20 32 {1 2 3 4} 502de4996e2Sdan 4 20 33 {1 2 3 4} 503de4996e2Sdan 5 20 65536 {1 2 3 4} 504de4996e2Sdan 6 20 131072 {1 2 3 4} 505de4996e2Sdan 506de4996e2Sdan 7 24 511 {1 2 3 4} 507de4996e2Sdan 8 24 513 {1 2 3 4} 508b2eced5dSdrh 9 24 131072 {1 2 3 4} 509de4996e2Sdan 510de4996e2Sdan 10 32 65536 {1 2} 511de4996e2Sdan} { 512de4996e2Sdan do_test pager1.4.3.$tn { 513de4996e2Sdan faultsim_restore_and_reopen 514de4996e2Sdan hexio_write test.db-journal $ofst [format %.8x $value] 515de4996e2Sdan execsql { SELECT * FROM t1 } 516de4996e2Sdan } $result 517de4996e2Sdan} 518de4996e2Sdandb close 519de4996e2Sdan 520e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal 521e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the 522e08341c6Sdan# file-system is saved just before the xDelete() call to remove the 523e08341c6Sdan# master journal file from the file-system. 524e08341c6Sdan# 525e08341c6Sdantestvfs tv -default 1 526e08341c6Sdantv script copy_on_mj_delete 527e08341c6Sdanset ::mj_filename_length 0 528e08341c6Sdanproc copy_on_mj_delete {method filename args} { 529e08341c6Sdan if {[string match *mj* [file tail $filename]]} { 530e08341c6Sdan set ::mj_filename_length [string length $filename] 531e08341c6Sdan faultsim_save 532e08341c6Sdan } 533e08341c6Sdan return SQLITE_OK 534e08341c6Sdan} 535e08341c6Sdan 536e08341c6Sdanset pwd [pwd] 537e08341c6Sdanforeach {tn1 tcl} { 538e08341c6Sdan 1 { set prefix "test.db" } 539e08341c6Sdan 2 { 540e08341c6Sdan # This test depends on the underlying VFS being able to open paths 541e08341c6Sdan # 512 bytes in length. The idea is to create a hot-journal file that 542e08341c6Sdan # contains a master-journal pointer so large that it could contain 543e08341c6Sdan # a valid page record (if the file page-size is 512 bytes). So as to 544e08341c6Sdan # make sure SQLite doesn't get confused by this. 545e08341c6Sdan # 546e08341c6Sdan set nPadding [expr 511 - $::mj_filename_length] 54733d85c9cSshaneh if {$tcl_platform(platform)=="windows"} { 54833d85c9cSshaneh # TBD need to figure out how to do this correctly for Windows!!! 54933d85c9cSshaneh set nPadding [expr 255 - $::mj_filename_length] 55033d85c9cSshaneh } 551e08341c6Sdan 552e08341c6Sdan # We cannot just create a really long database file name to open, as 553e08341c6Sdan # Linux limits a single component of a path to 255 bytes by default 554e08341c6Sdan # (and presumably other systems have limits too). So create a directory 555e08341c6Sdan # hierarchy to work in. 556e08341c6Sdan # 557e08341c6Sdan set dirname "d123456789012345678901234567890/" 558e08341c6Sdan set nDir [expr $nPadding / 32] 559e08341c6Sdan if { $nDir } { 560e08341c6Sdan set p [string repeat $dirname $nDir] 561e08341c6Sdan file mkdir $p 562e08341c6Sdan cd $p 563e08341c6Sdan } 564e08341c6Sdan 565e08341c6Sdan set padding [string repeat x [expr $nPadding %32]] 566e08341c6Sdan set prefix "test.db${padding}" 567e08341c6Sdan } 568e08341c6Sdan} { 569e08341c6Sdan eval $tcl 570e08341c6Sdan foreach {tn2 sql} { 571e08341c6Sdan o { 572e08341c6Sdan PRAGMA main.synchronous=OFF; 573e08341c6Sdan PRAGMA aux.synchronous=OFF; 5743f94b609Sdan PRAGMA journal_mode = DELETE; 575e08341c6Sdan } 576e08341c6Sdan o512 { 577e08341c6Sdan PRAGMA main.synchronous=OFF; 578e08341c6Sdan PRAGMA aux.synchronous=OFF; 579e08341c6Sdan PRAGMA main.page_size = 512; 580e08341c6Sdan PRAGMA aux.page_size = 512; 5813f94b609Sdan PRAGMA journal_mode = DELETE; 582e08341c6Sdan } 583e08341c6Sdan n { 584e08341c6Sdan PRAGMA main.synchronous=NORMAL; 585e08341c6Sdan PRAGMA aux.synchronous=NORMAL; 5863f94b609Sdan PRAGMA journal_mode = DELETE; 587e08341c6Sdan } 588e08341c6Sdan f { 589e08341c6Sdan PRAGMA main.synchronous=FULL; 590e08341c6Sdan PRAGMA aux.synchronous=FULL; 5913f94b609Sdan PRAGMA journal_mode = DELETE; 592e08341c6Sdan } 593e08341c6Sdan } { 594e08341c6Sdan 595e08341c6Sdan set tn "${tn1}.${tn2}" 596e08341c6Sdan 597e08341c6Sdan # Set up a connection to have two databases, test.db (main) and 598e08341c6Sdan # test.db2 (aux). Then run a multi-file transaction on them. The 599e08341c6Sdan # VFS will snapshot the file-system just before the master-journal 600e08341c6Sdan # file is deleted to commit the transaction. 601e08341c6Sdan # 602e08341c6Sdan tv filter xDelete 603e08341c6Sdan do_test pager1-4.4.$tn.1 { 604e08341c6Sdan faultsim_delete_and_reopen $prefix 605e08341c6Sdan execsql " 606e08341c6Sdan ATTACH '${prefix}2' AS aux; 607e08341c6Sdan $sql 608e08341c6Sdan CREATE TABLE a(x); 609e08341c6Sdan CREATE TABLE aux.b(x); 610e08341c6Sdan INSERT INTO a VALUES('double-you'); 611e08341c6Sdan INSERT INTO a VALUES('why'); 612e08341c6Sdan INSERT INTO a VALUES('zed'); 613e08341c6Sdan INSERT INTO b VALUES('won'); 614e08341c6Sdan INSERT INTO b VALUES('too'); 615e08341c6Sdan INSERT INTO b VALUES('free'); 616e08341c6Sdan " 617e08341c6Sdan execsql { 618e08341c6Sdan BEGIN; 619e08341c6Sdan INSERT INTO a SELECT * FROM b WHERE rowid<=3; 620e08341c6Sdan INSERT INTO b SELECT * FROM a WHERE rowid<=3; 621e08341c6Sdan COMMIT; 622e08341c6Sdan } 623e08341c6Sdan } {} 624e08341c6Sdan tv filter {} 625e08341c6Sdan 626e08341c6Sdan # Check that the transaction was committed successfully. 627e08341c6Sdan # 628e08341c6Sdan do_execsql_test pager1-4.4.$tn.2 { 629e08341c6Sdan SELECT * FROM a 630e08341c6Sdan } {double-you why zed won too free} 631e08341c6Sdan do_execsql_test pager1-4.4.$tn.3 { 632e08341c6Sdan SELECT * FROM b 633e08341c6Sdan } {won too free double-you why zed} 634e08341c6Sdan 635e08341c6Sdan # Restore the file-system and reopen the databases. Check that it now 636e08341c6Sdan # appears that the transaction was not committed (because the file-system 637e08341c6Sdan # was restored to the state where it had not been). 638e08341c6Sdan # 639e08341c6Sdan do_test pager1-4.4.$tn.4 { 640e08341c6Sdan faultsim_restore_and_reopen $prefix 641e08341c6Sdan execsql "ATTACH '${prefix}2' AS aux" 642e08341c6Sdan } {} 643e08341c6Sdan do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed} 644e08341c6Sdan do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free} 645e08341c6Sdan 646e08341c6Sdan # Restore the file-system again. This time, before reopening the databases, 647e08341c6Sdan # delete the master-journal file from the file-system. It now appears that 648e08341c6Sdan # the transaction was committed (no master-journal file == no rollback). 649e08341c6Sdan # 650e08341c6Sdan do_test pager1-4.4.$tn.7 { 651e08341c6Sdan faultsim_restore_and_reopen $prefix 652*fda06befSmistachkin foreach f [glob ${prefix}-mj*] { forcedelete $f } 653e08341c6Sdan execsql "ATTACH '${prefix}2' AS aux" 654e08341c6Sdan } {} 655e08341c6Sdan do_execsql_test pager1-4.4.$tn.8 { 656e08341c6Sdan SELECT * FROM a 657e08341c6Sdan } {double-you why zed won too free} 658e08341c6Sdan do_execsql_test pager1-4.4.$tn.9 { 659e08341c6Sdan SELECT * FROM b 660e08341c6Sdan } {won too free double-you why zed} 661e08341c6Sdan } 662e08341c6Sdan 663e08341c6Sdan cd $pwd 664e08341c6Sdan} 665e08341c6Sdandb close 666e08341c6Sdantv delete 667*fda06befSmistachkinforcedelete $dirname 6680e986f51Sdan 6690e986f51Sdan 6700e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a 6710e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly 6720e986f51Sdan# two database pages (and page 1 - the change counter). 6730e986f51Sdan# 6740e986f51Sdantestvfs tv -default 1 6750e986f51Sdantv sectorsize 512 6760e986f51Sdantv script copy_on_journal_delete 6770e986f51Sdantv filter xDelete 6780e986f51Sdanproc copy_on_journal_delete {method filename args} { 6790e986f51Sdan if {[string match *journal $filename]} faultsim_save 6800e986f51Sdan return SQLITE_OK 6810e986f51Sdan} 6820e986f51Sdanfaultsim_delete_and_reopen 6830e986f51Sdando_execsql_test pager1.4.5.1 { 6843f94b609Sdan PRAGMA journal_mode = DELETE; 6850e986f51Sdan PRAGMA page_size = 1024; 6860e986f51Sdan CREATE TABLE t1(a, b); 6870e986f51Sdan CREATE TABLE t2(a, b); 6880e986f51Sdan INSERT INTO t1 VALUES('I', 'II'); 6890e986f51Sdan INSERT INTO t2 VALUES('III', 'IV'); 6900e986f51Sdan BEGIN; 6910e986f51Sdan INSERT INTO t1 VALUES(1, 2); 6920e986f51Sdan INSERT INTO t2 VALUES(3, 4); 6930e986f51Sdan COMMIT; 6943f94b609Sdan} {delete} 6950e986f51Sdantv filter {} 6960e986f51Sdan 6970e986f51Sdan# Check the transaction was committed: 6980e986f51Sdan# 6990e986f51Sdando_execsql_test pager1.4.5.2 { 7000e986f51Sdan SELECT * FROM t1; 7010e986f51Sdan SELECT * FROM t2; 7020e986f51Sdan} {I II 1 2 III IV 3 4} 7030e986f51Sdan 704ec6ffc1aSdan# Now try four tests: 7050e986f51Sdan# 7060e986f51Sdan# pager1-4.5.3: Restore the file-system. Check that the whole transaction 7070e986f51Sdan# is rolled back. 7080e986f51Sdan# 7090e986f51Sdan# pager1-4.5.4: Restore the file-system. Corrupt the first record in the 7100e986f51Sdan# journal. Check the transaction is not rolled back. 7110e986f51Sdan# 7120e986f51Sdan# pager1-4.5.5: Restore the file-system. Corrupt the second record in the 7130e986f51Sdan# journal. Check that the first record in the transaction is 7140e986f51Sdan# played back, but not the second. 7150e986f51Sdan# 71610f5a50eSdan# pager1-4.5.6: Restore the file-system. Try to open the database with a 71710f5a50eSdan# readonly connection. This should fail, as a read-only 71810f5a50eSdan# connection cannot roll back the database file. 71910f5a50eSdan# 7200e986f51Sdanfaultsim_restore_and_reopen 7210e986f51Sdando_execsql_test pager1.4.5.3 { 7220e986f51Sdan SELECT * FROM t1; 7230e986f51Sdan SELECT * FROM t2; 7240e986f51Sdan} {I II III IV} 7250e986f51Sdanfaultsim_restore_and_reopen 7260e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF 7270e986f51Sdando_execsql_test pager1.4.5.4 { 7280e986f51Sdan SELECT * FROM t1; 7290e986f51Sdan SELECT * FROM t2; 7300e986f51Sdan} {I II 1 2 III IV 3 4} 7310e986f51Sdanfaultsim_restore_and_reopen 7320e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF 7330e986f51Sdando_execsql_test pager1.4.5.5 { 7340e986f51Sdan SELECT * FROM t1; 7350e986f51Sdan SELECT * FROM t2; 7360e986f51Sdan} {I II III IV 3 4} 7370e986f51Sdan 73810f5a50eSdanfaultsim_restore_and_reopen 73910f5a50eSdandb close 74010f5a50eSdansqlite3 db test.db -readonly 1 74110f5a50eSdando_catchsql_test pager1.4.5.6 { 74210f5a50eSdan SELECT * FROM t1; 74310f5a50eSdan SELECT * FROM t2; 74410f5a50eSdan} {1 {disk I/O error}} 745ec6ffc1aSdandb close 746ec6ffc1aSdan 747ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name 748ec6ffc1aSdan# of the master journal file in $::mj_filename. 749ec6ffc1aSdan# 750ec6ffc1aSdantv script copy_on_mj_delete 751ec6ffc1aSdantv filter xDelete 752ec6ffc1aSdanproc copy_on_mj_delete {method filename args} { 753ec6ffc1aSdan if {[string match *mj* [file tail $filename]]} { 754ec6ffc1aSdan set ::mj_filename $filename 755ec6ffc1aSdan faultsim_save 756ec6ffc1aSdan } 757ec6ffc1aSdan return SQLITE_OK 758ec6ffc1aSdan} 759ec6ffc1aSdando_test pager1.4.6.1 { 760ec6ffc1aSdan faultsim_delete_and_reopen 761ec6ffc1aSdan execsql { 7623f94b609Sdan PRAGMA journal_mode = DELETE; 763ec6ffc1aSdan ATTACH 'test.db2' AS two; 764ec6ffc1aSdan CREATE TABLE t1(a, b); 765ec6ffc1aSdan CREATE TABLE two.t2(a, b); 766ec6ffc1aSdan INSERT INTO t1 VALUES(1, 't1.1'); 767ec6ffc1aSdan INSERT INTO t2 VALUES(1, 't2.1'); 768ec6ffc1aSdan BEGIN; 769ec6ffc1aSdan UPDATE t1 SET b = 't1.2'; 770ec6ffc1aSdan UPDATE t2 SET b = 't2.2'; 771ec6ffc1aSdan COMMIT; 772ec6ffc1aSdan } 773ec6ffc1aSdan tv filter {} 774ec6ffc1aSdan db close 775ec6ffc1aSdan} {} 776ec6ffc1aSdan 777ec6ffc1aSdanfaultsim_restore_and_reopen 778ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 } {1 t1.1} 779ec6ffc1aSdando_test pager1.4.6.3 { file exists $::mj_filename } {1} 780ec6ffc1aSdando_execsql_test pager1.4.6.4 { 781ec6ffc1aSdan ATTACH 'test.db2' AS two; 782ec6ffc1aSdan SELECT * FROM t2; 783ec6ffc1aSdan} {1 t2.1} 784ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0} 785ec6ffc1aSdan 786ec6ffc1aSdanfaultsim_restore_and_reopen 787ec6ffc1aSdandb close 788ec6ffc1aSdando_test pager1.4.6.8 { 789ec6ffc1aSdan set ::mj_filename1 $::mj_filename 790ec6ffc1aSdan tv filter xDelete 791ec6ffc1aSdan sqlite3 db test.db2 792ec6ffc1aSdan execsql { 7933f94b609Sdan PRAGMA journal_mode = DELETE; 794ec6ffc1aSdan ATTACH 'test.db3' AS three; 795ec6ffc1aSdan CREATE TABLE three.t3(a, b); 796ec6ffc1aSdan INSERT INTO t3 VALUES(1, 't3.1'); 797ec6ffc1aSdan BEGIN; 798ec6ffc1aSdan UPDATE t2 SET b = 't2.3'; 799ec6ffc1aSdan UPDATE t3 SET b = 't3.3'; 800ec6ffc1aSdan COMMIT; 801ec6ffc1aSdan } 802ec6ffc1aSdan expr {$::mj_filename1 != $::mj_filename} 803ec6ffc1aSdan} {1} 804ec6ffc1aSdanfaultsim_restore_and_reopen 805ec6ffc1aSdantv filter {} 806ec6ffc1aSdan 807ec6ffc1aSdan# The file-system now contains: 808ec6ffc1aSdan# 809ec6ffc1aSdan# * three databases 810ec6ffc1aSdan# * three hot-journal files 811ec6ffc1aSdan# * two master-journal files. 812ec6ffc1aSdan# 813ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to 814ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with 815ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from 816ec6ffc1aSdan# test.db should delete $::mj_filename1. 817ec6ffc1aSdan# 818ec6ffc1aSdando_test pager1.4.6.9 { 819ec6ffc1aSdan lsort [glob test.db*] 820ec6ffc1aSdan} [lsort [list \ 821ec6ffc1aSdan test.db test.db2 test.db3 \ 822ec6ffc1aSdan test.db-journal test.db2-journal test.db3-journal \ 823ec6ffc1aSdan [file tail $::mj_filename] [file tail $::mj_filename1] 824ec6ffc1aSdan]] 825ec6ffc1aSdan 826ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and 827ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to 828ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should 829ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1. 830ec6ffc1aSdan# 831ec6ffc1aSdando_test pager1.4.6.10 { file exists $::mj_filename } {1} 832ec6ffc1aSdando_test pager1.4.6.11 { file exists $::mj_filename1 } {1} 833ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1} 834ec6ffc1aSdando_test pager1.4.6.13 { file exists $::mj_filename } {1} 835ec6ffc1aSdando_test pager1.4.6.14 { file exists $::mj_filename1 } {0} 836ec6ffc1aSdan 837ec6ffc1aSdando_execsql_test pager1.4.6.12 { 838ec6ffc1aSdan ATTACH 'test.db2' AS two; 839ec6ffc1aSdan SELECT * FROM t2; 840ec6ffc1aSdan} {1 t2.1} 841ec6ffc1aSdando_test pager1.4.6.13 { file exists $::mj_filename } {1} 842ec6ffc1aSdando_execsql_test pager1.4.6.14 { 843ec6ffc1aSdan ATTACH 'test.db3' AS three; 844ec6ffc1aSdan SELECT * FROM t3; 845ec6ffc1aSdan} {1 t3.1} 846ec6ffc1aSdando_test pager1.4.6.15 { file exists $::mj_filename } {0} 84710f5a50eSdan 8480e986f51Sdandb close 8490e986f51Sdantv delete 850e08341c6Sdan 851c8ce3972Sdantestvfs tv -default 1 852c8ce3972Sdantv sectorsize 512 853c8ce3972Sdantv script copy_on_journal_delete 854c8ce3972Sdantv filter xDelete 855c8ce3972Sdanproc copy_on_journal_delete {method filename args} { 856c8ce3972Sdan if {[string match *journal $filename]} faultsim_save 857c8ce3972Sdan return SQLITE_OK 858c8ce3972Sdan} 859c8ce3972Sdanfaultsim_delete_and_reopen 860c8ce3972Sdando_execsql_test pager1.4.7.1 { 8613f94b609Sdan PRAGMA journal_mode = DELETE; 862c8ce3972Sdan CREATE TABLE t1(x PRIMARY KEY, y); 863c8ce3972Sdan CREATE INDEX i1 ON t1(y); 864c8ce3972Sdan INSERT INTO t1 VALUES('I', 'one'); 865c8ce3972Sdan INSERT INTO t1 VALUES('II', 'four'); 866c8ce3972Sdan INSERT INTO t1 VALUES('III', 'nine'); 867c8ce3972Sdan BEGIN; 868c8ce3972Sdan INSERT INTO t1 VALUES('IV', 'sixteen'); 869c8ce3972Sdan INSERT INTO t1 VALUES('V' , 'twentyfive'); 870c8ce3972Sdan COMMIT; 8713f94b609Sdan} {delete} 872c8ce3972Sdantv filter {} 873c8ce3972Sdandb close 874c8ce3972Sdantv delete 875c8ce3972Sdando_test pager1.4.7.2 { 876c8ce3972Sdan faultsim_restore_and_reopen 877c8ce3972Sdan catch {file attributes test.db-journal -permissions r--------} 878c8ce3972Sdan catch {file attributes test.db-journal -readonly 1} 879c8ce3972Sdan catchsql { SELECT * FROM t1 } 880c8ce3972Sdan} {1 {unable to open database file}} 881c8ce3972Sdando_test pager1.4.7.3 { 882c8ce3972Sdan db close 883c8ce3972Sdan catch {file attributes test.db-journal -permissions rw-rw-rw-} 884c8ce3972Sdan catch {file attributes test.db-journal -readonly 0} 885*fda06befSmistachkin delete_file test.db-journal 886c8ce3972Sdan file exists test.db-journal 887c8ce3972Sdan} {0} 888c8ce3972Sdan 889de4996e2Sdan#------------------------------------------------------------------------- 890146ed78bSdan# The following tests deal with multi-file commits. 891de4996e2Sdan# 892146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because 893146ed78bSdan# another connection is holding a SHARED lock on one of the 894146ed78bSdan# files. After the SHARED lock is removed, the COMMIT succeeds. 895146ed78bSdan# 896146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory. 897146ed78bSdan# 898146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory. 899146ed78bSdan# 900146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file 901146ed78bSdan# name is added to a journal file immediately after the last 902146ed78bSdan# journal record. But with synchronous=full, extra unused space 903146ed78bSdan# is allocated between the last journal record and the 904146ed78bSdan# master-journal file name so that the master-journal file 905146ed78bSdan# name does not lie on the same sector as the last journal file 906146ed78bSdan# record. 907146ed78bSdan# 908e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is 909e08341c6Sdan# truncated to zero bytes when a multi-file transaction is 910e08341c6Sdan# committed (instead of the first couple of bytes being zeroed). 911e08341c6Sdan# 912146ed78bSdan# 913146ed78bSdando_test pager1-5.1.1 { 914146ed78bSdan faultsim_delete_and_reopen 915146ed78bSdan execsql { 916146ed78bSdan ATTACH 'test.db2' AS aux; 917146ed78bSdan CREATE TABLE t1(a, b); 918146ed78bSdan CREATE TABLE aux.t2(a, b); 919146ed78bSdan INSERT INTO t1 VALUES(17, 'Lenin'); 920146ed78bSdan INSERT INTO t1 VALUES(22, 'Stalin'); 921146ed78bSdan INSERT INTO t1 VALUES(53, 'Khrushchev'); 922146ed78bSdan } 923146ed78bSdan} {} 924146ed78bSdando_test pager1-5.1.2 { 925146ed78bSdan execsql { 926146ed78bSdan BEGIN; 927146ed78bSdan INSERT INTO t1 VALUES(64, 'Brezhnev'); 928146ed78bSdan INSERT INTO t2 SELECT * FROM t1; 929146ed78bSdan } 930146ed78bSdan sqlite3 db2 test.db2 931146ed78bSdan execsql { 932146ed78bSdan BEGIN; 933146ed78bSdan SELECT * FROM t2; 934146ed78bSdan } db2 935146ed78bSdan} {} 936146ed78bSdando_test pager1-5.1.3 { 937146ed78bSdan catchsql COMMIT 938146ed78bSdan} {1 {database is locked}} 939146ed78bSdando_test pager1-5.1.4 { 940146ed78bSdan execsql COMMIT db2 941146ed78bSdan execsql COMMIT 942146ed78bSdan execsql { SELECT * FROM t2 } db2 943146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev} 944146ed78bSdando_test pager1-5.1.5 { 945146ed78bSdan db2 close 946146ed78bSdan} {} 947146ed78bSdan 948146ed78bSdando_test pager1-5.2.1 { 949146ed78bSdan execsql { 950146ed78bSdan PRAGMA journal_mode = memory; 951146ed78bSdan BEGIN; 952146ed78bSdan INSERT INTO t1 VALUES(84, 'Andropov'); 953146ed78bSdan INSERT INTO t2 VALUES(84, 'Andropov'); 954146ed78bSdan COMMIT; 955146ed78bSdan } 956146ed78bSdan} {memory} 957146ed78bSdando_test pager1-5.3.1 { 958146ed78bSdan execsql { 959146ed78bSdan PRAGMA journal_mode = off; 960146ed78bSdan BEGIN; 961146ed78bSdan INSERT INTO t1 VALUES(85, 'Gorbachev'); 962146ed78bSdan INSERT INTO t2 VALUES(85, 'Gorbachev'); 963146ed78bSdan COMMIT; 964146ed78bSdan } 965146ed78bSdan} {off} 966146ed78bSdan 967146ed78bSdando_test pager1-5.4.1 { 968146ed78bSdan db close 969146ed78bSdan testvfs tv 970146ed78bSdan sqlite3 db test.db -vfs tv 971146ed78bSdan execsql { ATTACH 'test.db2' AS aux } 972146ed78bSdan 973146ed78bSdan tv filter xDelete 974146ed78bSdan tv script max_journal_size 975146ed78bSdan tv sectorsize 512 976146ed78bSdan set ::max_journal 0 977146ed78bSdan proc max_journal_size {method args} { 978146ed78bSdan set sz 0 979146ed78bSdan catch { set sz [file size test.db-journal] } 980146ed78bSdan if {$sz > $::max_journal} { 981146ed78bSdan set ::max_journal $sz 982146ed78bSdan } 983146ed78bSdan return SQLITE_OK 984146ed78bSdan } 985146ed78bSdan execsql { 986146ed78bSdan PRAGMA journal_mode = DELETE; 987146ed78bSdan PRAGMA synchronous = NORMAL; 988146ed78bSdan BEGIN; 989146ed78bSdan INSERT INTO t1 VALUES(85, 'Gorbachev'); 990146ed78bSdan INSERT INTO t2 VALUES(85, 'Gorbachev'); 991146ed78bSdan COMMIT; 992146ed78bSdan } 993146ed78bSdan set ::max_journal 994146ed78bSdan} [expr 2615+[string length [pwd]]] 995146ed78bSdando_test pager1-5.4.2 { 996146ed78bSdan set ::max_journal 0 997146ed78bSdan execsql { 998146ed78bSdan PRAGMA synchronous = full; 999146ed78bSdan BEGIN; 1000146ed78bSdan DELETE FROM t1 WHERE b = 'Lenin'; 1001146ed78bSdan DELETE FROM t2 WHERE b = 'Lenin'; 1002146ed78bSdan COMMIT; 1003146ed78bSdan } 1004146ed78bSdan set ::max_journal 1005146ed78bSdan} [expr 3111+[string length [pwd]]] 1006146ed78bSdandb close 1007146ed78bSdantv delete 1008146ed78bSdan 1009146ed78bSdando_test pager1-5.5.1 { 1010146ed78bSdan sqlite3 db test.db 1011146ed78bSdan execsql { 1012146ed78bSdan ATTACH 'test.db2' AS aux; 1013146ed78bSdan PRAGMA journal_mode = PERSIST; 1014146ed78bSdan CREATE TABLE t3(a, b); 1015146ed78bSdan INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1; 1016146ed78bSdan UPDATE t3 SET b = randomblob(1500); 1017146ed78bSdan } 1018146ed78bSdan expr [file size test.db-journal] > 15000 1019146ed78bSdan} {1} 1020146ed78bSdando_test pager1-5.5.2 { 1021146ed78bSdan execsql { 1022146ed78bSdan PRAGMA synchronous = full; 1023146ed78bSdan BEGIN; 1024146ed78bSdan DELETE FROM t1 WHERE b = 'Stalin'; 1025146ed78bSdan DELETE FROM t2 WHERE b = 'Stalin'; 1026146ed78bSdan COMMIT; 1027146ed78bSdan } 1028146ed78bSdan file size test.db-journal 1029146ed78bSdan} {0} 1030146ed78bSdan 1031146ed78bSdan 1032146ed78bSdan#------------------------------------------------------------------------- 1033146ed78bSdan# The following tests work with "PRAGMA max_page_count" 1034146ed78bSdan# 1035146ed78bSdando_test pager1-6.1 { 1036146ed78bSdan faultsim_delete_and_reopen 1037146ed78bSdan execsql { 1038f43d7fceSdan PRAGMA auto_vacuum = none; 1039146ed78bSdan PRAGMA max_page_count = 10; 1040146ed78bSdan CREATE TABLE t2(a, b); 1041146ed78bSdan CREATE TABLE t3(a, b); 1042146ed78bSdan CREATE TABLE t4(a, b); 1043146ed78bSdan CREATE TABLE t5(a, b); 1044146ed78bSdan CREATE TABLE t6(a, b); 1045146ed78bSdan CREATE TABLE t7(a, b); 1046146ed78bSdan CREATE TABLE t8(a, b); 1047146ed78bSdan CREATE TABLE t9(a, b); 1048146ed78bSdan CREATE TABLE t10(a, b); 1049146ed78bSdan } 1050146ed78bSdan} {10} 1051d353331aSdando_catchsql_test pager1-6.2 { 1052d353331aSdan CREATE TABLE t11(a, b) 1053146ed78bSdan} {1 {database or disk is full}} 1054d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count } {10} 1055d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15} 1056d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b) } {} 1057d353331aSdando_execsql_test pager1-6.7 { 1058d353331aSdan BEGIN; 1059d353331aSdan INSERT INTO t11 VALUES(1, 2); 1060d353331aSdan PRAGMA max_page_count = 13; 1061d353331aSdan} {13} 1062d353331aSdando_execsql_test pager1-6.8 { 1063d353331aSdan INSERT INTO t11 VALUES(3, 4); 1064d353331aSdan PRAGMA max_page_count = 10; 1065d353331aSdan} {11} 1066d353331aSdando_execsql_test pager1-6.9 { COMMIT } {} 1067de4996e2Sdan 106860ac3f42Sdrhdo_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11} 106922b328b2Sdando_execsql_test pager1-6.11 { SELECT * FROM t11 } {1 2 3 4} 107022b328b2Sdando_execsql_test pager1-6.12 { PRAGMA max_page_count } {11} 107122b328b2Sdan 1072153eda0aSdan 1073153eda0aSdan#------------------------------------------------------------------------- 1074153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and 1075153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE". 1076153eda0aSdan# 1077153eda0aSdan# Each test is specified with 5 variables. As follows: 1078153eda0aSdan# 1079153eda0aSdan# $tn: Test Number. Used as part of the [do_test] test names. 1080153eda0aSdan# $sql: SQL to execute. 1081153eda0aSdan# $res: Expected result of executing $sql. 1082153eda0aSdan# $js: The expected size of the journal file, in bytes, after executing 1083153eda0aSdan# the SQL script. Or -1 if the journal is not expected to exist. 1084153eda0aSdan# $ws: The expected size of the WAL file, in bytes, after executing 1085153eda0aSdan# the SQL script. Or -1 if the WAL is not expected to exist. 1086153eda0aSdan# 108738e1a279Sdanifcapable wal { 1088153eda0aSdan faultsim_delete_and_reopen 1089153eda0aSdan foreach {tn sql res js ws} [subst { 1090153eda0aSdan 1091153eda0aSdan 1 { 1092153eda0aSdan CREATE TABLE t1(a, b); 1093153eda0aSdan PRAGMA auto_vacuum=OFF; 1094153eda0aSdan PRAGMA synchronous=NORMAL; 1095153eda0aSdan PRAGMA page_size=1024; 1096153eda0aSdan PRAGMA locking_mode=EXCLUSIVE; 1097153eda0aSdan PRAGMA journal_mode=TRUNCATE; 1098153eda0aSdan INSERT INTO t1 VALUES(1, 2); 1099153eda0aSdan } {exclusive truncate} 0 -1 1100153eda0aSdan 1101153eda0aSdan 2 { 1102153eda0aSdan BEGIN IMMEDIATE; 1103153eda0aSdan SELECT * FROM t1; 1104153eda0aSdan COMMIT; 1105153eda0aSdan } {1 2} 0 -1 1106153eda0aSdan 1107153eda0aSdan 3 { 1108153eda0aSdan BEGIN; 1109153eda0aSdan SELECT * FROM t1; 1110153eda0aSdan COMMIT; 1111153eda0aSdan } {1 2} 0 -1 1112153eda0aSdan 1113153eda0aSdan 4 { PRAGMA journal_mode = WAL } wal -1 -1 1114153eda0aSdan 5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024] 11158c408004Sdan 6 { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024] 1116153eda0aSdan 7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024] 1117153eda0aSdan 1118153eda0aSdan 8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1 1119153eda0aSdan 9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1 1120153eda0aSdan 10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1 1121153eda0aSdan 1122153eda0aSdan }] { 1123153eda0aSdan do_execsql_test pager1-7.1.$tn.1 $sql $res 1124153eda0aSdan catch { set J -1 ; set J [file size test.db-journal] } 1125153eda0aSdan catch { set W -1 ; set W [file size test.db-wal] } 1126153eda0aSdan do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws] 1127153eda0aSdan } 112838e1a279Sdan} 1129153eda0aSdan 113089ccf448Sdando_test pager1-7.2.1 { 113189ccf448Sdan faultsim_delete_and_reopen 113289ccf448Sdan execsql { 113389ccf448Sdan PRAGMA locking_mode = EXCLUSIVE; 113489ccf448Sdan CREATE TABLE t1(a, b); 113589ccf448Sdan BEGIN; 113689ccf448Sdan PRAGMA journal_mode = delete; 113789ccf448Sdan PRAGMA journal_mode = truncate; 113889ccf448Sdan } 113989ccf448Sdan} {exclusive delete truncate} 114089ccf448Sdando_test pager1-7.2.2 { 114189ccf448Sdan execsql { INSERT INTO t1 VALUES(1, 2) } 114289ccf448Sdan execsql { PRAGMA journal_mode = persist } 114389ccf448Sdan} {truncate} 114489ccf448Sdando_test pager1-7.2.3 { 114589ccf448Sdan execsql { COMMIT } 114689ccf448Sdan execsql { 114789ccf448Sdan PRAGMA journal_mode = persist; 114889ccf448Sdan PRAGMA journal_size_limit; 114989ccf448Sdan } 115089ccf448Sdan} {persist -1} 115189ccf448Sdan 1152d353331aSdan#------------------------------------------------------------------------- 1153d353331aSdan# The following tests, pager1-8.*, test that the special filenames 1154d353331aSdan# ":memory:" and "" open temporary databases. 1155d353331aSdan# 11560e986f51Sdanforeach {tn filename} { 11570e986f51Sdan 1 :memory: 11580e986f51Sdan 2 "" 11590e986f51Sdan} { 11600e986f51Sdan do_test pager1-8.$tn.1 { 1161153eda0aSdan faultsim_delete_and_reopen 1162153eda0aSdan db close 11630e986f51Sdan sqlite3 db $filename 1164153eda0aSdan execsql { 1165c8ce3972Sdan PRAGMA auto_vacuum = 1; 1166153eda0aSdan CREATE TABLE x1(x); 1167153eda0aSdan INSERT INTO x1 VALUES('Charles'); 1168153eda0aSdan INSERT INTO x1 VALUES('James'); 1169153eda0aSdan INSERT INTO x1 VALUES('Mary'); 1170153eda0aSdan SELECT * FROM x1; 1171153eda0aSdan } 1172153eda0aSdan } {Charles James Mary} 11730e986f51Sdan 11740e986f51Sdan do_test pager1-8.$tn.2 { 11750e986f51Sdan sqlite3 db2 $filename 11760e986f51Sdan catchsql { SELECT * FROM x1 } db2 1177153eda0aSdan } {1 {no such table: x1}} 1178153eda0aSdan 11790e986f51Sdan do_execsql_test pager1-8.$tn.3 { 11800e986f51Sdan BEGIN; 11810e986f51Sdan INSERT INTO x1 VALUES('William'); 11820e986f51Sdan INSERT INTO x1 VALUES('Anne'); 11830e986f51Sdan ROLLBACK; 11840e986f51Sdan } {} 11850e986f51Sdan} 11860e986f51Sdan 1187dca321aeSdan#------------------------------------------------------------------------- 1188dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between 1189dca321aeSdan# the pager and the backup API. Test cases: 1190dca321aeSdan# 1191dca321aeSdan# pager1-9.1.*: Test that a backup completes successfully even if the 1192dca321aeSdan# source db is written to during the backup op. 1193dca321aeSdan# 1194dca321aeSdan# pager1-9.2.*: Test that a backup completes successfully even if the 1195dca321aeSdan# source db is written to and then rolled back during a 1196dca321aeSdan# backup operation. 1197dca321aeSdan# 1198dca321aeSdando_test pager1-9.0.1 { 1199dca321aeSdan faultsim_delete_and_reopen 1200dca321aeSdan db func a_string a_string 1201dca321aeSdan execsql { 1202dca321aeSdan PRAGMA cache_size = 10; 1203dca321aeSdan BEGIN; 1204dca321aeSdan CREATE TABLE ab(a, b, UNIQUE(a, b)); 1205dca321aeSdan INSERT INTO ab VALUES( a_string(200), a_string(300) ); 1206dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1207dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1208dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1209dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1210dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1211dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1212dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1213dca321aeSdan COMMIT; 1214dca321aeSdan } 1215dca321aeSdan} {} 1216dca321aeSdando_test pager1-9.0.2 { 1217dca321aeSdan sqlite3 db2 test.db2 1218dca321aeSdan db2 eval { PRAGMA cache_size = 10 } 1219dca321aeSdan sqlite3_backup B db2 main db main 1220dca321aeSdan list [B step 10000] [B finish] 1221dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1222dca321aeSdando_test pager1-9.0.3 { 1223dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1224dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1225dca321aeSdan 1226dca321aeSdando_test pager1-9.1.1 { 1227dca321aeSdan execsql { UPDATE ab SET a = a_string(201) } 1228dca321aeSdan sqlite3_backup B db2 main db main 1229dca321aeSdan B step 30 1230dca321aeSdan} {SQLITE_OK} 1231dca321aeSdando_test pager1-9.1.2 { 1232dca321aeSdan execsql { UPDATE ab SET b = a_string(301) } 1233dca321aeSdan list [B step 10000] [B finish] 1234dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1235dca321aeSdando_test pager1-9.1.3 { 1236dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1237dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1238dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128} 1239dca321aeSdan 1240dca321aeSdando_test pager1-9.2.1 { 1241dca321aeSdan execsql { UPDATE ab SET a = a_string(202) } 1242dca321aeSdan sqlite3_backup B db2 main db main 1243dca321aeSdan B step 30 1244dca321aeSdan} {SQLITE_OK} 1245dca321aeSdando_test pager1-9.2.2 { 1246dca321aeSdan execsql { 1247dca321aeSdan BEGIN; 1248dca321aeSdan UPDATE ab SET b = a_string(301); 1249dca321aeSdan ROLLBACK; 1250dca321aeSdan } 1251dca321aeSdan list [B step 10000] [B finish] 1252dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1253dca321aeSdando_test pager1-9.2.3 { 1254dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1255dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1256dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128} 1257ec6ffc1aSdandb close 1258ec6ffc1aSdandb2 close 1259ec6ffc1aSdan 1260c396d4afSdando_test pager1-9.3.1 { 1261c396d4afSdan testvfs tv -default 1 1262c396d4afSdan tv sectorsize 4096 1263c396d4afSdan faultsim_delete_and_reopen 1264c396d4afSdan 1265c396d4afSdan execsql { PRAGMA page_size = 1024 } 1266c396d4afSdan for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" } 1267c396d4afSdan} {} 1268c396d4afSdando_test pager1-9.3.2 { 1269c396d4afSdan sqlite3 db2 test.db2 1270f412ee2eSdan 1271c396d4afSdan execsql { 1272c396d4afSdan PRAGMA page_size = 4096; 1273c396d4afSdan PRAGMA synchronous = OFF; 1274c396d4afSdan CREATE TABLE t1(a, b); 1275c396d4afSdan CREATE TABLE t2(a, b); 1276c396d4afSdan } db2 1277c396d4afSdan 1278c396d4afSdan sqlite3_backup B db2 main db main 1279c396d4afSdan B step 30 1280c396d4afSdan list [B step 10000] [B finish] 1281c396d4afSdan} {SQLITE_DONE SQLITE_OK} 1282c396d4afSdando_test pager1-9.3.3 { 1283c396d4afSdan db2 close 1284c396d4afSdan db close 1285c396d4afSdan tv delete 1286c396d4afSdan file size test.db2 1287c396d4afSdan} [file size test.db] 1288c396d4afSdan 1289f412ee2eSdando_test pager1-9.4.1 { 1290f412ee2eSdan faultsim_delete_and_reopen 1291f412ee2eSdan sqlite3 db2 test.db2 1292f412ee2eSdan execsql { 1293f412ee2eSdan PRAGMA page_size = 4096; 1294f412ee2eSdan CREATE TABLE t1(a, b); 1295f412ee2eSdan CREATE TABLE t2(a, b); 1296f412ee2eSdan } db2 1297f412ee2eSdan sqlite3_backup B db2 main db main 1298f412ee2eSdan list [B step 10000] [B finish] 1299f412ee2eSdan} {SQLITE_DONE SQLITE_OK} 1300f412ee2eSdando_test pager1-9.4.2 { 1301f412ee2eSdan list [file size test.db2] [file size test.db] 1302f412ee2eSdan} {0 0} 130333d85c9cSshanehdb2 close 1304d0b0d4dcSdan 1305ec6ffc1aSdan#------------------------------------------------------------------------- 1306ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the 1307ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes. 1308ec6ffc1aSdan# 1309ec6ffc1aSdantestvfs tv -default 1 1310ec6ffc1aSdanforeach sectorsize { 1311ec6ffc1aSdan 32 64 128 256 512 1024 2048 1312ec6ffc1aSdan 4096 8192 16384 32768 65536 131072 262144 1313ec6ffc1aSdan} { 1314ec6ffc1aSdan tv sectorsize $sectorsize 1315ec6ffc1aSdan set eff $sectorsize 1316ec6ffc1aSdan if {$sectorsize < 512} { set eff 512 } 1317ec6ffc1aSdan if {$sectorsize > 65536} { set eff 65536 } 1318ec6ffc1aSdan 1319d0b0d4dcSdan do_test pager1-10.$sectorsize.1 { 1320ec6ffc1aSdan faultsim_delete_and_reopen 1321d0b0d4dcSdan db func a_string a_string 1322ec6ffc1aSdan execsql { 1323ec6ffc1aSdan PRAGMA journal_mode = PERSIST; 1324ec6ffc1aSdan PRAGMA page_size = 1024; 1325d0b0d4dcSdan BEGIN; 1326ec6ffc1aSdan CREATE TABLE t1(a, b); 1327d0b0d4dcSdan CREATE TABLE t2(a, b); 1328d0b0d4dcSdan CREATE TABLE t3(a, b); 1329d0b0d4dcSdan COMMIT; 1330ec6ffc1aSdan } 1331ec6ffc1aSdan file size test.db-journal 1332ec6ffc1aSdan } [expr $sectorsize > 65536 ? 65536 : $sectorsize] 1333d0b0d4dcSdan 1334d0b0d4dcSdan do_test pager1-10.$sectorsize.2 { 1335d0b0d4dcSdan execsql { 1336d0b0d4dcSdan INSERT INTO t3 VALUES(a_string(300), a_string(300)); 1337d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 2 */ 1338d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 4 */ 1339d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 8 */ 1340d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 16 */ 1341d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 32 */ 1342ec6ffc1aSdan } 1343d0b0d4dcSdan } {} 1344d0b0d4dcSdan 1345d0b0d4dcSdan do_test pager1-10.$sectorsize.3 { 1346d0b0d4dcSdan db close 1347d0b0d4dcSdan sqlite3 db test.db 1348d0b0d4dcSdan execsql { 1349d0b0d4dcSdan PRAGMA cache_size = 10; 1350d0b0d4dcSdan BEGIN; 1351d0b0d4dcSdan } 1352d0b0d4dcSdan recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"} 1353d0b0d4dcSdan execsql { 1354d0b0d4dcSdan COMMIT; 1355d0b0d4dcSdan SELECT * FROM t2; 1356d0b0d4dcSdan } 1357d0b0d4dcSdan } {1 2} 1358d0b0d4dcSdan 1359d0b0d4dcSdan do_test pager1-10.$sectorsize.4 { 1360d0b0d4dcSdan execsql { 1361d0b0d4dcSdan CREATE TABLE t6(a, b); 1362d0b0d4dcSdan CREATE TABLE t7(a, b); 1363d0b0d4dcSdan CREATE TABLE t5(a, b); 1364d0b0d4dcSdan DROP TABLE t6; 1365d0b0d4dcSdan DROP TABLE t7; 1366d0b0d4dcSdan } 1367d0b0d4dcSdan execsql { 1368d0b0d4dcSdan BEGIN; 1369d0b0d4dcSdan CREATE TABLE t6(a, b); 1370d0b0d4dcSdan } 1371d0b0d4dcSdan recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"} 1372d0b0d4dcSdan execsql { 1373d0b0d4dcSdan COMMIT; 1374d0b0d4dcSdan SELECT * FROM t5; 1375d0b0d4dcSdan } 1376d0b0d4dcSdan } {1 2} 1377d0b0d4dcSdan 1378d0b0d4dcSdan} 1379d0b0d4dcSdandb close 1380d0b0d4dcSdan 1381d0b0d4dcSdantv sectorsize 4096 1382d0b0d4dcSdando_test pager1.10.x.1 { 1383d0b0d4dcSdan faultsim_delete_and_reopen 1384d0b0d4dcSdan execsql { 1385f43d7fceSdan PRAGMA auto_vacuum = none; 1386d0b0d4dcSdan PRAGMA page_size = 1024; 1387d0b0d4dcSdan CREATE TABLE t1(x); 1388d0b0d4dcSdan } 1389d0b0d4dcSdan for {set i 0} {$i<30} {incr i} { 1390d0b0d4dcSdan execsql { INSERT INTO t1 VALUES(zeroblob(900)) } 1391d0b0d4dcSdan } 1392d0b0d4dcSdan file size test.db 1393d0b0d4dcSdan} {32768} 1394d0b0d4dcSdando_test pager1.10.x.2 { 1395d0b0d4dcSdan execsql { 1396d0b0d4dcSdan CREATE TABLE t2(x); 1397d0b0d4dcSdan DROP TABLE t2; 1398d0b0d4dcSdan } 1399d0b0d4dcSdan file size test.db 1400d0b0d4dcSdan} {33792} 1401d0b0d4dcSdando_test pager1.10.x.3 { 1402d0b0d4dcSdan execsql { 1403d0b0d4dcSdan BEGIN; 1404d0b0d4dcSdan CREATE TABLE t2(x); 1405d0b0d4dcSdan } 1406d0b0d4dcSdan recursive_select 30 t1 1407d0b0d4dcSdan execsql { 1408d0b0d4dcSdan CREATE TABLE t3(x); 1409d0b0d4dcSdan COMMIT; 1410d0b0d4dcSdan } 1411d0b0d4dcSdan} {} 1412d0b0d4dcSdan 1413ec6ffc1aSdandb close 1414ec6ffc1aSdantv delete 1415ec6ffc1aSdan 1416ec6ffc1aSdantestvfs tv -default 1 1417ec6ffc1aSdanfaultsim_delete_and_reopen 1418ec6ffc1aSdandb func a_string a_string 1419ec6ffc1aSdando_execsql_test pager1-11.1 { 14203f94b609Sdan PRAGMA journal_mode = DELETE; 1421ec6ffc1aSdan PRAGMA cache_size = 10; 1422ec6ffc1aSdan BEGIN; 1423ec6ffc1aSdan CREATE TABLE zz(top PRIMARY KEY); 1424ec6ffc1aSdan INSERT INTO zz VALUES(a_string(222)); 1425ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1426ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1427ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1428ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1429ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1430ec6ffc1aSdan COMMIT; 1431ec6ffc1aSdan BEGIN; 1432ec6ffc1aSdan UPDATE zz SET top = a_string(345); 14333f94b609Sdan} {delete} 1434ec6ffc1aSdan 1435ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR } 1436ec6ffc1aSdantv script lockout 1437ec6ffc1aSdantv filter {xWrite xTruncate xSync} 1438ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}} 1439ec6ffc1aSdan 1440ec6ffc1aSdantv script {} 1441ec6ffc1aSdando_test pager1-11.3 { 1442ec6ffc1aSdan sqlite3 db2 test.db 1443ec6ffc1aSdan execsql { 1444ec6ffc1aSdan PRAGMA journal_mode = TRUNCATE; 1445ec6ffc1aSdan PRAGMA integrity_check; 1446ec6ffc1aSdan } db2 1447ec6ffc1aSdan} {truncate ok} 1448ec6ffc1aSdando_test pager1-11.4 { 1449ec6ffc1aSdan db2 close 1450f6c61471Sdan file exists test.db-journal 1451ec6ffc1aSdan} {0} 1452ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} 1453f9b4419dSdandb close 1454f9b4419dSdantv delete 1455ec6ffc1aSdan 1456f9b4419dSdan#------------------------------------------------------------------------- 1457f9b4419dSdan# Test "PRAGMA page_size" 1458f9b4419dSdan# 1459f43d7fceSdantestvfs tv -default 1 1460f43d7fceSdantv sectorsize 1024 1461f9b4419dSdanforeach pagesize { 1462f9b4419dSdan 512 1024 2048 4096 8192 16384 32768 1463f9b4419dSdan} { 1464f9b4419dSdan faultsim_delete_and_reopen 1465f9b4419dSdan 1466f43d7fceSdan # The sector-size (according to the VFS) is 1024 bytes. So if the 1467f43d7fceSdan # page-size requested using "PRAGMA page_size" is greater than the 1468f43d7fceSdan # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective 1469f43d7fceSdan # page-size remains 1024 bytes. 1470f43d7fceSdan # 1471f43d7fceSdan set eff $pagesize 1472f43d7fceSdan if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 } 1473f43d7fceSdan 1474f9b4419dSdan do_test pager1-12.$pagesize.1 { 1475f9b4419dSdan sqlite3 db2 test.db 1476f9b4419dSdan execsql " 1477f9b4419dSdan PRAGMA page_size = $pagesize; 1478f9b4419dSdan CREATE VIEW v AS SELECT * FROM sqlite_master; 1479f9b4419dSdan " db2 1480f9b4419dSdan file size test.db 1481f43d7fceSdan } $eff 1482f9b4419dSdan do_test pager1-12.$pagesize.2 { 1483f9b4419dSdan sqlite3 db2 test.db 1484f9b4419dSdan execsql { 1485f9b4419dSdan SELECT count(*) FROM v; 1486f9b4419dSdan PRAGMA main.page_size; 1487f9b4419dSdan } db2 1488f43d7fceSdan } [list 1 $eff] 1489f9b4419dSdan do_test pager1-12.$pagesize.3 { 1490f9b4419dSdan execsql { 1491f9b4419dSdan SELECT count(*) FROM v; 1492f9b4419dSdan PRAGMA main.page_size; 1493f9b4419dSdan } 1494f43d7fceSdan } [list 1 $eff] 1495f9b4419dSdan db2 close 1496f9b4419dSdan} 1497f43d7fceSdandb close 1498f43d7fceSdantv delete 1499dca321aeSdan 1500d353331aSdan#------------------------------------------------------------------------- 1501d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases. 1502d353331aSdan# 1503d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent 1504d353331aSdan# journal mode: If the journal associated with a transaction 1505d353331aSdan# is smaller than the journal file (because a previous 1506d353331aSdan# transaction left a very large non-hot journal file in the 1507d353331aSdan# file-system), then SQLite has to be careful that there is 1508d353331aSdan# not a journal-header left over from a previous transaction 1509d353331aSdan# immediately following the journal content just written. 1510d353331aSdan# If there is, and the process crashes so that the journal 1511d353331aSdan# becomes a hot-journal and must be rolled back by another 1512d353331aSdan# process, there is a danger that the other process may roll 1513d353331aSdan# back the aborted transaction, then continue copying data 1514d353331aSdan# from an older transaction from the remainder of the journal. 1515d353331aSdan# See the syncJournal() function for details. 1516d353331aSdan# 1517d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into 1518d353331aSdan# the mix to make the integrity-check more likely to catch 1519d353331aSdan# errors. 1520d353331aSdan# 1521d353331aSdantestvfs tv -default 1 1522d353331aSdantv script xSyncCb 1523d353331aSdantv filter xSync 1524d353331aSdanproc xSyncCb {method filename args} { 1525d353331aSdan set t [file tail $filename] 1526d353331aSdan if {$t == "test.db"} faultsim_save 1527d353331aSdan return SQLITE_OK 1528d353331aSdan} 1529d353331aSdanfaultsim_delete_and_reopen 1530d353331aSdandb func a_string a_string 1531e91a54e1Sdan 1532d353331aSdan# The UPDATE statement at the end of this test case creates a really big 1533d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains 1534d353331aSdan# frequent journal headers. 1535d353331aSdan# 1536d353331aSdando_execsql_test pager1-13.1.1 { 1537d353331aSdan PRAGMA page_size = 1024; 1538d353331aSdan PRAGMA journal_mode = PERSIST; 1539d353331aSdan PRAGMA cache_size = 10; 1540d353331aSdan BEGIN; 1541d353331aSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); 1542d353331aSdan INSERT INTO t1 VALUES(NULL, a_string(400)); 1543d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 2 */ 1544d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 4 */ 1545d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 8 */ 1546d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 16 */ 1547d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 32 */ 1548d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 64 */ 1549d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 128 */ 1550d353331aSdan COMMIT; 1551d353331aSdan UPDATE t1 SET b = a_string(400); 1552d353331aSdan} {persist} 1553d353331aSdan 1554b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} { 1555d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one) 1556d353331aSdan# of these will write just enough content that one of the old headers created 1557d353331aSdan# by the transaction in the block above lies immediately after the content 1558d353331aSdan# journalled by the current transaction. 1559d353331aSdan# 1560d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1561d353331aSdan do_execsql_test pager1-13.1.2.$nUp.1 { 1562d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1563d353331aSdan } {} 1564d353331aSdan do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok} 1565d353331aSdan 1566d353331aSdan # Try to access the snapshot of the file-system. 1567d353331aSdan # 1568d353331aSdan sqlite3 db2 sv_test.db 1569d353331aSdan do_test pager1-13.1.2.$nUp.3 { 1570d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1571d353331aSdan } [expr {128*400 - ($nUp-1)}] 1572d353331aSdan do_test pager1-13.1.2.$nUp.4 { 1573d353331aSdan execsql { PRAGMA integrity_check } db2 1574d353331aSdan } {ok} 1575d353331aSdan db2 close 1576d353331aSdan} 1577b2f20bfcSshaneh} 1578d353331aSdan 1579b2f20bfcSshanehif {$::tcl_platform(platform)!="windows"} { 1580d353331aSdan# Same test as above. But this time with an index on the table. 1581d353331aSdan# 1582d353331aSdando_execsql_test pager1-13.2.1 { 1583d353331aSdan CREATE INDEX i1 ON t1(b); 1584d353331aSdan UPDATE t1 SET b = a_string(400); 1585d353331aSdan} {} 1586d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1587d353331aSdan do_execsql_test pager1-13.2.2.$nUp.1 { 1588d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1589d353331aSdan } {} 1590d353331aSdan do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok} 1591d353331aSdan sqlite3 db2 sv_test.db 1592d353331aSdan do_test pager1-13.2.2.$nUp.3 { 1593d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1594d353331aSdan } [expr {128*400 - ($nUp-1)}] 1595d353331aSdan do_test pager1-13.2.2.$nUp.4 { 1596d353331aSdan execsql { PRAGMA integrity_check } db2 1597d353331aSdan } {ok} 1598d353331aSdan db2 close 1599d353331aSdan} 1600b2f20bfcSshaneh} 1601d353331aSdan 1602d353331aSdandb close 1603d353331aSdantv delete 1604d353331aSdan 1605d353331aSdan#------------------------------------------------------------------------- 1606d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases. 1607d353331aSdan# 1608d353331aSdanfaultsim_delete_and_reopen 1609d353331aSdando_execsql_test pager1-14.1.1 { 1610d353331aSdan PRAGMA journal_mode = OFF; 1611d353331aSdan CREATE TABLE t1(a, b); 1612d353331aSdan BEGIN; 1613d353331aSdan INSERT INTO t1 VALUES(1, 2); 1614d353331aSdan COMMIT; 1615d353331aSdan SELECT * FROM t1; 1616d353331aSdan} {off 1 2} 1617d353331aSdando_catchsql_test pager1-14.1.2 { 1618d353331aSdan BEGIN; 1619d353331aSdan INSERT INTO t1 VALUES(3, 4); 1620d353331aSdan ROLLBACK; 1621d353331aSdan} {0 {}} 1622d353331aSdando_execsql_test pager1-14.1.3 { 1623d353331aSdan SELECT * FROM t1; 1624354bfe03Sdan} {1 2} 1625d353331aSdando_catchsql_test pager1-14.1.4 { 1626d353331aSdan BEGIN; 1627d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1628d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1629d353331aSdan} {1 {PRIMARY KEY must be unique}} 1630d353331aSdando_execsql_test pager1-14.1.5 { 1631d353331aSdan COMMIT; 1632d353331aSdan SELECT * FROM t1; 1633354bfe03Sdan} {1 2 2 2} 1634d353331aSdan 1635c8ce3972Sdan#------------------------------------------------------------------------- 1636c8ce3972Sdan# Test opening and closing the pager sub-system with different values 1637c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable. 1638c8ce3972Sdan# 1639c8ce3972Sdanfaultsim_delete_and_reopen 1640c8ce3972Sdando_execsql_test pager1-15.0 { 1641c8ce3972Sdan CREATE TABLE tx(y, z); 1642c8ce3972Sdan INSERT INTO tx VALUES('Ayutthaya', 'Beijing'); 1643c8ce3972Sdan INSERT INTO tx VALUES('London', 'Tokyo'); 1644c8ce3972Sdan} {} 1645c8ce3972Sdandb close 1646c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} { 1647c8ce3972Sdan testvfs tv -default 1 -szosfile $i 1648c8ce3972Sdan sqlite3 db test.db 1649c8ce3972Sdan do_execsql_test pager1-15.$i.1 { 1650c8ce3972Sdan SELECT * FROM tx; 1651c8ce3972Sdan } {Ayutthaya Beijing London Tokyo} 1652c8ce3972Sdan db close 1653c8ce3972Sdan tv delete 1654c8ce3972Sdan} 1655c8ce3972Sdan 1656c8ce3972Sdan#------------------------------------------------------------------------- 1657c8ce3972Sdan# Check that it is not possible to open a database file if the full path 1658c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname. 1659c8ce3972Sdan# 1660c8ce3972Sdantestvfs tv -default 1 1661c8ce3972Sdantv script xOpenCb 1662c8ce3972Sdantv filter xOpen 166333f5379cSdanproc xOpenCb {method filename args} { 1664c8ce3972Sdan set ::file_len [string length $filename] 1665c8ce3972Sdan} 1666c8ce3972Sdansqlite3 db test.db 1667c8ce3972Sdandb close 1668c8ce3972Sdantv delete 1669c8ce3972Sdan 1670c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} { 1671c8ce3972Sdan testvfs tv -default 1 -mxpathname $ii 1672c8ce3972Sdan 1673c8ce3972Sdan # The length of the full path to file "test.db-journal" is ($::file_len+8). 1674c8ce3972Sdan # If the configured sqlite3_vfs.mxPathname value greater than or equal to 1675c8ce3972Sdan # this, then the file can be opened. Otherwise, it cannot. 1676c8ce3972Sdan # 1677c8ce3972Sdan if {$ii >= [expr $::file_len+8]} { 1678c8ce3972Sdan set res {0 {}} 1679c8ce3972Sdan } else { 1680c8ce3972Sdan set res {1 {unable to open database file}} 1681c8ce3972Sdan } 1682c8ce3972Sdan 1683c8ce3972Sdan do_test pager1-16.1.$ii { 1684c8ce3972Sdan list [catch { sqlite3 db test.db } msg] $msg 1685c8ce3972Sdan } $res 1686c8ce3972Sdan 1687c8ce3972Sdan catch {db close} 1688c8ce3972Sdan tv delete 1689c8ce3972Sdan} 1690c8ce3972Sdan 1691c8ce3972Sdan#------------------------------------------------------------------------- 1692c8ce3972Sdan# Test "PRAGMA omit_readlock". 1693c8ce3972Sdan# 1694c8ce3972Sdan# pager1-17.$tn.1.*: Test that if a second connection has an open 1695c8ce3972Sdan# read-transaction, it is not usually possible to write 1696c8ce3972Sdan# the database. 1697c8ce3972Sdan# 1698c8ce3972Sdan# pager1-17.$tn.2.*: Test that if the second connection was opened with 1699c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, and 1700c8ce3972Sdan# "PRAGMA omit_readlock = 1" is executed before attaching 1701c8ce3972Sdan# the database and opening a read-transaction on it, it is 1702c8ce3972Sdan# possible to write the db. 1703c8ce3972Sdan# 1704c8ce3972Sdan# pager1-17.$tn.3.*: Test that if the second connection was *not* opened with 1705c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, executing 1706c8ce3972Sdan# "PRAGMA omit_readlock = 1" has no effect. 1707c8ce3972Sdan# 1708c8ce3972Sdando_multiclient_test tn { 1709c8ce3972Sdan do_test pager1-17.$tn.1.1 { 1710c8ce3972Sdan sql1 { 1711c8ce3972Sdan CREATE TABLE t1(a, b); 1712c8ce3972Sdan INSERT INTO t1 VALUES(1, 2); 1713c8ce3972Sdan } 1714c8ce3972Sdan sql2 { 1715c8ce3972Sdan BEGIN; 1716c8ce3972Sdan SELECT * FROM t1; 1717c8ce3972Sdan } 1718c8ce3972Sdan } {1 2} 1719c8ce3972Sdan do_test pager1-17.$tn.1.2 { 1720c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1721c8ce3972Sdan } {1 {database is locked}} 1722c8ce3972Sdan do_test pager1-17.$tn.1.3 { 1723c8ce3972Sdan sql2 { COMMIT } 1724c8ce3972Sdan sql1 { INSERT INTO t1 VALUES(3, 4) } 1725c8ce3972Sdan } {} 1726c8ce3972Sdan 1727c8ce3972Sdan do_test pager1-17.$tn.2.1 { 1728c8ce3972Sdan code2 { 1729c8ce3972Sdan db2 close 1730c8ce3972Sdan sqlite3 db2 :memory: -readonly 1 1731c8ce3972Sdan } 1732c8ce3972Sdan sql2 { 1733c8ce3972Sdan PRAGMA omit_readlock = 1; 1734c8ce3972Sdan ATTACH 'test.db' AS two; 1735c8ce3972Sdan BEGIN; 1736c8ce3972Sdan SELECT * FROM t1; 1737c8ce3972Sdan } 1738c8ce3972Sdan } {1 2 3 4} 1739c8ce3972Sdan do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {} 1740c8ce3972Sdan do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" } {1 2 3 4} 1741c8ce3972Sdan do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" } {1 2 3 4 5 6} 1742c8ce3972Sdan 1743c8ce3972Sdan do_test pager1-17.$tn.3.1 { 1744c8ce3972Sdan code2 { 1745c8ce3972Sdan db2 close 1746c8ce3972Sdan sqlite3 db2 :memory: 1747c8ce3972Sdan } 1748c8ce3972Sdan sql2 { 1749c8ce3972Sdan PRAGMA omit_readlock = 1; 1750c8ce3972Sdan ATTACH 'test.db' AS two; 1751c8ce3972Sdan BEGIN; 1752c8ce3972Sdan SELECT * FROM t1; 1753c8ce3972Sdan } 1754c8ce3972Sdan } {1 2 3 4 5 6} 1755c8ce3972Sdan do_test pager1-17.$tn.3.2 { 1756c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1757c8ce3972Sdan } {1 {database is locked}} 1758c8ce3972Sdan do_test pager1-17.$tn.3.3 { sql2 COMMIT } {} 1759c8ce3972Sdan} 1760c8ce3972Sdan 1761c8ce3972Sdan#------------------------------------------------------------------------- 1762c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page 1763c8ce3972Sdan# numbers: 1764c8ce3972Sdan# 1765c8ce3972Sdan# + The locking page, 1766c8ce3972Sdan# + Page 0, 1767c8ce3972Sdan# + A page with a page number greater than (2^31-1). 1768c8ce3972Sdan# 1769c8ce3972Sdando_test pager1-18.1 { 1770c8ce3972Sdan faultsim_delete_and_reopen 1771c8ce3972Sdan db func a_string a_string 1772c8ce3972Sdan execsql { 1773c8ce3972Sdan PRAGMA page_size = 1024; 1774c8ce3972Sdan CREATE TABLE t1(a, b); 1775c8ce3972Sdan INSERT INTO t1 VALUES(a_string(500), a_string(200)); 1776c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1777c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1778c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1779c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1780c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1781c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1782c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1783c8ce3972Sdan } 1784c8ce3972Sdan} {} 1785c8ce3972Sdando_test pager1-18.2 { 1786c8ce3972Sdan set root [db one "SELECT rootpage FROM sqlite_master"] 1787c8ce3972Sdan set lockingpage [expr (0x10000/1024) + 1] 1788c8ce3972Sdan execsql { 1789c8ce3972Sdan PRAGMA writable_schema = 1; 1790c8ce3972Sdan UPDATE sqlite_master SET rootpage = $lockingpage; 1791c8ce3972Sdan } 1792c8ce3972Sdan sqlite3 db2 test.db 1793c8ce3972Sdan catchsql { SELECT count(*) FROM t1 } db2 1794c8ce3972Sdan} {1 {database disk image is malformed}} 1795c8ce3972Sdandb2 close 1796c8ce3972Sdando_test pager1-18.3 { 1797c8ce3972Sdan execsql { 1798c8ce3972Sdan CREATE TABLE t2(x); 1799c8ce3972Sdan INSERT INTO t2 VALUES(a_string(5000)); 1800c8ce3972Sdan } 1801c8ce3972Sdan set pgno [expr ([file size test.db] / 1024)-2] 1802c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 00000000 1803c8ce3972Sdan sqlite3 db2 test.db 1804c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1805c8ce3972Sdan} {1 {database disk image is malformed}} 1806c8ce3972Sdandb2 close 1807c8ce3972Sdando_test pager1-18.4 { 1808c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 90000000 1809c8ce3972Sdan sqlite3 db2 test.db 1810c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1811c8ce3972Sdan} {1 {database disk image is malformed}} 1812c8ce3972Sdandb2 close 1813c8ce3972Sdando_test pager1-18.5 { 1814c8ce3972Sdan sqlite3 db "" 1815c8ce3972Sdan execsql { 1816c8ce3972Sdan CREATE TABLE t1(a, b); 1817c8ce3972Sdan CREATE TABLE t2(a, b); 1818c8ce3972Sdan PRAGMA writable_schema = 1; 1819c8ce3972Sdan UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; 1820c8ce3972Sdan PRAGMA writable_schema = 0; 1821c8ce3972Sdan ALTER TABLE t1 RENAME TO x1; 1822c8ce3972Sdan } 1823c8ce3972Sdan catchsql { SELECT * FROM x1 } 1824ba3cbf3dSdan} {1 {database disk image is malformed}} 1825c8ce3972Sdandb close 1826c8ce3972Sdan 1827ba3cbf3dSdando_test pager1-18.6 { 1828ba3cbf3dSdan faultsim_delete_and_reopen 1829ba3cbf3dSdan db func a_string a_string 1830ba3cbf3dSdan execsql { 1831ba3cbf3dSdan PRAGMA page_size = 1024; 1832ba3cbf3dSdan CREATE TABLE t1(x); 1833ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1834ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1835ba3cbf3dSdan } 1836ba3cbf3dSdan 1837ba3cbf3dSdan set root [db one "SELECT rootpage FROM sqlite_master"] 1838ba3cbf3dSdan db close 1839ba3cbf3dSdan 1840ba3cbf3dSdan hexio_write test.db [expr ($root-1)*1024 + 8] 00000000 1841ba3cbf3dSdan sqlite3 db test.db 1842ba3cbf3dSdan catchsql { SELECT length(x) FROM t1 } 1843ba3cbf3dSdan} {1 {database disk image is malformed}} 1844ba3cbf3dSdan 1845ba3cbf3dSdando_test pager1-19.1 { 1846ba3cbf3dSdan sqlite3 db "" 1847ba3cbf3dSdan db func a_string a_string 1848ba3cbf3dSdan execsql { 1849ba3cbf3dSdan PRAGMA page_size = 512; 1850ba3cbf3dSdan PRAGMA auto_vacuum = 1; 1851ba3cbf3dSdan CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1852ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1853ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1854ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1855ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1856ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1857ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1858ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1859ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1860ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1861ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1862ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1863ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1864ba3cbf3dSdan ); 1865ba3cbf3dSdan CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1866ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1867ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1868ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1869ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1870ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1871ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1872ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1873ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1874ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1875ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1876ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1877ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1878ba3cbf3dSdan ); 1879ba3cbf3dSdan INSERT INTO t1(aa) VALUES( a_string(100000) ); 1880ba3cbf3dSdan INSERT INTO t2(aa) VALUES( a_string(100000) ); 1881ba3cbf3dSdan VACUUM; 1882ba3cbf3dSdan } 1883ba3cbf3dSdan} {} 1884ba3cbf3dSdan 18856b63ab47Sdan#------------------------------------------------------------------------- 18866b63ab47Sdan# Test a couple of special cases that come up while committing 18876b63ab47Sdan# transactions: 18886b63ab47Sdan# 18896b63ab47Sdan# pager1-20.1.*: Committing an in-memory database transaction when the 18906b63ab47Sdan# database has not been modified at all. 18916b63ab47Sdan# 18926b63ab47Sdan# pager1-20.2.*: As above, but with a normal db in exclusive-locking mode. 18936b63ab47Sdan# 18946b63ab47Sdan# pager1-20.3.*: Committing a transaction in WAL mode where the database has 18956b63ab47Sdan# been modified, but all dirty pages have been flushed to 18966b63ab47Sdan# disk before the commit. 18976b63ab47Sdan# 18986b63ab47Sdando_test pager1-20.1.1 { 18996b63ab47Sdan catch {db close} 19006b63ab47Sdan sqlite3 db :memory: 19016b63ab47Sdan execsql { 19026b63ab47Sdan CREATE TABLE one(two, three); 19036b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 19046b63ab47Sdan } 19056b63ab47Sdan} {} 19066b63ab47Sdando_test pager1-20.1.2 { 19076b63ab47Sdan execsql { 19086b63ab47Sdan BEGIN EXCLUSIVE; 19096b63ab47Sdan COMMIT; 19106b63ab47Sdan } 19116b63ab47Sdan} {} 19126b63ab47Sdan 19136b63ab47Sdando_test pager1-20.2.1 { 19146b63ab47Sdan faultsim_delete_and_reopen 19156b63ab47Sdan execsql { 19166b63ab47Sdan PRAGMA locking_mode = exclusive; 19176b63ab47Sdan PRAGMA journal_mode = persist; 19186b63ab47Sdan CREATE TABLE one(two, three); 19196b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 19206b63ab47Sdan } 19216b63ab47Sdan} {exclusive persist} 19226b63ab47Sdando_test pager1-20.2.2 { 19236b63ab47Sdan execsql { 19246b63ab47Sdan BEGIN EXCLUSIVE; 19256b63ab47Sdan COMMIT; 19266b63ab47Sdan } 19276b63ab47Sdan} {} 19286b63ab47Sdan 19299091f775Sshanehifcapable wal { 19306b63ab47Sdan do_test pager1-20.3.1 { 19316b63ab47Sdan faultsim_delete_and_reopen 19326b63ab47Sdan db func a_string a_string 19336b63ab47Sdan execsql { 19346b63ab47Sdan PRAGMA cache_size = 10; 19356b63ab47Sdan PRAGMA journal_mode = wal; 19366b63ab47Sdan BEGIN; 19376b63ab47Sdan CREATE TABLE t1(x); 19386b63ab47Sdan CREATE TABLE t2(y); 19396b63ab47Sdan INSERT INTO t1 VALUES(a_string(800)); 19406b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */ 19416b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */ 19426b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */ 19436b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */ 19446b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */ 19456b63ab47Sdan COMMIT; 19466b63ab47Sdan } 19476b63ab47Sdan } {wal} 19486b63ab47Sdan do_test pager1-20.3.2 { 19496b63ab47Sdan execsql { 19506b63ab47Sdan BEGIN; 19516b63ab47Sdan INSERT INTO t2 VALUES('xxxx'); 19526b63ab47Sdan } 1953c396d4afSdan recursive_select 32 t1 19546b63ab47Sdan execsql COMMIT 19556b63ab47Sdan } {} 19569091f775Sshaneh} 19576b63ab47Sdan 195889ccf448Sdan#------------------------------------------------------------------------- 195989ccf448Sdan# Test that a WAL database may not be opened if: 196089ccf448Sdan# 196189ccf448Sdan# pager1-21.1.*: The VFS has an iVersion less than 2, or 196289ccf448Sdan# pager1-21.2.*: The VFS does not provide xShmXXX() methods. 196389ccf448Sdan# 19649091f775Sshanehifcapable wal { 196589ccf448Sdan do_test pager1-21.0 { 196689ccf448Sdan faultsim_delete_and_reopen 196789ccf448Sdan execsql { 196889ccf448Sdan PRAGMA journal_mode = WAL; 196989ccf448Sdan CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); 197089ccf448Sdan INSERT INTO ko DEFAULT VALUES; 197189ccf448Sdan } 197289ccf448Sdan } {wal} 197389ccf448Sdan do_test pager1-21.1 { 197489ccf448Sdan testvfs tv -noshm 1 197589ccf448Sdan sqlite3 db2 test.db -vfs tv 197689ccf448Sdan catchsql { SELECT * FROM ko } db2 197789ccf448Sdan } {1 {unable to open database file}} 197889ccf448Sdan db2 close 197989ccf448Sdan tv delete 198089ccf448Sdan do_test pager1-21.2 { 198189ccf448Sdan testvfs tv -iversion 1 198289ccf448Sdan sqlite3 db2 test.db -vfs tv 198389ccf448Sdan catchsql { SELECT * FROM ko } db2 198489ccf448Sdan } {1 {unable to open database file}} 198589ccf448Sdan db2 close 198689ccf448Sdan tv delete 19879091f775Sshaneh} 198889ccf448Sdan 198989ccf448Sdan#------------------------------------------------------------------------- 199089ccf448Sdan# Test that a "PRAGMA wal_checkpoint": 199189ccf448Sdan# 199289ccf448Sdan# pager1-22.1.*: is a no-op on a non-WAL db, and 199389ccf448Sdan# pager1-22.2.*: does not cause xSync calls with a synchronous=off db. 199489ccf448Sdan# 199589ccf448Sdando_test pager1-22.1.1 { 199689ccf448Sdan faultsim_delete_and_reopen 199789ccf448Sdan execsql { 199889ccf448Sdan CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); 199989ccf448Sdan INSERT INTO ko DEFAULT VALUES; 200089ccf448Sdan } 200189ccf448Sdan execsql { PRAGMA wal_checkpoint } 2002bdd9af0fSdan} {0 -1 -1} 200389ccf448Sdando_test pager1-22.2.1 { 200489ccf448Sdan testvfs tv -default 1 200589ccf448Sdan tv filter xSync 200689ccf448Sdan tv script xSyncCb 200789ccf448Sdan proc xSyncCb {args} {incr ::synccount} 200889ccf448Sdan set ::synccount 0 200989ccf448Sdan sqlite3 db test.db 201089ccf448Sdan execsql { 201189ccf448Sdan PRAGMA synchronous = off; 201289ccf448Sdan PRAGMA journal_mode = WAL; 201389ccf448Sdan INSERT INTO ko DEFAULT VALUES; 201489ccf448Sdan } 201589ccf448Sdan execsql { PRAGMA wal_checkpoint } 201689ccf448Sdan set synccount 201789ccf448Sdan} {0} 201889ccf448Sdandb close 201989ccf448Sdantv delete 202089ccf448Sdan 202189ccf448Sdan#------------------------------------------------------------------------- 202289ccf448Sdan# Tests for changing journal mode. 202389ccf448Sdan# 202489ccf448Sdan# pager1-23.1.*: Test that when changing from PERSIST to DELETE mode, 202589ccf448Sdan# the journal file is deleted. 202689ccf448Sdan# 202789ccf448Sdan# pager1-23.2.*: Same test as above, but while a shared lock is held 202889ccf448Sdan# on the database file. 202989ccf448Sdan# 203089ccf448Sdan# pager1-23.3.*: Same test as above, but while a reserved lock is held 203189ccf448Sdan# on the database file. 203289ccf448Sdan# 203389ccf448Sdan# pager1-23.4.*: And, for fun, while holding an exclusive lock. 203489ccf448Sdan# 203589ccf448Sdan# pager1-23.5.*: Try to set various different journal modes with an 203689ccf448Sdan# in-memory database (only MEMORY and OFF should work). 203789ccf448Sdan# 2038d0b0d4dcSdan# pager1-23.6.*: Try to set locking_mode=normal on an in-memory database 2039d0b0d4dcSdan# (doesn't work - in-memory databases always use 2040d0b0d4dcSdan# locking_mode=exclusive). 2041d0b0d4dcSdan# 204289ccf448Sdando_test pager1-23.1.1 { 204389ccf448Sdan faultsim_delete_and_reopen 204489ccf448Sdan execsql { 204589ccf448Sdan PRAGMA journal_mode = PERSIST; 204689ccf448Sdan CREATE TABLE t1(a, b); 204789ccf448Sdan } 204889ccf448Sdan file exists test.db-journal 204989ccf448Sdan} {1} 205089ccf448Sdando_test pager1-23.1.2 { 205189ccf448Sdan execsql { PRAGMA journal_mode = DELETE } 205289ccf448Sdan file exists test.db-journal 205389ccf448Sdan} {0} 205489ccf448Sdan 205589ccf448Sdando_test pager1-23.2.1 { 205689ccf448Sdan execsql { 205789ccf448Sdan PRAGMA journal_mode = PERSIST; 205889ccf448Sdan INSERT INTO t1 VALUES('Canberra', 'ACT'); 205989ccf448Sdan } 206089ccf448Sdan db eval { SELECT * FROM t1 } { 206189ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 206289ccf448Sdan } 206389ccf448Sdan execsql { PRAGMA journal_mode } 206489ccf448Sdan} {delete} 206589ccf448Sdando_test pager1-23.2.2 { 206689ccf448Sdan file exists test.db-journal 206789ccf448Sdan} {0} 206889ccf448Sdan 206989ccf448Sdando_test pager1-23.3.1 { 207089ccf448Sdan execsql { 207189ccf448Sdan PRAGMA journal_mode = PERSIST; 207289ccf448Sdan INSERT INTO t1 VALUES('Darwin', 'NT'); 207389ccf448Sdan BEGIN IMMEDIATE; 207489ccf448Sdan } 207589ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 207689ccf448Sdan execsql { PRAGMA journal_mode } 207789ccf448Sdan} {delete} 207889ccf448Sdando_test pager1-23.3.2 { 207989ccf448Sdan file exists test.db-journal 208089ccf448Sdan} {0} 208189ccf448Sdando_test pager1-23.3.3 { 208289ccf448Sdan execsql COMMIT 208389ccf448Sdan} {} 208489ccf448Sdan 208589ccf448Sdando_test pager1-23.4.1 { 208689ccf448Sdan execsql { 208789ccf448Sdan PRAGMA journal_mode = PERSIST; 208889ccf448Sdan INSERT INTO t1 VALUES('Adelaide', 'SA'); 208989ccf448Sdan BEGIN EXCLUSIVE; 209089ccf448Sdan } 209189ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 209289ccf448Sdan execsql { PRAGMA journal_mode } 209389ccf448Sdan} {delete} 209489ccf448Sdando_test pager1-23.4.2 { 209589ccf448Sdan file exists test.db-journal 209689ccf448Sdan} {0} 209789ccf448Sdando_test pager1-23.4.3 { 209889ccf448Sdan execsql COMMIT 209989ccf448Sdan} {} 210089ccf448Sdan 210189ccf448Sdando_test pager1-23.5.1 { 210289ccf448Sdan faultsim_delete_and_reopen 210389ccf448Sdan sqlite3 db :memory: 210489ccf448Sdan} {} 210589ccf448Sdanforeach {tn mode possible} { 210689ccf448Sdan 2 off 1 210789ccf448Sdan 3 memory 1 210889ccf448Sdan 4 persist 0 210989ccf448Sdan 5 delete 0 211089ccf448Sdan 6 wal 0 211189ccf448Sdan 7 truncate 0 211289ccf448Sdan} { 211389ccf448Sdan do_test pager1-23.5.$tn.1 { 211489ccf448Sdan execsql "PRAGMA journal_mode = off" 211589ccf448Sdan execsql "PRAGMA journal_mode = $mode" 211689ccf448Sdan } [if $possible {list $mode} {list off}] 211789ccf448Sdan do_test pager1-23.5.$tn.2 { 211889ccf448Sdan execsql "PRAGMA journal_mode = memory" 211989ccf448Sdan execsql "PRAGMA journal_mode = $mode" 212089ccf448Sdan } [if $possible {list $mode} {list memory}] 212189ccf448Sdan} 2122d0b0d4dcSdando_test pager1-23.6.1 { 212389ccf448Sdan execsql {PRAGMA locking_mode = normal} 212489ccf448Sdan} {exclusive} 2125d0b0d4dcSdando_test pager1-23.6.2 { 212689ccf448Sdan execsql {PRAGMA locking_mode = exclusive} 212789ccf448Sdan} {exclusive} 2128d0b0d4dcSdando_test pager1-23.6.3 { 212989ccf448Sdan execsql {PRAGMA locking_mode} 213089ccf448Sdan} {exclusive} 2131d0b0d4dcSdando_test pager1-23.6.4 { 213289ccf448Sdan execsql {PRAGMA main.locking_mode} 213389ccf448Sdan} {exclusive} 21346b63ab47Sdan 2135d0b0d4dcSdan#------------------------------------------------------------------------- 2136d0b0d4dcSdan# 2137d0b0d4dcSdando_test pager1-24.1.1 { 2138d0b0d4dcSdan faultsim_delete_and_reopen 2139d0b0d4dcSdan db func a_string a_string 2140d0b0d4dcSdan execsql { 2141d0b0d4dcSdan PRAGMA cache_size = 10; 2142d0b0d4dcSdan PRAGMA auto_vacuum = FULL; 2143d0b0d4dcSdan CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z)); 2144d0b0d4dcSdan CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z)); 2145d0b0d4dcSdan INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600)); 2146d0b0d4dcSdan INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2; 2147d0b0d4dcSdan INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2; 2148d0b0d4dcSdan INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2; 2149d0b0d4dcSdan INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2; 2150d0b0d4dcSdan INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2; 2151d0b0d4dcSdan INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2; 2152d0b0d4dcSdan INSERT INTO x1 SELECT * FROM x2; 2153d0b0d4dcSdan } 2154d0b0d4dcSdan} {} 2155d0b0d4dcSdando_test pager1-24.1.2 { 2156d0b0d4dcSdan execsql { 2157d0b0d4dcSdan BEGIN; 2158d0b0d4dcSdan DELETE FROM x1 WHERE rowid<32; 2159d0b0d4dcSdan } 2160c396d4afSdan recursive_select 64 x2 2161d0b0d4dcSdan} {} 2162d0b0d4dcSdando_test pager1-24.1.3 { 2163d0b0d4dcSdan execsql { 2164d0b0d4dcSdan UPDATE x1 SET z = a_string(300) WHERE rowid>40; 2165d0b0d4dcSdan COMMIT; 2166d0b0d4dcSdan PRAGMA integrity_check; 2167d0b0d4dcSdan SELECT count(*) FROM x1; 2168d0b0d4dcSdan } 2169d0b0d4dcSdan} {ok 33} 2170d0b0d4dcSdan 2171d0b0d4dcSdando_test pager1-24.1.4 { 2172d0b0d4dcSdan execsql { 2173d0b0d4dcSdan DELETE FROM x1; 2174d0b0d4dcSdan INSERT INTO x1 SELECT * FROM x2; 2175d0b0d4dcSdan BEGIN; 2176d0b0d4dcSdan DELETE FROM x1 WHERE rowid<32; 2177d0b0d4dcSdan UPDATE x1 SET z = a_string(299) WHERE rowid>40; 2178d0b0d4dcSdan } 2179c396d4afSdan recursive_select 64 x2 {db eval COMMIT} 2180d0b0d4dcSdan execsql { 2181d0b0d4dcSdan PRAGMA integrity_check; 2182d0b0d4dcSdan SELECT count(*) FROM x1; 2183d0b0d4dcSdan } 2184d0b0d4dcSdan} {ok 33} 2185d0b0d4dcSdan 2186d0b0d4dcSdando_test pager1-24.1.5 { 2187d0b0d4dcSdan execsql { 2188d0b0d4dcSdan DELETE FROM x1; 2189d0b0d4dcSdan INSERT INTO x1 SELECT * FROM x2; 2190d0b0d4dcSdan } 2191c396d4afSdan recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} } 2192d0b0d4dcSdan execsql { SELECT * FROM x3 } 2193d0b0d4dcSdan} {} 2194d0b0d4dcSdan 2195d0b0d4dcSdan#------------------------------------------------------------------------- 2196d0b0d4dcSdan# 2197d0b0d4dcSdando_test pager1-25-1 { 2198d0b0d4dcSdan faultsim_delete_and_reopen 2199d0b0d4dcSdan execsql { 2200d0b0d4dcSdan BEGIN; 2201d0b0d4dcSdan SAVEPOINT abc; 2202d0b0d4dcSdan CREATE TABLE t1(a, b); 2203d0b0d4dcSdan ROLLBACK TO abc; 2204d0b0d4dcSdan COMMIT; 2205d0b0d4dcSdan } 2206d0b0d4dcSdan db close 2207d0b0d4dcSdan} {} 2208d0b0d4dcSdanbreakpoint 2209d0b0d4dcSdando_test pager1-25-2 { 2210d0b0d4dcSdan faultsim_delete_and_reopen 2211d0b0d4dcSdan execsql { 2212d0b0d4dcSdan SAVEPOINT abc; 2213d0b0d4dcSdan CREATE TABLE t1(a, b); 2214d0b0d4dcSdan ROLLBACK TO abc; 2215d0b0d4dcSdan COMMIT; 2216d0b0d4dcSdan } 2217d0b0d4dcSdan db close 2218d0b0d4dcSdan} {} 22196b63ab47Sdan 2220c396d4afSdan#------------------------------------------------------------------------- 2221c396d4afSdan# Sector-size tests. 2222c396d4afSdan# 2223c396d4afSdando_test pager1-26.1 { 2224c396d4afSdan testvfs tv -default 1 2225c396d4afSdan tv sectorsize 4096 2226c396d4afSdan faultsim_delete_and_reopen 2227c396d4afSdan db func a_string a_string 2228c396d4afSdan execsql { 2229c396d4afSdan PRAGMA page_size = 512; 2230c396d4afSdan CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE); 2231c396d4afSdan BEGIN; 2232c396d4afSdan INSERT INTO tbl VALUES(a_string(25), a_string(600)); 2233c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2234c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2235c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2236c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2237c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2238c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2239c396d4afSdan INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl; 2240c396d4afSdan COMMIT; 2241c396d4afSdan } 2242c396d4afSdan} {} 2243c396d4afSdando_execsql_test pager1-26.1 { 2244c396d4afSdan UPDATE tbl SET b = a_string(550); 2245c396d4afSdan} {} 2246c396d4afSdandb close 2247c396d4afSdantv delete 2248c396d4afSdan 2249c396d4afSdan#------------------------------------------------------------------------- 225022b328b2Sdan# 2251c396d4afSdando_test pager1.27.1 { 2252c396d4afSdan faultsim_delete_and_reopen 2253c396d4afSdan sqlite3_pager_refcounts db 2254c396d4afSdan execsql { 2255c396d4afSdan BEGIN; 2256c396d4afSdan CREATE TABLE t1(a, b); 2257c396d4afSdan } 2258c396d4afSdan sqlite3_pager_refcounts db 2259c396d4afSdan execsql COMMIT 2260c396d4afSdan} {} 2261c396d4afSdan 226222b328b2Sdan#------------------------------------------------------------------------- 226322b328b2Sdan# Test that attempting to open a write-transaction with 226422b328b2Sdan# locking_mode=exclusive in WAL mode fails if there are other clients on 226522b328b2Sdan# the same database. 226622b328b2Sdan# 226722b328b2Sdancatch { db close } 22689091f775Sshanehifcapable wal { 226922b328b2Sdan do_multiclient_test tn { 227022b328b2Sdan do_test pager1-28.$tn.1 { 227122b328b2Sdan sql1 { 227222b328b2Sdan PRAGMA journal_mode = WAL; 227322b328b2Sdan CREATE TABLE t1(a, b); 227422b328b2Sdan INSERT INTO t1 VALUES('a', 'b'); 227522b328b2Sdan } 227622b328b2Sdan } {wal} 227722b328b2Sdan do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b} 227822b328b2Sdan 227922b328b2Sdan do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive} 228022b328b2Sdan do_test pager1-28.$tn.4 { 228122b328b2Sdan csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); } 228222b328b2Sdan } {1 {database is locked}} 228322b328b2Sdan code2 { db2 close ; sqlite3 db2 test.db } 228422b328b2Sdan do_test pager1-28.$tn.4 { 228522b328b2Sdan sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT } 228622b328b2Sdan } {} 228722b328b2Sdan } 22889091f775Sshaneh} 22895653e4daSdan 22905653e4daSdan#------------------------------------------------------------------------- 22915653e4daSdan# Normally, when changing from journal_mode=PERSIST to DELETE the pager 22925653e4daSdan# attempts to delete the journal file. However, if it cannot obtain a 22935653e4daSdan# RESERVED lock on the database file, this step is skipped. 22945653e4daSdan# 22955653e4daSdando_multiclient_test tn { 22965653e4daSdan do_test pager1-28.$tn.1 { 22975653e4daSdan sql1 { 22985653e4daSdan PRAGMA journal_mode = PERSIST; 22995653e4daSdan CREATE TABLE t1(a, b); 23005653e4daSdan INSERT INTO t1 VALUES('a', 'b'); 23015653e4daSdan } 23025653e4daSdan } {persist} 23035653e4daSdan do_test pager1-28.$tn.2 { file exists test.db-journal } 1 23045653e4daSdan do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete 23055653e4daSdan do_test pager1-28.$tn.4 { file exists test.db-journal } 0 23065653e4daSdan 23075653e4daSdan do_test pager1-28.$tn.5 { 23085653e4daSdan sql1 { 23095653e4daSdan PRAGMA journal_mode = PERSIST; 23105653e4daSdan INSERT INTO t1 VALUES('c', 'd'); 23115653e4daSdan } 23125653e4daSdan } {persist} 23135653e4daSdan do_test pager1-28.$tn.6 { file exists test.db-journal } 1 23145653e4daSdan do_test pager1-28.$tn.7 { 23155653e4daSdan sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); } 23165653e4daSdan } {} 23175653e4daSdan do_test pager1-28.$tn.8 { file exists test.db-journal } 1 23185653e4daSdan do_test pager1-28.$tn.9 { sql1 { PRAGMA journal_mode = DELETE } } delete 23195653e4daSdan do_test pager1-28.$tn.10 { file exists test.db-journal } 1 23205653e4daSdan 23215653e4daSdan do_test pager1-28.$tn.11 { sql2 COMMIT } {} 23225653e4daSdan do_test pager1-28.$tn.12 { file exists test.db-journal } 0 23235653e4daSdan 23245653e4daSdan do_test pager1-28-$tn.13 { 23255653e4daSdan code1 { set channel [db incrblob -readonly t1 a 2] } 23265653e4daSdan sql1 { 23275653e4daSdan PRAGMA journal_mode = PERSIST; 23285653e4daSdan INSERT INTO t1 VALUES('g', 'h'); 23295653e4daSdan } 23305653e4daSdan } {persist} 23315653e4daSdan do_test pager1-28.$tn.14 { file exists test.db-journal } 1 23325653e4daSdan do_test pager1-28.$tn.15 { 23335653e4daSdan sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); } 23345653e4daSdan } {} 23355653e4daSdan do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete 23365653e4daSdan do_test pager1-28.$tn.17 { file exists test.db-journal } 1 23375653e4daSdan 23385653e4daSdan do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}} 23395653e4daSdan do_test pager1-28-$tn.18 { code1 { read $channel } } c 23405653e4daSdan do_test pager1-28-$tn.19 { code1 { close $channel } } {} 23415653e4daSdan do_test pager1-28.$tn.20 { sql2 { COMMIT } } {} 23425653e4daSdan} 23435653e4daSdan 23441879b088Sdando_test pager1-29.1 { 23451879b088Sdan faultsim_delete_and_reopen 23461879b088Sdan execsql { 23471879b088Sdan PRAGMA page_size = 1024; 23481879b088Sdan PRAGMA auto_vacuum = full; 23491879b088Sdan PRAGMA locking_mode=exclusive; 23501879b088Sdan CREATE TABLE t1(a, b); 23511879b088Sdan INSERT INTO t1 VALUES(1, 2); 23521879b088Sdan } 23531879b088Sdan file size test.db 23541879b088Sdan} [expr 1024*3] 23551879b088Sdando_test pager1-29.2 { 23561879b088Sdan execsql { 23571879b088Sdan PRAGMA page_size = 4096; 23581879b088Sdan VACUUM; 23591879b088Sdan } 23601879b088Sdan file size test.db 23611879b088Sdan} [expr 4096*3] 23621879b088Sdan 2363e08c2066Sdan#------------------------------------------------------------------------- 2364e08c2066Sdan# Test that if an empty database file (size 0 bytes) is opened in 2365e08c2066Sdan# exclusive-locking mode, any journal file is deleted from the file-system 2366e08c2066Sdan# without being rolled back. And that the RESERVED lock obtained while 2367e08c2066Sdan# doing this is not released. 2368e08c2066Sdan# 2369e08c2066Sdando_test pager1-30.1 { 2370e08c2066Sdan db close 2371*fda06befSmistachkin delete_file test.db 2372*fda06befSmistachkin delete_file test.db-journal 2373e08c2066Sdan set fd [open test.db-journal w] 2374e08c2066Sdan seek $fd [expr 512+1032*2] 2375e08c2066Sdan puts -nonewline $fd x 2376e08c2066Sdan close $fd 2377e08c2066Sdan 2378e08c2066Sdan sqlite3 db test.db 2379e08c2066Sdan execsql { 2380e08c2066Sdan PRAGMA locking_mode=EXCLUSIVE; 2381e08c2066Sdan SELECT count(*) FROM sqlite_master; 2382e08c2066Sdan PRAGMA lock_status; 2383e08c2066Sdan } 2384e08c2066Sdan} {exclusive 0 main reserved temp closed} 2385e08c2066Sdan 2386e08c2066Sdan#------------------------------------------------------------------------- 2387e08c2066Sdan# Test that if the "page-size" field in a journal-header is 0, the journal 2388e08c2066Sdan# file can still be rolled back. This is required for backward compatibility - 2389e08c2066Sdan# versions of SQLite prior to 3.5.8 always set this field to zero. 2390e08c2066Sdan# 239133f5379cSdanif {$tcl_platform(platform)=="unix"} { 2392e08c2066Sdando_test pager1-31.1 { 2393e08c2066Sdan faultsim_delete_and_reopen 2394e08c2066Sdan execsql { 2395e08c2066Sdan PRAGMA cache_size = 10; 2396e08c2066Sdan PRAGMA page_size = 1024; 2397e08c2066Sdan CREATE TABLE t1(x, y, UNIQUE(x, y)); 2398e08c2066Sdan INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500)); 2399e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2400e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2401e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2402e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2403e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2404e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2405e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2406e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2407e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2408e08c2066Sdan INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1; 2409e08c2066Sdan BEGIN; 2410e08c2066Sdan UPDATE t1 SET y = randomblob(1499); 2411e08c2066Sdan } 2412*fda06befSmistachkin copy_file test.db test.db2 2413*fda06befSmistachkin copy_file test.db-journal test.db2-journal 2414e08c2066Sdan 2415e08c2066Sdan hexio_write test.db2-journal 24 00000000 2416e08c2066Sdan sqlite3 db2 test.db2 2417e08c2066Sdan execsql { PRAGMA integrity_check } db2 2418e08c2066Sdan} {ok} 241933f5379cSdan} 2420e08c2066Sdan 24215653e4daSdan 2422d353331aSdanfinish_test 2423