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 6253f04f3bSdanset a_string_counter 1 6353f04f3bSdanproc a_string {n} { 6453f04f3bSdan global a_string_counter 6553f04f3bSdan incr a_string_counter 6653f04f3bSdan string range [string repeat "${a_string_counter}." $n] 1 $n 6753f04f3bSdan} 6853f04f3bSdandb func a_string a_string 6953f04f3bSdan 70a4a9095eSdando_multiclient_test tn { 71e91a54e1Sdan 72e91a54e1Sdan # Create and populate a database table using connection [db]. Check 73e91a54e1Sdan # that connections [db2] and [db3] can see the schema and content. 74e91a54e1Sdan # 75e91a54e1Sdan do_test pager1-$tn.1 { 76e91a54e1Sdan sql1 { 77e91a54e1Sdan CREATE TABLE t1(a PRIMARY KEY, b); 78e91a54e1Sdan CREATE INDEX i1 ON t1(b); 79d353331aSdan INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); 80e91a54e1Sdan } 81e91a54e1Sdan } {} 82e91a54e1Sdan do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two} 83e91a54e1Sdan do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two} 84e91a54e1Sdan 85e91a54e1Sdan # Open a transaction and add a row using [db]. This puts [db] in 86e91a54e1Sdan # RESERVED state. Check that connections [db2] and [db3] can still 87e91a54e1Sdan # read the database content as it was before the transaction was 88e91a54e1Sdan # opened. [db] should see the inserted row. 89e91a54e1Sdan # 90e91a54e1Sdan do_test pager1-$tn.4 { 91e91a54e1Sdan sql1 { 92e91a54e1Sdan BEGIN; 93e91a54e1Sdan INSERT INTO t1 VALUES(3, 'three'); 94e91a54e1Sdan } 95e91a54e1Sdan } {} 96e91a54e1Sdan do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two} 97e91a54e1Sdan do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three} 98e91a54e1Sdan 99e91a54e1Sdan # [db] still has an open write transaction. Check that this prevents 100e91a54e1Sdan # other connections (specifically [db2]) from writing to the database. 101e91a54e1Sdan # 102e91a54e1Sdan # Even if [db2] opens a transaction first, it may not write to the 103e91a54e1Sdan # database. After the attempt to write the db within a transaction, 104e91a54e1Sdan # [db2] is left with an open transaction, but not a read-lock on 105e91a54e1Sdan # the main database. So it does not prevent [db] from committing. 106e91a54e1Sdan # 107e91a54e1Sdan do_test pager1-$tn.8 { 108e91a54e1Sdan csql2 { UPDATE t1 SET a = a + 10 } 109e91a54e1Sdan } {1 {database is locked}} 110e91a54e1Sdan do_test pager1-$tn.9 { 111e91a54e1Sdan csql2 { 112e91a54e1Sdan BEGIN; 113e91a54e1Sdan UPDATE t1 SET a = a + 10; 114e91a54e1Sdan } 115e91a54e1Sdan } {1 {database is locked}} 116e91a54e1Sdan 117e91a54e1Sdan # Have [db] commit its transactions. Check the other connections can 118e91a54e1Sdan # now see the new database content. 119e91a54e1Sdan # 120e91a54e1Sdan do_test pager1-$tn.10 { sql1 { COMMIT } } {} 121e91a54e1Sdan do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three} 122e91a54e1Sdan do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 123e91a54e1Sdan do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 124e91a54e1Sdan 125e91a54e1Sdan # Check that, as noted above, [db2] really did keep an open transaction 126e91a54e1Sdan # after the attempt to write the database failed. 127e91a54e1Sdan # 128e91a54e1Sdan do_test pager1-$tn.14 { 129e91a54e1Sdan csql2 { BEGIN } 130e91a54e1Sdan } {1 {cannot start a transaction within a transaction}} 131e91a54e1Sdan do_test pager1-$tn.15 { sql2 { ROLLBACK } } {} 132e91a54e1Sdan 133e91a54e1Sdan # Have [db2] open a transaction and take a read-lock on the database. 134e91a54e1Sdan # Check that this prevents [db] from writing to the database (outside 135e91a54e1Sdan # of any transaction). After this fails, check that [db3] can read 136e91a54e1Sdan # the db (showing that [db] did not take a PENDING lock etc.) 137e91a54e1Sdan # 138e91a54e1Sdan do_test pager1-$tn.15 { 139e91a54e1Sdan sql2 { BEGIN; SELECT * FROM t1; } 140e91a54e1Sdan } {1 one 2 two 3 three} 141e91a54e1Sdan do_test pager1-$tn.16 { 142e91a54e1Sdan csql1 { UPDATE t1 SET a = a + 10 } 143e91a54e1Sdan } {1 {database is locked}} 144e91a54e1Sdan do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 145e91a54e1Sdan 146e91a54e1Sdan # This time, have [db] open a transaction before writing the database. 147e91a54e1Sdan # This works - [db] gets a RESERVED lock which does not conflict with 148e91a54e1Sdan # the SHARED lock [db2] is holding. 149e91a54e1Sdan # 150e91a54e1Sdan do_test pager1-$tn.18 { 151e91a54e1Sdan sql1 { 152e91a54e1Sdan BEGIN; 153e91a54e1Sdan UPDATE t1 SET a = a + 10; 154e91a54e1Sdan } 155e91a54e1Sdan } {} 156e91a54e1Sdan do_test pager1-$tn-19 { 157e91a54e1Sdan sql1 { PRAGMA lock_status } 158e91a54e1Sdan } {main reserved temp closed} 159e91a54e1Sdan do_test pager1-$tn-20 { 160e91a54e1Sdan sql2 { PRAGMA lock_status } 161e91a54e1Sdan } {main shared temp closed} 162e91a54e1Sdan 163e91a54e1Sdan # Check that all connections can still read the database. Only [db] sees 164e91a54e1Sdan # the updated content (as the transaction has not been committed yet). 165e91a54e1Sdan # 166e91a54e1Sdan do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three} 167e91a54e1Sdan do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 168e91a54e1Sdan do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three} 169e91a54e1Sdan 170e91a54e1Sdan # Because [db2] still has the SHARED lock, [db] is unable to commit the 171e91a54e1Sdan # transaction. If it tries, an error is returned and the connection 172e91a54e1Sdan # upgrades to a PENDING lock. 173e91a54e1Sdan # 174e91a54e1Sdan # Once this happens, [db] can read the database and see the new content, 175e91a54e1Sdan # [db2] (still holding SHARED) can still read the old content, but [db3] 176e91a54e1Sdan # (not holding any lock) is prevented by [db]'s PENDING from reading 177e91a54e1Sdan # the database. 178e91a54e1Sdan # 179e91a54e1Sdan do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}} 180e91a54e1Sdan do_test pager1-$tn-25 { 181e91a54e1Sdan sql1 { PRAGMA lock_status } 182e91a54e1Sdan } {main pending temp closed} 183e91a54e1Sdan do_test pager1-$tn.26 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three} 184e91a54e1Sdan do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three} 185e91a54e1Sdan do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}} 186e91a54e1Sdan 187e91a54e1Sdan # Have [db2] commit its read transaction, releasing the SHARED lock it 188e91a54e1Sdan # is holding. Now, neither [db2] nor [db3] may read the database (as [db] 189e91a54e1Sdan # is still holding a PENDING). 190e91a54e1Sdan # 191e91a54e1Sdan do_test pager1-$tn.29 { sql2 { COMMIT } } {} 192e91a54e1Sdan do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}} 193e91a54e1Sdan do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}} 194e91a54e1Sdan 195e91a54e1Sdan # [db] is now able to commit the transaction. Once the transaction is 196e91a54e1Sdan # committed, all three connections can read the new content. 197e91a54e1Sdan # 198e91a54e1Sdan do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {} 199e91a54e1Sdan do_test pager1-$tn.26 { sql1 { COMMIT } } {} 200e91a54e1Sdan do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three} 201e91a54e1Sdan do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three} 202e91a54e1Sdan do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three} 203d353331aSdan 204d353331aSdan # Install a busy-handler for connection [db]. 205d353331aSdan # 206d353331aSdan set ::nbusy [list] 207d353331aSdan proc busy {n} { 208d353331aSdan lappend ::nbusy $n 209d353331aSdan if {$n>5} { sql2 COMMIT } 210d353331aSdan return 0 211d353331aSdan } 212d353331aSdan db busy busy 213d353331aSdan 214d353331aSdan do_test pager1-$tn.29 { 215d353331aSdan sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') } 216d353331aSdan } {} 217d353331aSdan do_test pager1-$tn.30 { 218d353331aSdan sql2 { BEGIN ; SELECT * FROM t1 } 219d353331aSdan } {21 one 22 two 23 three} 220d353331aSdan do_test pager1-$tn.31 { sql1 COMMIT } {} 221d353331aSdan do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6} 222e91a54e1Sdan} 223e91a54e1Sdan 22453f04f3bSdan#------------------------------------------------------------------------- 22553f04f3bSdan# Savepoint related test cases. 22653f04f3bSdan# 227dca321aeSdan# pager1-3.1.2.*: Force a savepoint rollback to cause the database file 228dca321aeSdan# to grow. 229dca321aeSdan# 230273f3f0dSdan# pager1-3.1.3.*: Use a journal created in synchronous=off mode as part 231273f3f0dSdan# of a savepoint rollback. 232273f3f0dSdan# 2330e986f51Sdando_test pager1-3.1.1 { 234b0ac3e3aSdan faultsim_delete_and_reopen 235b0ac3e3aSdan execsql { 236b0ac3e3aSdan CREATE TABLE t1(a PRIMARY KEY, b); 237b0ac3e3aSdan CREATE TABLE counter( 238b0ac3e3aSdan i CHECK (i<5), 239b0ac3e3aSdan u CHECK (u<10) 240b0ac3e3aSdan ); 241b0ac3e3aSdan INSERT INTO counter VALUES(0, 0); 242b0ac3e3aSdan CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN 243b0ac3e3aSdan UPDATE counter SET i = i+1; 244b0ac3e3aSdan END; 245b0ac3e3aSdan CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN 246b0ac3e3aSdan UPDATE counter SET u = u+1; 247b0ac3e3aSdan END; 248b0ac3e3aSdan } 249b0ac3e3aSdan execsql { SELECT * FROM counter } 250b0ac3e3aSdan} {0 0} 251b0ac3e3aSdan 2520e986f51Sdando_execsql_test pager1-3.1.2 { 253d353331aSdan PRAGMA cache_size = 10; 254b0ac3e3aSdan BEGIN; 255b0ac3e3aSdan INSERT INTO t1 VALUES(1, randomblob(1500)); 256b0ac3e3aSdan INSERT INTO t1 VALUES(2, randomblob(1500)); 257b0ac3e3aSdan INSERT INTO t1 VALUES(3, randomblob(1500)); 258b0ac3e3aSdan SELECT * FROM counter; 259b0ac3e3aSdan} {3 0} 2600e986f51Sdando_catchsql_test pager1-3.1.3 { 261b0ac3e3aSdan INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1 262b0ac3e3aSdan} {1 {constraint failed}} 263b0ac3e3aSdando_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} 264b0ac3e3aSdando_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} 265b0ac3e3aSdando_execsql_test pager1-3.6 { COMMIT } {} 266b0ac3e3aSdan 267273f3f0dSdanforeach {tn sql tcl} { 268d353331aSdan 7 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } { 269273f3f0dSdan testvfs tv -default 1 270273f3f0dSdan tv devchar safe_append 271273f3f0dSdan } 272d353331aSdan 8 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } { 273d353331aSdan testvfs tv -default 1 274d353331aSdan tv devchar sequential 275d353331aSdan } 276d353331aSdan 9 { PRAGMA synchronous = FULL } { } 277d353331aSdan 10 { PRAGMA synchronous = NORMAL } { } 278d353331aSdan 11 { PRAGMA synchronous = OFF } { } 279d353331aSdan 12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { } 280d353331aSdan 13 { PRAGMA synchronous = FULL } { 281d353331aSdan testvfs tv -default 1 282d353331aSdan tv devchar sequential 283d353331aSdan } 2846b63ab47Sdan 14 { PRAGMA locking_mode = EXCLUSIVE } { 2856b63ab47Sdan } 286273f3f0dSdan} { 287273f3f0dSdan do_test pager1-3.$tn.1 { 288273f3f0dSdan eval $tcl 289dca321aeSdan faultsim_delete_and_reopen 290dca321aeSdan db func a_string a_string 291273f3f0dSdan execsql $sql 292dca321aeSdan execsql { 293dca321aeSdan PRAGMA auto_vacuum = 2; 294dca321aeSdan PRAGMA cache_size = 10; 295dca321aeSdan CREATE TABLE z(x INTEGER PRIMARY KEY, y); 296dca321aeSdan BEGIN; 297dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 298dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 2 299dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 4 300dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 8 301dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 16 302dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 32 303dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 64 304dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 128 305dca321aeSdan INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 256 306dca321aeSdan COMMIT; 307dca321aeSdan } 308dca321aeSdan execsql { PRAGMA auto_vacuum } 309dca321aeSdan } {2} 310273f3f0dSdan do_execsql_test pager1-3.$tn.2 { 311dca321aeSdan BEGIN; 312dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 313dca321aeSdan INSERT INTO z VALUES(NULL, a_string(800)); 314dca321aeSdan SAVEPOINT one; 315273f3f0dSdan UPDATE z SET y = NULL WHERE x>256; 316dca321aeSdan PRAGMA incremental_vacuum; 317dca321aeSdan SELECT count(*) FROM z WHERE x < 100; 318dca321aeSdan ROLLBACK TO one; 319dca321aeSdan COMMIT; 320dca321aeSdan } {99} 321dca321aeSdan 322273f3f0dSdan do_execsql_test pager1-3.$tn.3 { 323273f3f0dSdan BEGIN; 324273f3f0dSdan SAVEPOINT one; 325273f3f0dSdan UPDATE z SET y = y||x; 326273f3f0dSdan ROLLBACK TO one; 327273f3f0dSdan COMMIT; 328273f3f0dSdan SELECT count(*) FROM z; 329273f3f0dSdan } {258} 330273f3f0dSdan 331273f3f0dSdan do_execsql_test pager1-3.$tn.4 { 332273f3f0dSdan SAVEPOINT one; 333273f3f0dSdan UPDATE z SET y = y||x; 334273f3f0dSdan ROLLBACK TO one; 335273f3f0dSdan } {} 336273f3f0dSdan do_execsql_test pager1-3.$tn.5 { 337273f3f0dSdan SELECT count(*) FROM z; 338273f3f0dSdan RELEASE one; 339273f3f0dSdan PRAGMA integrity_check; 340273f3f0dSdan } {258 ok} 341273f3f0dSdan 342273f3f0dSdan db close 343273f3f0dSdan catch { tv delete } 344273f3f0dSdan} 345273f3f0dSdan 34653f04f3bSdan#------------------------------------------------------------------------- 34753f04f3bSdan# Hot journal rollback related test cases. 34853f04f3bSdan# 34953f04f3bSdan# pager1.4.1.*: Test that the pager module deletes very small invalid 35053f04f3bSdan# journal files. 35153f04f3bSdan# 35253f04f3bSdan# pager1.4.2.*: Test that if the master journal pointer at the end of a 35353f04f3bSdan# hot-journal file appears to be corrupt (checksum does not 35453f04f3bSdan# compute) the associated journal is rolled back (and no 35553f04f3bSdan# xAccess() call to check for the presence of any master 35653f04f3bSdan# journal file is made). 35753f04f3bSdan# 358de4996e2Sdan# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the 359de4996e2Sdan# page-size or sector-size in the journal header appear to 360de4996e2Sdan# be invalid (too large, too small or not a power of 2). 361de4996e2Sdan# 362e08341c6Sdan# pager1.4.4.*: Test hot-journal rollback of journal file with a master 363e08341c6Sdan# journal pointer generated in various "PRAGMA synchronous" 364e08341c6Sdan# modes. 365e08341c6Sdan# 366e08341c6Sdan# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a 367e08341c6Sdan# journal-record for which the checksum fails. 368e08341c6Sdan# 369ec6ffc1aSdan# pager1.4.6.*: Test that when rolling back a hot-journal that contains a 370ec6ffc1aSdan# master journal pointer, the master journal file is deleted 371ec6ffc1aSdan# after all the hot-journals that refer to it are deleted. 372ec6ffc1aSdan# 373c8ce3972Sdan# pager1.4.7.*: Test that if a hot-journal file exists but a client can 374c8ce3972Sdan# open it for reading only, the database cannot be accessed and 375c8ce3972Sdan# SQLITE_CANTOPEN is returned. 376c8ce3972Sdan# 37753f04f3bSdando_test pager1.4.1.1 { 37853f04f3bSdan faultsim_delete_and_reopen 37953f04f3bSdan execsql { 38053f04f3bSdan CREATE TABLE x(y, z); 38153f04f3bSdan INSERT INTO x VALUES(1, 2); 38253f04f3bSdan } 38353f04f3bSdan set fd [open test.db-journal w] 38453f04f3bSdan puts -nonewline $fd "helloworld" 38553f04f3bSdan close $fd 38653f04f3bSdan file exists test.db-journal 38753f04f3bSdan} {1} 38853f04f3bSdando_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2} 38953f04f3bSdando_test pager1.4.1.3 { file exists test.db-journal } {0} 39053f04f3bSdan 39153f04f3bSdan# Set up a [testvfs] to snapshot the file-system just before SQLite 39253f04f3bSdan# deletes the master-journal to commit a multi-file transaction. 39353f04f3bSdan# 39453f04f3bSdan# In subsequent test cases, invoking [faultsim_restore_and_reopen] sets 39553f04f3bSdan# up the file system to contain two databases, two hot-journal files and 39653f04f3bSdan# a master-journal. 39753f04f3bSdan# 39853f04f3bSdando_test pager1.4.2.1 { 39953f04f3bSdan testvfs tstvfs -default 1 40053f04f3bSdan tstvfs filter xDelete 40153f04f3bSdan tstvfs script xDeleteCallback 40253f04f3bSdan proc xDeleteCallback {method file args} { 40353f04f3bSdan set file [file tail $file] 40453f04f3bSdan if { [string match *mj* $file] } { faultsim_save } 40553f04f3bSdan } 40653f04f3bSdan faultsim_delete_and_reopen 40753f04f3bSdan db func a_string a_string 40853f04f3bSdan execsql { 40953f04f3bSdan ATTACH 'test.db2' AS aux; 41053f04f3bSdan PRAGMA journal_mode = DELETE; 41153f04f3bSdan PRAGMA main.cache_size = 10; 41253f04f3bSdan PRAGMA aux.cache_size = 10; 41353f04f3bSdan CREATE TABLE t1(a UNIQUE, b UNIQUE); 41453f04f3bSdan CREATE TABLE aux.t2(a UNIQUE, b UNIQUE); 41553f04f3bSdan INSERT INTO t1 VALUES(a_string(200), a_string(300)); 41653f04f3bSdan INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 41753f04f3bSdan INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 41853f04f3bSdan INSERT INTO t2 SELECT * FROM t1; 41953f04f3bSdan BEGIN; 42053f04f3bSdan INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; 42153f04f3bSdan INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; 42253f04f3bSdan INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; 42353f04f3bSdan INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; 42453f04f3bSdan REPLACE INTO t2 SELECT * FROM t1; 42553f04f3bSdan COMMIT; 42653f04f3bSdan } 42753f04f3bSdan db close 42853f04f3bSdan tstvfs delete 42953f04f3bSdan} {} 43053f04f3bSdando_test pager1.4.2.2 { 43153f04f3bSdan faultsim_restore_and_reopen 43253f04f3bSdan execsql { 43353f04f3bSdan SELECT count(*) FROM t1; 43453f04f3bSdan PRAGMA integrity_check; 43553f04f3bSdan } 43653f04f3bSdan} {4 ok} 43753f04f3bSdando_test pager1.4.2.3 { 43853f04f3bSdan faultsim_restore_and_reopen 43953f04f3bSdan foreach f [glob test.db-mj*] { file delete -force $f } 44053f04f3bSdan execsql { 44153f04f3bSdan SELECT count(*) FROM t1; 44253f04f3bSdan PRAGMA integrity_check; 44353f04f3bSdan } 44453f04f3bSdan} {64 ok} 44553f04f3bSdando_test pager1.4.2.4 { 44653f04f3bSdan faultsim_restore_and_reopen 44753f04f3bSdan hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 44853f04f3bSdan execsql { 44953f04f3bSdan SELECT count(*) FROM t1; 45053f04f3bSdan PRAGMA integrity_check; 45153f04f3bSdan } 45253f04f3bSdan} {4 ok} 45353f04f3bSdando_test pager1.4.2.5 { 45453f04f3bSdan faultsim_restore_and_reopen 45553f04f3bSdan hexio_write test.db-journal [expr [file size test.db-journal]-20] 123456 45653f04f3bSdan foreach f [glob test.db-mj*] { file delete -force $f } 45753f04f3bSdan execsql { 45853f04f3bSdan SELECT count(*) FROM t1; 45953f04f3bSdan PRAGMA integrity_check; 46053f04f3bSdan } 46153f04f3bSdan} {4 ok} 46253f04f3bSdan 463de4996e2Sdando_test pager1.4.3.1 { 464de4996e2Sdan testvfs tstvfs -default 1 465de4996e2Sdan tstvfs filter xSync 466de4996e2Sdan tstvfs script xSyncCallback 467de4996e2Sdan proc xSyncCallback {method file args} { 468de4996e2Sdan set file [file tail $file] 469de4996e2Sdan if { 0==[string match *journal $file] } { faultsim_save } 470de4996e2Sdan } 471de4996e2Sdan faultsim_delete_and_reopen 472de4996e2Sdan execsql { 473de4996e2Sdan PRAGMA journal_mode = DELETE; 474de4996e2Sdan CREATE TABLE t1(a, b); 475de4996e2Sdan INSERT INTO t1 VALUES(1, 2); 476de4996e2Sdan INSERT INTO t1 VALUES(3, 4); 477de4996e2Sdan } 478de4996e2Sdan db close 479de4996e2Sdan tstvfs delete 480de4996e2Sdan} {} 481de4996e2Sdan 482de4996e2Sdanforeach {tn ofst value result} { 483de4996e2Sdan 2 20 31 {1 2 3 4} 484de4996e2Sdan 3 20 32 {1 2 3 4} 485de4996e2Sdan 4 20 33 {1 2 3 4} 486de4996e2Sdan 5 20 65536 {1 2 3 4} 487de4996e2Sdan 6 20 131072 {1 2 3 4} 488de4996e2Sdan 489de4996e2Sdan 7 24 511 {1 2 3 4} 490de4996e2Sdan 8 24 513 {1 2 3 4} 491de4996e2Sdan 9 24 65536 {1 2 3 4} 492de4996e2Sdan 493de4996e2Sdan 10 32 65536 {1 2} 494de4996e2Sdan} { 495de4996e2Sdan do_test pager1.4.3.$tn { 496de4996e2Sdan faultsim_restore_and_reopen 497de4996e2Sdan hexio_write test.db-journal $ofst [format %.8x $value] 498de4996e2Sdan execsql { SELECT * FROM t1 } 499de4996e2Sdan } $result 500de4996e2Sdan} 501de4996e2Sdandb close 502de4996e2Sdan 503e08341c6Sdan# Set up a VFS that snapshots the file-system just before a master journal 504e08341c6Sdan# file is deleted to commit a multi-file transaction. Specifically, the 505e08341c6Sdan# file-system is saved just before the xDelete() call to remove the 506e08341c6Sdan# master journal file from the file-system. 507e08341c6Sdan# 508e08341c6Sdantestvfs tv -default 1 509e08341c6Sdantv script copy_on_mj_delete 510e08341c6Sdanset ::mj_filename_length 0 511e08341c6Sdanproc copy_on_mj_delete {method filename args} { 512e08341c6Sdan if {[string match *mj* [file tail $filename]]} { 513e08341c6Sdan set ::mj_filename_length [string length $filename] 514e08341c6Sdan faultsim_save 515e08341c6Sdan } 516e08341c6Sdan return SQLITE_OK 517e08341c6Sdan} 518e08341c6Sdan 519e08341c6Sdanset pwd [pwd] 520e08341c6Sdanforeach {tn1 tcl} { 521e08341c6Sdan 1 { set prefix "test.db" } 522e08341c6Sdan 2 { 523e08341c6Sdan # This test depends on the underlying VFS being able to open paths 524e08341c6Sdan # 512 bytes in length. The idea is to create a hot-journal file that 525e08341c6Sdan # contains a master-journal pointer so large that it could contain 526e08341c6Sdan # a valid page record (if the file page-size is 512 bytes). So as to 527e08341c6Sdan # make sure SQLite doesn't get confused by this. 528e08341c6Sdan # 529e08341c6Sdan set nPadding [expr 511 - $::mj_filename_length] 530e08341c6Sdan 531e08341c6Sdan # We cannot just create a really long database file name to open, as 532e08341c6Sdan # Linux limits a single component of a path to 255 bytes by default 533e08341c6Sdan # (and presumably other systems have limits too). So create a directory 534e08341c6Sdan # hierarchy to work in. 535e08341c6Sdan # 536e08341c6Sdan set dirname "d123456789012345678901234567890/" 537e08341c6Sdan set nDir [expr $nPadding / 32] 538e08341c6Sdan if { $nDir } { 539e08341c6Sdan set p [string repeat $dirname $nDir] 540e08341c6Sdan file mkdir $p 541e08341c6Sdan cd $p 542e08341c6Sdan } 543e08341c6Sdan 544e08341c6Sdan set padding [string repeat x [expr $nPadding %32]] 545e08341c6Sdan set prefix "test.db${padding}" 546e08341c6Sdan } 547e08341c6Sdan} { 548e08341c6Sdan eval $tcl 549e08341c6Sdan foreach {tn2 sql} { 550e08341c6Sdan o { 551e08341c6Sdan PRAGMA main.synchronous=OFF; 552e08341c6Sdan PRAGMA aux.synchronous=OFF; 553e08341c6Sdan } 554e08341c6Sdan o512 { 555e08341c6Sdan PRAGMA main.synchronous=OFF; 556e08341c6Sdan PRAGMA aux.synchronous=OFF; 557e08341c6Sdan PRAGMA main.page_size = 512; 558e08341c6Sdan PRAGMA aux.page_size = 512; 559e08341c6Sdan } 560e08341c6Sdan n { 561e08341c6Sdan PRAGMA main.synchronous=NORMAL; 562e08341c6Sdan PRAGMA aux.synchronous=NORMAL; 563e08341c6Sdan } 564e08341c6Sdan f { 565e08341c6Sdan PRAGMA main.synchronous=FULL; 566e08341c6Sdan PRAGMA aux.synchronous=FULL; 567e08341c6Sdan } 568e08341c6Sdan } { 569e08341c6Sdan 570e08341c6Sdan set tn "${tn1}.${tn2}" 571e08341c6Sdan 572e08341c6Sdan # Set up a connection to have two databases, test.db (main) and 573e08341c6Sdan # test.db2 (aux). Then run a multi-file transaction on them. The 574e08341c6Sdan # VFS will snapshot the file-system just before the master-journal 575e08341c6Sdan # file is deleted to commit the transaction. 576e08341c6Sdan # 577e08341c6Sdan tv filter xDelete 578e08341c6Sdan do_test pager1-4.4.$tn.1 { 579e08341c6Sdan faultsim_delete_and_reopen $prefix 580e08341c6Sdan execsql " 581e08341c6Sdan ATTACH '${prefix}2' AS aux; 582e08341c6Sdan $sql 583e08341c6Sdan CREATE TABLE a(x); 584e08341c6Sdan CREATE TABLE aux.b(x); 585e08341c6Sdan INSERT INTO a VALUES('double-you'); 586e08341c6Sdan INSERT INTO a VALUES('why'); 587e08341c6Sdan INSERT INTO a VALUES('zed'); 588e08341c6Sdan INSERT INTO b VALUES('won'); 589e08341c6Sdan INSERT INTO b VALUES('too'); 590e08341c6Sdan INSERT INTO b VALUES('free'); 591e08341c6Sdan " 592e08341c6Sdan execsql { 593e08341c6Sdan BEGIN; 594e08341c6Sdan INSERT INTO a SELECT * FROM b WHERE rowid<=3; 595e08341c6Sdan INSERT INTO b SELECT * FROM a WHERE rowid<=3; 596e08341c6Sdan COMMIT; 597e08341c6Sdan } 598e08341c6Sdan } {} 599e08341c6Sdan tv filter {} 600e08341c6Sdan 601e08341c6Sdan # Check that the transaction was committed successfully. 602e08341c6Sdan # 603e08341c6Sdan do_execsql_test pager1-4.4.$tn.2 { 604e08341c6Sdan SELECT * FROM a 605e08341c6Sdan } {double-you why zed won too free} 606e08341c6Sdan do_execsql_test pager1-4.4.$tn.3 { 607e08341c6Sdan SELECT * FROM b 608e08341c6Sdan } {won too free double-you why zed} 609e08341c6Sdan 610e08341c6Sdan # Restore the file-system and reopen the databases. Check that it now 611e08341c6Sdan # appears that the transaction was not committed (because the file-system 612e08341c6Sdan # was restored to the state where it had not been). 613e08341c6Sdan # 614e08341c6Sdan do_test pager1-4.4.$tn.4 { 615e08341c6Sdan faultsim_restore_and_reopen $prefix 616e08341c6Sdan execsql "ATTACH '${prefix}2' AS aux" 617e08341c6Sdan } {} 618e08341c6Sdan do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed} 619e08341c6Sdan do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free} 620e08341c6Sdan 621e08341c6Sdan # Restore the file-system again. This time, before reopening the databases, 622e08341c6Sdan # delete the master-journal file from the file-system. It now appears that 623e08341c6Sdan # the transaction was committed (no master-journal file == no rollback). 624e08341c6Sdan # 625e08341c6Sdan do_test pager1-4.4.$tn.7 { 626e08341c6Sdan faultsim_restore_and_reopen $prefix 627e08341c6Sdan foreach f [glob ${prefix}-mj*] { file delete -force $f } 628e08341c6Sdan execsql "ATTACH '${prefix}2' AS aux" 629e08341c6Sdan } {} 630e08341c6Sdan do_execsql_test pager1-4.4.$tn.8 { 631e08341c6Sdan SELECT * FROM a 632e08341c6Sdan } {double-you why zed won too free} 633e08341c6Sdan do_execsql_test pager1-4.4.$tn.9 { 634e08341c6Sdan SELECT * FROM b 635e08341c6Sdan } {won too free double-you why zed} 636e08341c6Sdan } 637e08341c6Sdan 638e08341c6Sdan cd $pwd 639e08341c6Sdan} 640e08341c6Sdandb close 641e08341c6Sdantv delete 6420e986f51Sdanfile delete -force $dirname 6430e986f51Sdan 6440e986f51Sdan 6450e986f51Sdan# Set up a VFS to make a copy of the file-system just before deleting a 6460e986f51Sdan# journal file to commit a transaction. The transaction modifies exactly 6470e986f51Sdan# two database pages (and page 1 - the change counter). 6480e986f51Sdan# 6490e986f51Sdantestvfs tv -default 1 6500e986f51Sdantv sectorsize 512 6510e986f51Sdantv script copy_on_journal_delete 6520e986f51Sdantv filter xDelete 6530e986f51Sdanproc copy_on_journal_delete {method filename args} { 6540e986f51Sdan if {[string match *journal $filename]} faultsim_save 6550e986f51Sdan return SQLITE_OK 6560e986f51Sdan} 6570e986f51Sdanfaultsim_delete_and_reopen 6580e986f51Sdando_execsql_test pager1.4.5.1 { 6590e986f51Sdan PRAGMA page_size = 1024; 6600e986f51Sdan CREATE TABLE t1(a, b); 6610e986f51Sdan CREATE TABLE t2(a, b); 6620e986f51Sdan INSERT INTO t1 VALUES('I', 'II'); 6630e986f51Sdan INSERT INTO t2 VALUES('III', 'IV'); 6640e986f51Sdan BEGIN; 6650e986f51Sdan INSERT INTO t1 VALUES(1, 2); 6660e986f51Sdan INSERT INTO t2 VALUES(3, 4); 6670e986f51Sdan COMMIT; 6680e986f51Sdan} {} 6690e986f51Sdantv filter {} 6700e986f51Sdan 6710e986f51Sdan# Check the transaction was committed: 6720e986f51Sdan# 6730e986f51Sdando_execsql_test pager1.4.5.2 { 6740e986f51Sdan SELECT * FROM t1; 6750e986f51Sdan SELECT * FROM t2; 6760e986f51Sdan} {I II 1 2 III IV 3 4} 6770e986f51Sdan 678ec6ffc1aSdan# Now try four tests: 6790e986f51Sdan# 6800e986f51Sdan# pager1-4.5.3: Restore the file-system. Check that the whole transaction 6810e986f51Sdan# is rolled back. 6820e986f51Sdan# 6830e986f51Sdan# pager1-4.5.4: Restore the file-system. Corrupt the first record in the 6840e986f51Sdan# journal. Check the transaction is not rolled back. 6850e986f51Sdan# 6860e986f51Sdan# pager1-4.5.5: Restore the file-system. Corrupt the second record in the 6870e986f51Sdan# journal. Check that the first record in the transaction is 6880e986f51Sdan# played back, but not the second. 6890e986f51Sdan# 69010f5a50eSdan# pager1-4.5.6: Restore the file-system. Try to open the database with a 69110f5a50eSdan# readonly connection. This should fail, as a read-only 69210f5a50eSdan# connection cannot roll back the database file. 69310f5a50eSdan# 6940e986f51Sdanfaultsim_restore_and_reopen 6950e986f51Sdando_execsql_test pager1.4.5.3 { 6960e986f51Sdan SELECT * FROM t1; 6970e986f51Sdan SELECT * FROM t2; 6980e986f51Sdan} {I II III IV} 6990e986f51Sdanfaultsim_restore_and_reopen 7000e986f51Sdanhexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF 7010e986f51Sdando_execsql_test pager1.4.5.4 { 7020e986f51Sdan SELECT * FROM t1; 7030e986f51Sdan SELECT * FROM t2; 7040e986f51Sdan} {I II 1 2 III IV 3 4} 7050e986f51Sdanfaultsim_restore_and_reopen 7060e986f51Sdanhexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF 7070e986f51Sdando_execsql_test pager1.4.5.5 { 7080e986f51Sdan SELECT * FROM t1; 7090e986f51Sdan SELECT * FROM t2; 7100e986f51Sdan} {I II III IV 3 4} 7110e986f51Sdan 71210f5a50eSdanfaultsim_restore_and_reopen 71310f5a50eSdandb close 71410f5a50eSdansqlite3 db test.db -readonly 1 71510f5a50eSdando_catchsql_test pager1.4.5.6 { 71610f5a50eSdan SELECT * FROM t1; 71710f5a50eSdan SELECT * FROM t2; 71810f5a50eSdan} {1 {disk I/O error}} 719ec6ffc1aSdandb close 720ec6ffc1aSdan 721ec6ffc1aSdan# Snapshot the file-system just before multi-file commit. Save the name 722ec6ffc1aSdan# of the master journal file in $::mj_filename. 723ec6ffc1aSdan# 724ec6ffc1aSdantv script copy_on_mj_delete 725ec6ffc1aSdantv filter xDelete 726ec6ffc1aSdanproc copy_on_mj_delete {method filename args} { 727ec6ffc1aSdan if {[string match *mj* [file tail $filename]]} { 728ec6ffc1aSdan set ::mj_filename $filename 729ec6ffc1aSdan faultsim_save 730ec6ffc1aSdan } 731ec6ffc1aSdan return SQLITE_OK 732ec6ffc1aSdan} 733ec6ffc1aSdando_test pager1.4.6.1 { 734ec6ffc1aSdan faultsim_delete_and_reopen 735ec6ffc1aSdan execsql { 736ec6ffc1aSdan ATTACH 'test.db2' AS two; 737ec6ffc1aSdan CREATE TABLE t1(a, b); 738ec6ffc1aSdan CREATE TABLE two.t2(a, b); 739ec6ffc1aSdan INSERT INTO t1 VALUES(1, 't1.1'); 740ec6ffc1aSdan INSERT INTO t2 VALUES(1, 't2.1'); 741ec6ffc1aSdan BEGIN; 742ec6ffc1aSdan UPDATE t1 SET b = 't1.2'; 743ec6ffc1aSdan UPDATE t2 SET b = 't2.2'; 744ec6ffc1aSdan COMMIT; 745ec6ffc1aSdan } 746ec6ffc1aSdan tv filter {} 747ec6ffc1aSdan db close 748ec6ffc1aSdan} {} 749ec6ffc1aSdan 750ec6ffc1aSdanfaultsim_restore_and_reopen 751ec6ffc1aSdando_execsql_test pager1.4.6.2 { SELECT * FROM t1 } {1 t1.1} 752ec6ffc1aSdando_test pager1.4.6.3 { file exists $::mj_filename } {1} 753ec6ffc1aSdando_execsql_test pager1.4.6.4 { 754ec6ffc1aSdan ATTACH 'test.db2' AS two; 755ec6ffc1aSdan SELECT * FROM t2; 756ec6ffc1aSdan} {1 t2.1} 757ec6ffc1aSdando_test pager1.4.6.5 { file exists $::mj_filename } {0} 758ec6ffc1aSdan 759ec6ffc1aSdanfaultsim_restore_and_reopen 760ec6ffc1aSdandb close 761ec6ffc1aSdando_test pager1.4.6.8 { 762ec6ffc1aSdan set ::mj_filename1 $::mj_filename 763ec6ffc1aSdan tv filter xDelete 764ec6ffc1aSdan sqlite3 db test.db2 765ec6ffc1aSdan execsql { 766ec6ffc1aSdan ATTACH 'test.db3' AS three; 767ec6ffc1aSdan CREATE TABLE three.t3(a, b); 768ec6ffc1aSdan INSERT INTO t3 VALUES(1, 't3.1'); 769ec6ffc1aSdan BEGIN; 770ec6ffc1aSdan UPDATE t2 SET b = 't2.3'; 771ec6ffc1aSdan UPDATE t3 SET b = 't3.3'; 772ec6ffc1aSdan COMMIT; 773ec6ffc1aSdan } 774ec6ffc1aSdan expr {$::mj_filename1 != $::mj_filename} 775ec6ffc1aSdan} {1} 776ec6ffc1aSdanfaultsim_restore_and_reopen 777ec6ffc1aSdantv filter {} 778ec6ffc1aSdan 779ec6ffc1aSdan# The file-system now contains: 780ec6ffc1aSdan# 781ec6ffc1aSdan# * three databases 782ec6ffc1aSdan# * three hot-journal files 783ec6ffc1aSdan# * two master-journal files. 784ec6ffc1aSdan# 785ec6ffc1aSdan# The hot-journals associated with test.db2 and test.db3 point to 786ec6ffc1aSdan# master journal $::mj_filename. The hot-journal file associated with 787ec6ffc1aSdan# test.db points to master journal $::mj_filename1. So reading from 788ec6ffc1aSdan# test.db should delete $::mj_filename1. 789ec6ffc1aSdan# 790ec6ffc1aSdando_test pager1.4.6.9 { 791ec6ffc1aSdan lsort [glob test.db*] 792ec6ffc1aSdan} [lsort [list \ 793ec6ffc1aSdan test.db test.db2 test.db3 \ 794ec6ffc1aSdan test.db-journal test.db2-journal test.db3-journal \ 795ec6ffc1aSdan [file tail $::mj_filename] [file tail $::mj_filename1] 796ec6ffc1aSdan]] 797ec6ffc1aSdan 798ec6ffc1aSdan# The master-journal $::mj_filename1 contains pointers to test.db and 799ec6ffc1aSdan# test.db2. However the hot-journal associated with test.db2 points to 800ec6ffc1aSdan# a different master-journal. Therefore, reading from test.db only should 801ec6ffc1aSdan# be enough to cause SQLite to delete $::mj_filename1. 802ec6ffc1aSdan# 803ec6ffc1aSdando_test pager1.4.6.10 { file exists $::mj_filename } {1} 804ec6ffc1aSdando_test pager1.4.6.11 { file exists $::mj_filename1 } {1} 805ec6ffc1aSdando_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1} 806ec6ffc1aSdando_test pager1.4.6.13 { file exists $::mj_filename } {1} 807ec6ffc1aSdando_test pager1.4.6.14 { file exists $::mj_filename1 } {0} 808ec6ffc1aSdan 809ec6ffc1aSdando_execsql_test pager1.4.6.12 { 810ec6ffc1aSdan ATTACH 'test.db2' AS two; 811ec6ffc1aSdan SELECT * FROM t2; 812ec6ffc1aSdan} {1 t2.1} 813ec6ffc1aSdando_test pager1.4.6.13 { file exists $::mj_filename } {1} 814ec6ffc1aSdando_execsql_test pager1.4.6.14 { 815ec6ffc1aSdan ATTACH 'test.db3' AS three; 816ec6ffc1aSdan SELECT * FROM t3; 817ec6ffc1aSdan} {1 t3.1} 818ec6ffc1aSdando_test pager1.4.6.15 { file exists $::mj_filename } {0} 81910f5a50eSdan 8200e986f51Sdandb close 8210e986f51Sdantv delete 822e08341c6Sdan 823c8ce3972Sdantestvfs tv -default 1 824c8ce3972Sdantv sectorsize 512 825c8ce3972Sdantv script copy_on_journal_delete 826c8ce3972Sdantv filter xDelete 827c8ce3972Sdanproc copy_on_journal_delete {method filename args} { 828c8ce3972Sdan if {[string match *journal $filename]} faultsim_save 829c8ce3972Sdan return SQLITE_OK 830c8ce3972Sdan} 831c8ce3972Sdanfaultsim_delete_and_reopen 832c8ce3972Sdando_execsql_test pager1.4.7.1 { 833c8ce3972Sdan CREATE TABLE t1(x PRIMARY KEY, y); 834c8ce3972Sdan CREATE INDEX i1 ON t1(y); 835c8ce3972Sdan INSERT INTO t1 VALUES('I', 'one'); 836c8ce3972Sdan INSERT INTO t1 VALUES('II', 'four'); 837c8ce3972Sdan INSERT INTO t1 VALUES('III', 'nine'); 838c8ce3972Sdan BEGIN; 839c8ce3972Sdan INSERT INTO t1 VALUES('IV', 'sixteen'); 840c8ce3972Sdan INSERT INTO t1 VALUES('V' , 'twentyfive'); 841c8ce3972Sdan COMMIT; 842c8ce3972Sdan} {} 843c8ce3972Sdantv filter {} 844c8ce3972Sdandb close 845c8ce3972Sdantv delete 846c8ce3972Sdando_test pager1.4.7.2 { 847c8ce3972Sdan faultsim_restore_and_reopen 848c8ce3972Sdan catch {file attributes test.db-journal -permissions r--------} 849c8ce3972Sdan catch {file attributes test.db-journal -readonly 1} 850c8ce3972Sdan catchsql { SELECT * FROM t1 } 851c8ce3972Sdan} {1 {unable to open database file}} 852c8ce3972Sdando_test pager1.4.7.3 { 853c8ce3972Sdan db close 854c8ce3972Sdan catch {file attributes test.db-journal -permissions rw-rw-rw-} 855c8ce3972Sdan catch {file attributes test.db-journal -readonly 0} 856c8ce3972Sdan file delete test.db-journal 857c8ce3972Sdan file exists test.db-journal 858c8ce3972Sdan} {0} 859c8ce3972Sdan 860de4996e2Sdan#------------------------------------------------------------------------- 861146ed78bSdan# The following tests deal with multi-file commits. 862de4996e2Sdan# 863146ed78bSdan# pager1-5.1.*: The case where a multi-file cannot be committed because 864146ed78bSdan# another connection is holding a SHARED lock on one of the 865146ed78bSdan# files. After the SHARED lock is removed, the COMMIT succeeds. 866146ed78bSdan# 867146ed78bSdan# pager1-5.2.*: Multi-file commits with journal_mode=memory. 868146ed78bSdan# 869146ed78bSdan# pager1-5.3.*: Multi-file commits with journal_mode=memory. 870146ed78bSdan# 871146ed78bSdan# pager1-5.4.*: Check that with synchronous=normal, the master-journal file 872146ed78bSdan# name is added to a journal file immediately after the last 873146ed78bSdan# journal record. But with synchronous=full, extra unused space 874146ed78bSdan# is allocated between the last journal record and the 875146ed78bSdan# master-journal file name so that the master-journal file 876146ed78bSdan# name does not lie on the same sector as the last journal file 877146ed78bSdan# record. 878146ed78bSdan# 879e08341c6Sdan# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is 880e08341c6Sdan# truncated to zero bytes when a multi-file transaction is 881e08341c6Sdan# committed (instead of the first couple of bytes being zeroed). 882e08341c6Sdan# 883146ed78bSdan# 884146ed78bSdando_test pager1-5.1.1 { 885146ed78bSdan faultsim_delete_and_reopen 886146ed78bSdan execsql { 887146ed78bSdan ATTACH 'test.db2' AS aux; 888146ed78bSdan CREATE TABLE t1(a, b); 889146ed78bSdan CREATE TABLE aux.t2(a, b); 890146ed78bSdan INSERT INTO t1 VALUES(17, 'Lenin'); 891146ed78bSdan INSERT INTO t1 VALUES(22, 'Stalin'); 892146ed78bSdan INSERT INTO t1 VALUES(53, 'Khrushchev'); 893146ed78bSdan } 894146ed78bSdan} {} 895146ed78bSdando_test pager1-5.1.2 { 896146ed78bSdan execsql { 897146ed78bSdan BEGIN; 898146ed78bSdan INSERT INTO t1 VALUES(64, 'Brezhnev'); 899146ed78bSdan INSERT INTO t2 SELECT * FROM t1; 900146ed78bSdan } 901146ed78bSdan sqlite3 db2 test.db2 902146ed78bSdan execsql { 903146ed78bSdan BEGIN; 904146ed78bSdan SELECT * FROM t2; 905146ed78bSdan } db2 906146ed78bSdan} {} 907146ed78bSdando_test pager1-5.1.3 { 908146ed78bSdan catchsql COMMIT 909146ed78bSdan} {1 {database is locked}} 910146ed78bSdando_test pager1-5.1.4 { 911146ed78bSdan execsql COMMIT db2 912146ed78bSdan execsql COMMIT 913146ed78bSdan execsql { SELECT * FROM t2 } db2 914146ed78bSdan} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev} 915146ed78bSdando_test pager1-5.1.5 { 916146ed78bSdan db2 close 917146ed78bSdan} {} 918146ed78bSdan 919146ed78bSdando_test pager1-5.2.1 { 920146ed78bSdan execsql { 921146ed78bSdan PRAGMA journal_mode = memory; 922146ed78bSdan BEGIN; 923146ed78bSdan INSERT INTO t1 VALUES(84, 'Andropov'); 924146ed78bSdan INSERT INTO t2 VALUES(84, 'Andropov'); 925146ed78bSdan COMMIT; 926146ed78bSdan } 927146ed78bSdan} {memory} 928146ed78bSdando_test pager1-5.3.1 { 929146ed78bSdan execsql { 930146ed78bSdan PRAGMA journal_mode = off; 931146ed78bSdan BEGIN; 932146ed78bSdan INSERT INTO t1 VALUES(85, 'Gorbachev'); 933146ed78bSdan INSERT INTO t2 VALUES(85, 'Gorbachev'); 934146ed78bSdan COMMIT; 935146ed78bSdan } 936146ed78bSdan} {off} 937146ed78bSdan 938146ed78bSdando_test pager1-5.4.1 { 939146ed78bSdan db close 940146ed78bSdan testvfs tv 941146ed78bSdan sqlite3 db test.db -vfs tv 942146ed78bSdan execsql { ATTACH 'test.db2' AS aux } 943146ed78bSdan 944146ed78bSdan tv filter xDelete 945146ed78bSdan tv script max_journal_size 946146ed78bSdan tv sectorsize 512 947146ed78bSdan set ::max_journal 0 948146ed78bSdan proc max_journal_size {method args} { 949146ed78bSdan set sz 0 950146ed78bSdan catch { set sz [file size test.db-journal] } 951146ed78bSdan if {$sz > $::max_journal} { 952146ed78bSdan set ::max_journal $sz 953146ed78bSdan } 954146ed78bSdan return SQLITE_OK 955146ed78bSdan } 956146ed78bSdan execsql { 957146ed78bSdan PRAGMA journal_mode = DELETE; 958146ed78bSdan PRAGMA synchronous = NORMAL; 959146ed78bSdan BEGIN; 960146ed78bSdan INSERT INTO t1 VALUES(85, 'Gorbachev'); 961146ed78bSdan INSERT INTO t2 VALUES(85, 'Gorbachev'); 962146ed78bSdan COMMIT; 963146ed78bSdan } 964146ed78bSdan set ::max_journal 965146ed78bSdan} [expr 2615+[string length [pwd]]] 966146ed78bSdando_test pager1-5.4.2 { 967146ed78bSdan set ::max_journal 0 968146ed78bSdan execsql { 969146ed78bSdan PRAGMA synchronous = full; 970146ed78bSdan BEGIN; 971146ed78bSdan DELETE FROM t1 WHERE b = 'Lenin'; 972146ed78bSdan DELETE FROM t2 WHERE b = 'Lenin'; 973146ed78bSdan COMMIT; 974146ed78bSdan } 975146ed78bSdan set ::max_journal 976146ed78bSdan} [expr 3111+[string length [pwd]]] 977146ed78bSdandb close 978146ed78bSdantv delete 979146ed78bSdan 980146ed78bSdando_test pager1-5.5.1 { 981146ed78bSdan sqlite3 db test.db 982146ed78bSdan execsql { 983146ed78bSdan ATTACH 'test.db2' AS aux; 984146ed78bSdan PRAGMA journal_mode = PERSIST; 985146ed78bSdan CREATE TABLE t3(a, b); 986146ed78bSdan INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1; 987146ed78bSdan UPDATE t3 SET b = randomblob(1500); 988146ed78bSdan } 989146ed78bSdan expr [file size test.db-journal] > 15000 990146ed78bSdan} {1} 991146ed78bSdando_test pager1-5.5.2 { 992146ed78bSdan execsql { 993146ed78bSdan PRAGMA synchronous = full; 994146ed78bSdan BEGIN; 995146ed78bSdan DELETE FROM t1 WHERE b = 'Stalin'; 996146ed78bSdan DELETE FROM t2 WHERE b = 'Stalin'; 997146ed78bSdan COMMIT; 998146ed78bSdan } 999146ed78bSdan file size test.db-journal 1000146ed78bSdan} {0} 1001146ed78bSdan 1002146ed78bSdan 1003146ed78bSdan#------------------------------------------------------------------------- 1004146ed78bSdan# The following tests work with "PRAGMA max_page_count" 1005146ed78bSdan# 1006146ed78bSdando_test pager1-6.1 { 1007146ed78bSdan faultsim_delete_and_reopen 1008146ed78bSdan execsql { 1009146ed78bSdan PRAGMA max_page_count = 10; 1010146ed78bSdan CREATE TABLE t2(a, b); 1011146ed78bSdan CREATE TABLE t3(a, b); 1012146ed78bSdan CREATE TABLE t4(a, b); 1013146ed78bSdan CREATE TABLE t5(a, b); 1014146ed78bSdan CREATE TABLE t6(a, b); 1015146ed78bSdan CREATE TABLE t7(a, b); 1016146ed78bSdan CREATE TABLE t8(a, b); 1017146ed78bSdan CREATE TABLE t9(a, b); 1018146ed78bSdan CREATE TABLE t10(a, b); 1019146ed78bSdan } 1020146ed78bSdan} {10} 1021d353331aSdando_catchsql_test pager1-6.2 { 1022d353331aSdan CREATE TABLE t11(a, b) 1023146ed78bSdan} {1 {database or disk is full}} 1024d353331aSdando_execsql_test pager1-6.4 { PRAGMA max_page_count } {10} 1025d353331aSdando_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15} 1026d353331aSdando_execsql_test pager1-6.6 { CREATE TABLE t11(a, b) } {} 1027d353331aSdando_execsql_test pager1-6.7 { 1028d353331aSdan BEGIN; 1029d353331aSdan INSERT INTO t11 VALUES(1, 2); 1030d353331aSdan PRAGMA max_page_count = 13; 1031d353331aSdan} {13} 1032d353331aSdando_execsql_test pager1-6.8 { 1033d353331aSdan INSERT INTO t11 VALUES(3, 4); 1034d353331aSdan PRAGMA max_page_count = 10; 1035d353331aSdan} {11} 1036d353331aSdando_execsql_test pager1-6.9 { COMMIT } {} 1037de4996e2Sdan 1038153eda0aSdan 1039153eda0aSdan#------------------------------------------------------------------------- 1040153eda0aSdan# The following tests work with "PRAGMA journal_mode=TRUNCATE" and 1041153eda0aSdan# "PRAGMA locking_mode=EXCLUSIVE". 1042153eda0aSdan# 1043153eda0aSdan# Each test is specified with 5 variables. As follows: 1044153eda0aSdan# 1045153eda0aSdan# $tn: Test Number. Used as part of the [do_test] test names. 1046153eda0aSdan# $sql: SQL to execute. 1047153eda0aSdan# $res: Expected result of executing $sql. 1048153eda0aSdan# $js: The expected size of the journal file, in bytes, after executing 1049153eda0aSdan# the SQL script. Or -1 if the journal is not expected to exist. 1050153eda0aSdan# $ws: The expected size of the WAL file, in bytes, after executing 1051153eda0aSdan# the SQL script. Or -1 if the WAL is not expected to exist. 1052153eda0aSdan# 105338e1a279Sdanifcapable wal { 1054153eda0aSdan faultsim_delete_and_reopen 1055153eda0aSdan foreach {tn sql res js ws} [subst { 1056153eda0aSdan 1057153eda0aSdan 1 { 1058153eda0aSdan CREATE TABLE t1(a, b); 1059153eda0aSdan PRAGMA auto_vacuum=OFF; 1060153eda0aSdan PRAGMA synchronous=NORMAL; 1061153eda0aSdan PRAGMA page_size=1024; 1062153eda0aSdan PRAGMA locking_mode=EXCLUSIVE; 1063153eda0aSdan PRAGMA journal_mode=TRUNCATE; 1064153eda0aSdan INSERT INTO t1 VALUES(1, 2); 1065153eda0aSdan } {exclusive truncate} 0 -1 1066153eda0aSdan 1067153eda0aSdan 2 { 1068153eda0aSdan BEGIN IMMEDIATE; 1069153eda0aSdan SELECT * FROM t1; 1070153eda0aSdan COMMIT; 1071153eda0aSdan } {1 2} 0 -1 1072153eda0aSdan 1073153eda0aSdan 3 { 1074153eda0aSdan BEGIN; 1075153eda0aSdan SELECT * FROM t1; 1076153eda0aSdan COMMIT; 1077153eda0aSdan } {1 2} 0 -1 1078153eda0aSdan 1079153eda0aSdan 4 { PRAGMA journal_mode = WAL } wal -1 -1 1080153eda0aSdan 5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024] 1081153eda0aSdan 6 { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024] 1082153eda0aSdan 7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024] 1083153eda0aSdan 1084153eda0aSdan 8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1 1085153eda0aSdan 9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1 1086153eda0aSdan 10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1 1087153eda0aSdan 1088153eda0aSdan }] { 1089153eda0aSdan do_execsql_test pager1-7.1.$tn.1 $sql $res 1090153eda0aSdan catch { set J -1 ; set J [file size test.db-journal] } 1091153eda0aSdan catch { set W -1 ; set W [file size test.db-wal] } 1092153eda0aSdan do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws] 1093153eda0aSdan } 109438e1a279Sdan} 1095153eda0aSdan 1096*89ccf448Sdando_test pager1-7.2.1 { 1097*89ccf448Sdan faultsim_delete_and_reopen 1098*89ccf448Sdan execsql { 1099*89ccf448Sdan PRAGMA locking_mode = EXCLUSIVE; 1100*89ccf448Sdan CREATE TABLE t1(a, b); 1101*89ccf448Sdan BEGIN; 1102*89ccf448Sdan PRAGMA journal_mode = delete; 1103*89ccf448Sdan PRAGMA journal_mode = truncate; 1104*89ccf448Sdan } 1105*89ccf448Sdan} {exclusive delete truncate} 1106*89ccf448Sdando_test pager1-7.2.2 { 1107*89ccf448Sdan execsql { INSERT INTO t1 VALUES(1, 2) } 1108*89ccf448Sdan execsql { PRAGMA journal_mode = persist } 1109*89ccf448Sdan} {truncate} 1110*89ccf448Sdando_test pager1-7.2.3 { 1111*89ccf448Sdan execsql { COMMIT } 1112*89ccf448Sdan execsql { 1113*89ccf448Sdan PRAGMA journal_mode = persist; 1114*89ccf448Sdan PRAGMA journal_size_limit; 1115*89ccf448Sdan } 1116*89ccf448Sdan} {persist -1} 1117*89ccf448Sdan 1118d353331aSdan#------------------------------------------------------------------------- 1119d353331aSdan# The following tests, pager1-8.*, test that the special filenames 1120d353331aSdan# ":memory:" and "" open temporary databases. 1121d353331aSdan# 11220e986f51Sdanforeach {tn filename} { 11230e986f51Sdan 1 :memory: 11240e986f51Sdan 2 "" 11250e986f51Sdan} { 11260e986f51Sdan do_test pager1-8.$tn.1 { 1127153eda0aSdan faultsim_delete_and_reopen 1128153eda0aSdan db close 11290e986f51Sdan sqlite3 db $filename 1130153eda0aSdan execsql { 1131c8ce3972Sdan PRAGMA auto_vacuum = 1; 1132153eda0aSdan CREATE TABLE x1(x); 1133153eda0aSdan INSERT INTO x1 VALUES('Charles'); 1134153eda0aSdan INSERT INTO x1 VALUES('James'); 1135153eda0aSdan INSERT INTO x1 VALUES('Mary'); 1136153eda0aSdan SELECT * FROM x1; 1137153eda0aSdan } 1138153eda0aSdan } {Charles James Mary} 11390e986f51Sdan 11400e986f51Sdan do_test pager1-8.$tn.2 { 11410e986f51Sdan sqlite3 db2 $filename 11420e986f51Sdan catchsql { SELECT * FROM x1 } db2 1143153eda0aSdan } {1 {no such table: x1}} 1144153eda0aSdan 11450e986f51Sdan do_execsql_test pager1-8.$tn.3 { 11460e986f51Sdan BEGIN; 11470e986f51Sdan INSERT INTO x1 VALUES('William'); 11480e986f51Sdan INSERT INTO x1 VALUES('Anne'); 11490e986f51Sdan ROLLBACK; 11500e986f51Sdan } {} 11510e986f51Sdan} 11520e986f51Sdan 1153dca321aeSdan#------------------------------------------------------------------------- 1154dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between 1155dca321aeSdan# the pager and the backup API. Test cases: 1156dca321aeSdan# 1157dca321aeSdan# pager1-9.1.*: Test that a backup completes successfully even if the 1158dca321aeSdan# source db is written to during the backup op. 1159dca321aeSdan# 1160dca321aeSdan# pager1-9.2.*: Test that a backup completes successfully even if the 1161dca321aeSdan# source db is written to and then rolled back during a 1162dca321aeSdan# backup operation. 1163dca321aeSdan# 1164dca321aeSdando_test pager1-9.0.1 { 1165dca321aeSdan faultsim_delete_and_reopen 1166dca321aeSdan db func a_string a_string 1167dca321aeSdan execsql { 1168dca321aeSdan PRAGMA cache_size = 10; 1169dca321aeSdan BEGIN; 1170dca321aeSdan CREATE TABLE ab(a, b, UNIQUE(a, b)); 1171dca321aeSdan INSERT INTO ab VALUES( a_string(200), a_string(300) ); 1172dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1173dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1174dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1175dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1176dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1177dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1178dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1179dca321aeSdan COMMIT; 1180dca321aeSdan } 1181dca321aeSdan} {} 1182dca321aeSdando_test pager1-9.0.2 { 1183dca321aeSdan sqlite3 db2 test.db2 1184dca321aeSdan db2 eval { PRAGMA cache_size = 10 } 1185dca321aeSdan sqlite3_backup B db2 main db main 1186dca321aeSdan list [B step 10000] [B finish] 1187dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1188dca321aeSdando_test pager1-9.0.3 { 1189dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1190dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1191dca321aeSdan 1192dca321aeSdando_test pager1-9.1.1 { 1193dca321aeSdan execsql { UPDATE ab SET a = a_string(201) } 1194dca321aeSdan sqlite3_backup B db2 main db main 1195dca321aeSdan B step 30 1196dca321aeSdan} {SQLITE_OK} 1197dca321aeSdando_test pager1-9.1.2 { 1198dca321aeSdan execsql { UPDATE ab SET b = a_string(301) } 1199dca321aeSdan list [B step 10000] [B finish] 1200dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1201dca321aeSdando_test pager1-9.1.3 { 1202dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1203dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1204dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128} 1205dca321aeSdan 1206dca321aeSdando_test pager1-9.2.1 { 1207dca321aeSdan execsql { UPDATE ab SET a = a_string(202) } 1208dca321aeSdan sqlite3_backup B db2 main db main 1209dca321aeSdan B step 30 1210dca321aeSdan} {SQLITE_OK} 1211dca321aeSdando_test pager1-9.2.2 { 1212dca321aeSdan execsql { 1213dca321aeSdan BEGIN; 1214dca321aeSdan UPDATE ab SET b = a_string(301); 1215dca321aeSdan ROLLBACK; 1216dca321aeSdan } 1217dca321aeSdan list [B step 10000] [B finish] 1218dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1219dca321aeSdando_test pager1-9.2.3 { 1220dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1221dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1222dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128} 1223ec6ffc1aSdandb close 1224ec6ffc1aSdandb2 close 1225ec6ffc1aSdan 1226ec6ffc1aSdan#------------------------------------------------------------------------- 1227ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the 1228ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes. 1229ec6ffc1aSdan# 1230ec6ffc1aSdantestvfs tv -default 1 1231ec6ffc1aSdanforeach sectorsize { 1232ec6ffc1aSdan 32 64 128 256 512 1024 2048 1233ec6ffc1aSdan 4096 8192 16384 32768 65536 131072 262144 1234ec6ffc1aSdan} { 1235ec6ffc1aSdan tv sectorsize $sectorsize 1236ec6ffc1aSdan set eff $sectorsize 1237ec6ffc1aSdan if {$sectorsize < 512} { set eff 512 } 1238ec6ffc1aSdan if {$sectorsize > 65536} { set eff 65536 } 1239ec6ffc1aSdan 1240ec6ffc1aSdan do_test pager1-10.$sectorsize { 1241ec6ffc1aSdan faultsim_delete_and_reopen 1242ec6ffc1aSdan execsql { 1243ec6ffc1aSdan PRAGMA journal_mode = PERSIST; 1244ec6ffc1aSdan PRAGMA page_size = 1024; 1245ec6ffc1aSdan CREATE TABLE t1(a, b); 1246ec6ffc1aSdan } 1247ec6ffc1aSdan file size test.db-journal 1248ec6ffc1aSdan } [expr $sectorsize > 65536 ? 65536 : $sectorsize] 1249ec6ffc1aSdan} 1250ec6ffc1aSdandb close 1251ec6ffc1aSdantv delete 1252ec6ffc1aSdan 1253ec6ffc1aSdantestvfs tv -default 1 1254ec6ffc1aSdanfaultsim_delete_and_reopen 1255ec6ffc1aSdandb func a_string a_string 1256ec6ffc1aSdando_execsql_test pager1-11.1 { 1257ec6ffc1aSdan PRAGMA cache_size = 10; 1258ec6ffc1aSdan BEGIN; 1259ec6ffc1aSdan CREATE TABLE zz(top PRIMARY KEY); 1260ec6ffc1aSdan INSERT INTO zz VALUES(a_string(222)); 1261ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1262ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1263ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1264ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1265ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1266ec6ffc1aSdan COMMIT; 1267ec6ffc1aSdan BEGIN; 1268ec6ffc1aSdan UPDATE zz SET top = a_string(345); 1269ec6ffc1aSdan} {} 1270ec6ffc1aSdan 1271ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR } 1272ec6ffc1aSdantv script lockout 1273ec6ffc1aSdantv filter {xWrite xTruncate xSync} 1274ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}} 1275ec6ffc1aSdan 1276ec6ffc1aSdantv script {} 1277ec6ffc1aSdando_test pager1-11.3 { 1278ec6ffc1aSdan sqlite3 db2 test.db 1279ec6ffc1aSdan execsql { 1280ec6ffc1aSdan PRAGMA journal_mode = TRUNCATE; 1281ec6ffc1aSdan PRAGMA integrity_check; 1282ec6ffc1aSdan } db2 1283ec6ffc1aSdan} {truncate ok} 1284ec6ffc1aSdando_test pager1-11.4 { 1285ec6ffc1aSdan db2 close 1286ec6ffc1aSdan file size test.db-journal 1287ec6ffc1aSdan} {0} 1288ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} 1289f9b4419dSdandb close 1290f9b4419dSdantv delete 1291ec6ffc1aSdan 1292f9b4419dSdan#------------------------------------------------------------------------- 1293f9b4419dSdan# Test "PRAGMA page_size" 1294f9b4419dSdan# 1295f9b4419dSdanforeach pagesize { 1296f9b4419dSdan 512 1024 2048 4096 8192 16384 32768 1297f9b4419dSdan} { 1298f9b4419dSdan faultsim_delete_and_reopen 1299f9b4419dSdan 1300f9b4419dSdan do_test pager1-12.$pagesize.1 { 1301f9b4419dSdan sqlite3 db2 test.db 1302f9b4419dSdan execsql " 1303f9b4419dSdan PRAGMA page_size = $pagesize; 1304f9b4419dSdan CREATE VIEW v AS SELECT * FROM sqlite_master; 1305f9b4419dSdan " db2 1306f9b4419dSdan file size test.db 1307f9b4419dSdan } $pagesize 1308f9b4419dSdan do_test pager1-12.$pagesize.2 { 1309f9b4419dSdan sqlite3 db2 test.db 1310f9b4419dSdan execsql { 1311f9b4419dSdan SELECT count(*) FROM v; 1312f9b4419dSdan PRAGMA main.page_size; 1313f9b4419dSdan } db2 1314f9b4419dSdan } [list 1 $pagesize] 1315f9b4419dSdan do_test pager1-12.$pagesize.3 { 1316f9b4419dSdan execsql { 1317f9b4419dSdan SELECT count(*) FROM v; 1318f9b4419dSdan PRAGMA main.page_size; 1319f9b4419dSdan } 1320f9b4419dSdan } [list 1 $pagesize] 1321f9b4419dSdan db2 close 1322f9b4419dSdan} 1323dca321aeSdan 1324d353331aSdan#------------------------------------------------------------------------- 1325d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases. 1326d353331aSdan# 1327d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent 1328d353331aSdan# journal mode: If the journal associated with a transaction 1329d353331aSdan# is smaller than the journal file (because a previous 1330d353331aSdan# transaction left a very large non-hot journal file in the 1331d353331aSdan# file-system), then SQLite has to be careful that there is 1332d353331aSdan# not a journal-header left over from a previous transaction 1333d353331aSdan# immediately following the journal content just written. 1334d353331aSdan# If there is, and the process crashes so that the journal 1335d353331aSdan# becomes a hot-journal and must be rolled back by another 1336d353331aSdan# process, there is a danger that the other process may roll 1337d353331aSdan# back the aborted transaction, then continue copying data 1338d353331aSdan# from an older transaction from the remainder of the journal. 1339d353331aSdan# See the syncJournal() function for details. 1340d353331aSdan# 1341d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into 1342d353331aSdan# the mix to make the integrity-check more likely to catch 1343d353331aSdan# errors. 1344d353331aSdan# 1345d353331aSdantestvfs tv -default 1 1346d353331aSdantv script xSyncCb 1347d353331aSdantv filter xSync 1348d353331aSdanproc xSyncCb {method filename args} { 1349d353331aSdan set t [file tail $filename] 1350d353331aSdan if {$t == "test.db"} faultsim_save 1351d353331aSdan return SQLITE_OK 1352d353331aSdan} 1353d353331aSdanfaultsim_delete_and_reopen 1354d353331aSdandb func a_string a_string 1355e91a54e1Sdan 1356d353331aSdan# The UPDATE statement at the end of this test case creates a really big 1357d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains 1358d353331aSdan# frequent journal headers. 1359d353331aSdan# 1360d353331aSdando_execsql_test pager1-13.1.1 { 1361d353331aSdan PRAGMA page_size = 1024; 1362d353331aSdan PRAGMA journal_mode = PERSIST; 1363d353331aSdan PRAGMA cache_size = 10; 1364d353331aSdan BEGIN; 1365d353331aSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); 1366d353331aSdan INSERT INTO t1 VALUES(NULL, a_string(400)); 1367d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 2 */ 1368d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 4 */ 1369d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 8 */ 1370d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 16 */ 1371d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 32 */ 1372d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 64 */ 1373d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 128 */ 1374d353331aSdan COMMIT; 1375d353331aSdan UPDATE t1 SET b = a_string(400); 1376d353331aSdan} {persist} 1377d353331aSdan 1378d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one) 1379d353331aSdan# of these will write just enough content that one of the old headers created 1380d353331aSdan# by the transaction in the block above lies immediately after the content 1381d353331aSdan# journalled by the current transaction. 1382d353331aSdan# 1383d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1384d353331aSdan do_execsql_test pager1-13.1.2.$nUp.1 { 1385d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1386d353331aSdan } {} 1387d353331aSdan do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok} 1388d353331aSdan 1389d353331aSdan # Try to access the snapshot of the file-system. 1390d353331aSdan # 1391d353331aSdan sqlite3 db2 sv_test.db 1392d353331aSdan do_test pager1-13.1.2.$nUp.3 { 1393d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1394d353331aSdan } [expr {128*400 - ($nUp-1)}] 1395d353331aSdan do_test pager1-13.1.2.$nUp.4 { 1396d353331aSdan execsql { PRAGMA integrity_check } db2 1397d353331aSdan } {ok} 1398d353331aSdan db2 close 1399d353331aSdan} 1400d353331aSdan 1401d353331aSdan# Same test as above. But this time with an index on the table. 1402d353331aSdan# 1403d353331aSdando_execsql_test pager1-13.2.1 { 1404d353331aSdan CREATE INDEX i1 ON t1(b); 1405d353331aSdan UPDATE t1 SET b = a_string(400); 1406d353331aSdan} {} 1407d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1408d353331aSdan do_execsql_test pager1-13.2.2.$nUp.1 { 1409d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1410d353331aSdan } {} 1411d353331aSdan do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok} 1412d353331aSdan sqlite3 db2 sv_test.db 1413d353331aSdan do_test pager1-13.2.2.$nUp.3 { 1414d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1415d353331aSdan } [expr {128*400 - ($nUp-1)}] 1416d353331aSdan do_test pager1-13.2.2.$nUp.4 { 1417d353331aSdan execsql { PRAGMA integrity_check } db2 1418d353331aSdan } {ok} 1419d353331aSdan db2 close 1420d353331aSdan} 1421d353331aSdan 1422d353331aSdandb close 1423d353331aSdantv delete 1424d353331aSdan 1425d353331aSdan#------------------------------------------------------------------------- 1426d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases. 1427d353331aSdan# 1428d353331aSdanfaultsim_delete_and_reopen 1429d353331aSdando_execsql_test pager1-14.1.1 { 1430d353331aSdan PRAGMA journal_mode = OFF; 1431d353331aSdan CREATE TABLE t1(a, b); 1432d353331aSdan BEGIN; 1433d353331aSdan INSERT INTO t1 VALUES(1, 2); 1434d353331aSdan COMMIT; 1435d353331aSdan SELECT * FROM t1; 1436d353331aSdan} {off 1 2} 1437d353331aSdando_catchsql_test pager1-14.1.2 { 1438d353331aSdan BEGIN; 1439d353331aSdan INSERT INTO t1 VALUES(3, 4); 1440d353331aSdan ROLLBACK; 1441d353331aSdan} {0 {}} 1442d353331aSdando_execsql_test pager1-14.1.3 { 1443d353331aSdan SELECT * FROM t1; 1444d353331aSdan} {1 2 3 4} 1445d353331aSdando_catchsql_test pager1-14.1.4 { 1446d353331aSdan BEGIN; 1447d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1448d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1449d353331aSdan} {1 {PRIMARY KEY must be unique}} 1450d353331aSdando_execsql_test pager1-14.1.5 { 1451d353331aSdan COMMIT; 1452d353331aSdan SELECT * FROM t1; 1453d353331aSdan} {1 2 3 4 2 2 4 4} 1454d353331aSdan 1455c8ce3972Sdan#------------------------------------------------------------------------- 1456c8ce3972Sdan# Test opening and closing the pager sub-system with different values 1457c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable. 1458c8ce3972Sdan# 1459c8ce3972Sdanfaultsim_delete_and_reopen 1460c8ce3972Sdando_execsql_test pager1-15.0 { 1461c8ce3972Sdan CREATE TABLE tx(y, z); 1462c8ce3972Sdan INSERT INTO tx VALUES('Ayutthaya', 'Beijing'); 1463c8ce3972Sdan INSERT INTO tx VALUES('London', 'Tokyo'); 1464c8ce3972Sdan} {} 1465c8ce3972Sdandb close 1466c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} { 1467c8ce3972Sdan testvfs tv -default 1 -szosfile $i 1468c8ce3972Sdan sqlite3 db test.db 1469c8ce3972Sdan do_execsql_test pager1-15.$i.1 { 1470c8ce3972Sdan SELECT * FROM tx; 1471c8ce3972Sdan } {Ayutthaya Beijing London Tokyo} 1472c8ce3972Sdan db close 1473c8ce3972Sdan tv delete 1474c8ce3972Sdan} 1475c8ce3972Sdan 1476c8ce3972Sdan#------------------------------------------------------------------------- 1477c8ce3972Sdan# Check that it is not possible to open a database file if the full path 1478c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname. 1479c8ce3972Sdan# 1480c8ce3972Sdantestvfs tv -default 1 1481c8ce3972Sdantv script xOpenCb 1482c8ce3972Sdantv filter xOpen 1483c8ce3972Sdanproc xOpenCb {method filename} { 1484c8ce3972Sdan set ::file_len [string length $filename] 1485c8ce3972Sdan} 1486c8ce3972Sdansqlite3 db test.db 1487c8ce3972Sdandb close 1488c8ce3972Sdantv delete 1489c8ce3972Sdan 1490c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} { 1491c8ce3972Sdan testvfs tv -default 1 -mxpathname $ii 1492c8ce3972Sdan 1493c8ce3972Sdan # The length of the full path to file "test.db-journal" is ($::file_len+8). 1494c8ce3972Sdan # If the configured sqlite3_vfs.mxPathname value greater than or equal to 1495c8ce3972Sdan # this, then the file can be opened. Otherwise, it cannot. 1496c8ce3972Sdan # 1497c8ce3972Sdan if {$ii >= [expr $::file_len+8]} { 1498c8ce3972Sdan set res {0 {}} 1499c8ce3972Sdan } else { 1500c8ce3972Sdan set res {1 {unable to open database file}} 1501c8ce3972Sdan } 1502c8ce3972Sdan 1503c8ce3972Sdan do_test pager1-16.1.$ii { 1504c8ce3972Sdan list [catch { sqlite3 db test.db } msg] $msg 1505c8ce3972Sdan } $res 1506c8ce3972Sdan 1507c8ce3972Sdan catch {db close} 1508c8ce3972Sdan tv delete 1509c8ce3972Sdan} 1510c8ce3972Sdan 1511c8ce3972Sdan#------------------------------------------------------------------------- 1512c8ce3972Sdan# Test "PRAGMA omit_readlock". 1513c8ce3972Sdan# 1514c8ce3972Sdan# pager1-17.$tn.1.*: Test that if a second connection has an open 1515c8ce3972Sdan# read-transaction, it is not usually possible to write 1516c8ce3972Sdan# the database. 1517c8ce3972Sdan# 1518c8ce3972Sdan# pager1-17.$tn.2.*: Test that if the second connection was opened with 1519c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, and 1520c8ce3972Sdan# "PRAGMA omit_readlock = 1" is executed before attaching 1521c8ce3972Sdan# the database and opening a read-transaction on it, it is 1522c8ce3972Sdan# possible to write the db. 1523c8ce3972Sdan# 1524c8ce3972Sdan# pager1-17.$tn.3.*: Test that if the second connection was *not* opened with 1525c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, executing 1526c8ce3972Sdan# "PRAGMA omit_readlock = 1" has no effect. 1527c8ce3972Sdan# 1528c8ce3972Sdando_multiclient_test tn { 1529c8ce3972Sdan do_test pager1-17.$tn.1.1 { 1530c8ce3972Sdan sql1 { 1531c8ce3972Sdan CREATE TABLE t1(a, b); 1532c8ce3972Sdan INSERT INTO t1 VALUES(1, 2); 1533c8ce3972Sdan } 1534c8ce3972Sdan sql2 { 1535c8ce3972Sdan BEGIN; 1536c8ce3972Sdan SELECT * FROM t1; 1537c8ce3972Sdan } 1538c8ce3972Sdan } {1 2} 1539c8ce3972Sdan do_test pager1-17.$tn.1.2 { 1540c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1541c8ce3972Sdan } {1 {database is locked}} 1542c8ce3972Sdan do_test pager1-17.$tn.1.3 { 1543c8ce3972Sdan sql2 { COMMIT } 1544c8ce3972Sdan sql1 { INSERT INTO t1 VALUES(3, 4) } 1545c8ce3972Sdan } {} 1546c8ce3972Sdan 1547c8ce3972Sdan do_test pager1-17.$tn.2.1 { 1548c8ce3972Sdan code2 { 1549c8ce3972Sdan db2 close 1550c8ce3972Sdan sqlite3 db2 :memory: -readonly 1 1551c8ce3972Sdan } 1552c8ce3972Sdan sql2 { 1553c8ce3972Sdan PRAGMA omit_readlock = 1; 1554c8ce3972Sdan ATTACH 'test.db' AS two; 1555c8ce3972Sdan BEGIN; 1556c8ce3972Sdan SELECT * FROM t1; 1557c8ce3972Sdan } 1558c8ce3972Sdan } {1 2 3 4} 1559c8ce3972Sdan do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {} 1560c8ce3972Sdan do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" } {1 2 3 4} 1561c8ce3972Sdan do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" } {1 2 3 4 5 6} 1562c8ce3972Sdan 1563c8ce3972Sdan do_test pager1-17.$tn.3.1 { 1564c8ce3972Sdan code2 { 1565c8ce3972Sdan db2 close 1566c8ce3972Sdan sqlite3 db2 :memory: 1567c8ce3972Sdan } 1568c8ce3972Sdan sql2 { 1569c8ce3972Sdan PRAGMA omit_readlock = 1; 1570c8ce3972Sdan ATTACH 'test.db' AS two; 1571c8ce3972Sdan BEGIN; 1572c8ce3972Sdan SELECT * FROM t1; 1573c8ce3972Sdan } 1574c8ce3972Sdan } {1 2 3 4 5 6} 1575c8ce3972Sdan do_test pager1-17.$tn.3.2 { 1576c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1577c8ce3972Sdan } {1 {database is locked}} 1578c8ce3972Sdan do_test pager1-17.$tn.3.3 { sql2 COMMIT } {} 1579c8ce3972Sdan} 1580c8ce3972Sdan 1581c8ce3972Sdan#------------------------------------------------------------------------- 1582c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page 1583c8ce3972Sdan# numbers: 1584c8ce3972Sdan# 1585c8ce3972Sdan# + The locking page, 1586c8ce3972Sdan# + Page 0, 1587c8ce3972Sdan# + A page with a page number greater than (2^31-1). 1588c8ce3972Sdan# 1589c8ce3972Sdando_test pager1-18.1 { 1590c8ce3972Sdan faultsim_delete_and_reopen 1591c8ce3972Sdan db func a_string a_string 1592c8ce3972Sdan execsql { 1593c8ce3972Sdan PRAGMA page_size = 1024; 1594c8ce3972Sdan CREATE TABLE t1(a, b); 1595c8ce3972Sdan INSERT INTO t1 VALUES(a_string(500), a_string(200)); 1596c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1597c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1598c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1599c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1600c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1601c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1602c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1603c8ce3972Sdan } 1604c8ce3972Sdan} {} 1605c8ce3972Sdando_test pager1-18.2 { 1606c8ce3972Sdan set root [db one "SELECT rootpage FROM sqlite_master"] 1607c8ce3972Sdan set lockingpage [expr (0x10000/1024) + 1] 1608c8ce3972Sdan execsql { 1609c8ce3972Sdan PRAGMA writable_schema = 1; 1610c8ce3972Sdan UPDATE sqlite_master SET rootpage = $lockingpage; 1611c8ce3972Sdan } 1612c8ce3972Sdan sqlite3 db2 test.db 1613c8ce3972Sdan catchsql { SELECT count(*) FROM t1 } db2 1614c8ce3972Sdan} {1 {database disk image is malformed}} 1615c8ce3972Sdandb2 close 1616c8ce3972Sdando_test pager1-18.3 { 1617c8ce3972Sdan execsql { 1618c8ce3972Sdan CREATE TABLE t2(x); 1619c8ce3972Sdan INSERT INTO t2 VALUES(a_string(5000)); 1620c8ce3972Sdan } 1621c8ce3972Sdan set pgno [expr ([file size test.db] / 1024)-2] 1622c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 00000000 1623c8ce3972Sdan sqlite3 db2 test.db 1624c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1625c8ce3972Sdan} {1 {database disk image is malformed}} 1626c8ce3972Sdandb2 close 1627c8ce3972Sdando_test pager1-18.4 { 1628c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 90000000 1629c8ce3972Sdan sqlite3 db2 test.db 1630c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1631c8ce3972Sdan} {1 {database disk image is malformed}} 1632c8ce3972Sdandb2 close 1633c8ce3972Sdando_test pager1-18.5 { 1634c8ce3972Sdan sqlite3 db "" 1635c8ce3972Sdan execsql { 1636c8ce3972Sdan CREATE TABLE t1(a, b); 1637c8ce3972Sdan CREATE TABLE t2(a, b); 1638c8ce3972Sdan PRAGMA writable_schema = 1; 1639c8ce3972Sdan UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; 1640c8ce3972Sdan PRAGMA writable_schema = 0; 1641c8ce3972Sdan ALTER TABLE t1 RENAME TO x1; 1642c8ce3972Sdan } 1643c8ce3972Sdan catchsql { SELECT * FROM x1 } 1644ba3cbf3dSdan} {1 {database disk image is malformed}} 1645c8ce3972Sdandb close 1646c8ce3972Sdan 1647ba3cbf3dSdando_test pager1-18.6 { 1648ba3cbf3dSdan faultsim_delete_and_reopen 1649ba3cbf3dSdan db func a_string a_string 1650ba3cbf3dSdan execsql { 1651ba3cbf3dSdan PRAGMA page_size = 1024; 1652ba3cbf3dSdan CREATE TABLE t1(x); 1653ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1654ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1655ba3cbf3dSdan } 1656ba3cbf3dSdan 1657ba3cbf3dSdan set root [db one "SELECT rootpage FROM sqlite_master"] 1658ba3cbf3dSdan db close 1659ba3cbf3dSdan 1660ba3cbf3dSdan hexio_write test.db [expr ($root-1)*1024 + 8] 00000000 1661ba3cbf3dSdan sqlite3 db test.db 1662ba3cbf3dSdan catchsql { SELECT length(x) FROM t1 } 1663ba3cbf3dSdan} {1 {database disk image is malformed}} 1664ba3cbf3dSdan 1665ba3cbf3dSdando_test pager1-19.1 { 1666ba3cbf3dSdan sqlite3 db "" 1667ba3cbf3dSdan db func a_string a_string 1668ba3cbf3dSdan execsql { 1669ba3cbf3dSdan PRAGMA page_size = 512; 1670ba3cbf3dSdan PRAGMA auto_vacuum = 1; 1671ba3cbf3dSdan CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1672ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1673ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1674ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1675ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1676ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1677ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1678ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1679ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1680ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1681ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1682ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1683ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1684ba3cbf3dSdan ); 1685ba3cbf3dSdan CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1686ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1687ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1688ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1689ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1690ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1691ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1692ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1693ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1694ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1695ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1696ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1697ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1698ba3cbf3dSdan ); 1699ba3cbf3dSdan INSERT INTO t1(aa) VALUES( a_string(100000) ); 1700ba3cbf3dSdan INSERT INTO t2(aa) VALUES( a_string(100000) ); 1701ba3cbf3dSdan VACUUM; 1702ba3cbf3dSdan } 1703ba3cbf3dSdan} {} 1704ba3cbf3dSdan 17056b63ab47Sdan#------------------------------------------------------------------------- 17066b63ab47Sdan# Test a couple of special cases that come up while committing 17076b63ab47Sdan# transactions: 17086b63ab47Sdan# 17096b63ab47Sdan# pager1-20.1.*: Committing an in-memory database transaction when the 17106b63ab47Sdan# database has not been modified at all. 17116b63ab47Sdan# 17126b63ab47Sdan# pager1-20.2.*: As above, but with a normal db in exclusive-locking mode. 17136b63ab47Sdan# 17146b63ab47Sdan# pager1-20.3.*: Committing a transaction in WAL mode where the database has 17156b63ab47Sdan# been modified, but all dirty pages have been flushed to 17166b63ab47Sdan# disk before the commit. 17176b63ab47Sdan# 17186b63ab47Sdando_test pager1-20.1.1 { 17196b63ab47Sdan catch {db close} 17206b63ab47Sdan sqlite3 db :memory: 17216b63ab47Sdan execsql { 17226b63ab47Sdan CREATE TABLE one(two, three); 17236b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 17246b63ab47Sdan } 17256b63ab47Sdan} {} 17266b63ab47Sdando_test pager1-20.1.2 { 17276b63ab47Sdan execsql { 17286b63ab47Sdan BEGIN EXCLUSIVE; 17296b63ab47Sdan COMMIT; 17306b63ab47Sdan } 17316b63ab47Sdan} {} 17326b63ab47Sdan 17336b63ab47Sdando_test pager1-20.2.1 { 17346b63ab47Sdan faultsim_delete_and_reopen 17356b63ab47Sdan execsql { 17366b63ab47Sdan PRAGMA locking_mode = exclusive; 17376b63ab47Sdan PRAGMA journal_mode = persist; 17386b63ab47Sdan CREATE TABLE one(two, three); 17396b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 17406b63ab47Sdan } 17416b63ab47Sdan} {exclusive persist} 17426b63ab47Sdando_test pager1-20.2.2 { 17436b63ab47Sdan execsql { 17446b63ab47Sdan BEGIN EXCLUSIVE; 17456b63ab47Sdan COMMIT; 17466b63ab47Sdan } 17476b63ab47Sdan} {} 17486b63ab47Sdan 17496b63ab47Sdando_test pager1-20.3.1 { 17506b63ab47Sdan faultsim_delete_and_reopen 17516b63ab47Sdan db func a_string a_string 17526b63ab47Sdan execsql { 17536b63ab47Sdan PRAGMA cache_size = 10; 17546b63ab47Sdan PRAGMA journal_mode = wal; 17556b63ab47Sdan BEGIN; 17566b63ab47Sdan CREATE TABLE t1(x); 17576b63ab47Sdan CREATE TABLE t2(y); 17586b63ab47Sdan INSERT INTO t1 VALUES(a_string(800)); 17596b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */ 17606b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */ 17616b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */ 17626b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */ 17636b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */ 17646b63ab47Sdan COMMIT; 17656b63ab47Sdan } 17666b63ab47Sdan} {wal} 17676b63ab47Sdando_test pager1-20.3.2 { 17686b63ab47Sdan proc recursive_select {id} { 17696b63ab47Sdan db eval {SELECT rowid, x FROM t1 WHERE rowid = ($id-1)} { 17706b63ab47Sdan recursive_select $rowid 17716b63ab47Sdan } 17726b63ab47Sdan } 17736b63ab47Sdan execsql { 17746b63ab47Sdan BEGIN; 17756b63ab47Sdan INSERT INTO t2 VALUES('xxxx'); 17766b63ab47Sdan } 17776b63ab47Sdan recursive_select 32 17786b63ab47Sdan execsql COMMIT 17796b63ab47Sdan} {} 17806b63ab47Sdan 1781*89ccf448Sdan#------------------------------------------------------------------------- 1782*89ccf448Sdan# Test that a WAL database may not be opened if: 1783*89ccf448Sdan# 1784*89ccf448Sdan# pager1-21.1.*: The VFS has an iVersion less than 2, or 1785*89ccf448Sdan# pager1-21.2.*: The VFS does not provide xShmXXX() methods. 1786*89ccf448Sdan# 1787*89ccf448Sdando_test pager1-21.0 { 1788*89ccf448Sdan faultsim_delete_and_reopen 1789*89ccf448Sdan execsql { 1790*89ccf448Sdan PRAGMA journal_mode = WAL; 1791*89ccf448Sdan CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); 1792*89ccf448Sdan INSERT INTO ko DEFAULT VALUES; 1793*89ccf448Sdan } 1794*89ccf448Sdan} {wal} 1795*89ccf448Sdando_test pager1-21.1 { 1796*89ccf448Sdan testvfs tv -noshm 1 1797*89ccf448Sdan sqlite3 db2 test.db -vfs tv 1798*89ccf448Sdan catchsql { SELECT * FROM ko } db2 1799*89ccf448Sdan} {1 {unable to open database file}} 1800*89ccf448Sdandb2 close 1801*89ccf448Sdantv delete 1802*89ccf448Sdando_test pager1-21.2 { 1803*89ccf448Sdanbreakpoint 1804*89ccf448Sdan testvfs tv -iversion 1 1805*89ccf448Sdan sqlite3 db2 test.db -vfs tv 1806*89ccf448Sdan catchsql { SELECT * FROM ko } db2 1807*89ccf448Sdan} {1 {unable to open database file}} 1808*89ccf448Sdandb2 close 1809*89ccf448Sdantv delete 1810*89ccf448Sdan 1811*89ccf448Sdan#------------------------------------------------------------------------- 1812*89ccf448Sdan# Test that a "PRAGMA wal_checkpoint": 1813*89ccf448Sdan# 1814*89ccf448Sdan# pager1-22.1.*: is a no-op on a non-WAL db, and 1815*89ccf448Sdan# pager1-22.2.*: does not cause xSync calls with a synchronous=off db. 1816*89ccf448Sdan# 1817*89ccf448Sdando_test pager1-22.1.1 { 1818*89ccf448Sdan faultsim_delete_and_reopen 1819*89ccf448Sdan execsql { 1820*89ccf448Sdan CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); 1821*89ccf448Sdan INSERT INTO ko DEFAULT VALUES; 1822*89ccf448Sdan } 1823*89ccf448Sdan execsql { PRAGMA wal_checkpoint } 1824*89ccf448Sdan} {} 1825*89ccf448Sdando_test pager1-22.2.1 { 1826*89ccf448Sdan testvfs tv -default 1 1827*89ccf448Sdan tv filter xSync 1828*89ccf448Sdan tv script xSyncCb 1829*89ccf448Sdan proc xSyncCb {args} {incr ::synccount} 1830*89ccf448Sdan set ::synccount 0 1831*89ccf448Sdan sqlite3 db test.db 1832*89ccf448Sdan execsql { 1833*89ccf448Sdan PRAGMA synchronous = off; 1834*89ccf448Sdan PRAGMA journal_mode = WAL; 1835*89ccf448Sdan INSERT INTO ko DEFAULT VALUES; 1836*89ccf448Sdan } 1837*89ccf448Sdan execsql { PRAGMA wal_checkpoint } 1838*89ccf448Sdan set synccount 1839*89ccf448Sdan} {0} 1840*89ccf448Sdandb close 1841*89ccf448Sdantv delete 1842*89ccf448Sdan 1843*89ccf448Sdan#------------------------------------------------------------------------- 1844*89ccf448Sdan# Tests for changing journal mode. 1845*89ccf448Sdan# 1846*89ccf448Sdan# pager1-23.1.*: Test that when changing from PERSIST to DELETE mode, 1847*89ccf448Sdan# the journal file is deleted. 1848*89ccf448Sdan# 1849*89ccf448Sdan# pager1-23.2.*: Same test as above, but while a shared lock is held 1850*89ccf448Sdan# on the database file. 1851*89ccf448Sdan# 1852*89ccf448Sdan# pager1-23.3.*: Same test as above, but while a reserved lock is held 1853*89ccf448Sdan# on the database file. 1854*89ccf448Sdan# 1855*89ccf448Sdan# pager1-23.4.*: And, for fun, while holding an exclusive lock. 1856*89ccf448Sdan# 1857*89ccf448Sdan# pager1-23.5.*: Try to set various different journal modes with an 1858*89ccf448Sdan# in-memory database (only MEMORY and OFF should work). 1859*89ccf448Sdan# 1860*89ccf448Sdando_test pager1-23.1.1 { 1861*89ccf448Sdan faultsim_delete_and_reopen 1862*89ccf448Sdan execsql { 1863*89ccf448Sdan PRAGMA journal_mode = PERSIST; 1864*89ccf448Sdan CREATE TABLE t1(a, b); 1865*89ccf448Sdan } 1866*89ccf448Sdan file exists test.db-journal 1867*89ccf448Sdan} {1} 1868*89ccf448Sdando_test pager1-23.1.2 { 1869*89ccf448Sdan execsql { PRAGMA journal_mode = DELETE } 1870*89ccf448Sdan file exists test.db-journal 1871*89ccf448Sdan} {0} 1872*89ccf448Sdan 1873*89ccf448Sdando_test pager1-23.2.1 { 1874*89ccf448Sdan execsql { 1875*89ccf448Sdan PRAGMA journal_mode = PERSIST; 1876*89ccf448Sdan INSERT INTO t1 VALUES('Canberra', 'ACT'); 1877*89ccf448Sdan } 1878*89ccf448Sdan db eval { SELECT * FROM t1 } { 1879*89ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 1880*89ccf448Sdan } 1881*89ccf448Sdan execsql { PRAGMA journal_mode } 1882*89ccf448Sdan} {delete} 1883*89ccf448Sdando_test pager1-23.2.2 { 1884*89ccf448Sdan file exists test.db-journal 1885*89ccf448Sdan} {0} 1886*89ccf448Sdan 1887*89ccf448Sdando_test pager1-23.3.1 { 1888*89ccf448Sdan execsql { 1889*89ccf448Sdan PRAGMA journal_mode = PERSIST; 1890*89ccf448Sdan INSERT INTO t1 VALUES('Darwin', 'NT'); 1891*89ccf448Sdan BEGIN IMMEDIATE; 1892*89ccf448Sdan } 1893*89ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 1894*89ccf448Sdan execsql { PRAGMA journal_mode } 1895*89ccf448Sdan} {delete} 1896*89ccf448Sdando_test pager1-23.3.2 { 1897*89ccf448Sdan file exists test.db-journal 1898*89ccf448Sdan} {0} 1899*89ccf448Sdando_test pager1-23.3.3 { 1900*89ccf448Sdan execsql COMMIT 1901*89ccf448Sdan} {} 1902*89ccf448Sdan 1903*89ccf448Sdando_test pager1-23.4.1 { 1904*89ccf448Sdan execsql { 1905*89ccf448Sdan PRAGMA journal_mode = PERSIST; 1906*89ccf448Sdan INSERT INTO t1 VALUES('Adelaide', 'SA'); 1907*89ccf448Sdan BEGIN EXCLUSIVE; 1908*89ccf448Sdan } 1909*89ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 1910*89ccf448Sdan execsql { PRAGMA journal_mode } 1911*89ccf448Sdan} {delete} 1912*89ccf448Sdando_test pager1-23.4.2 { 1913*89ccf448Sdan file exists test.db-journal 1914*89ccf448Sdan} {0} 1915*89ccf448Sdando_test pager1-23.4.3 { 1916*89ccf448Sdan execsql COMMIT 1917*89ccf448Sdan} {} 1918*89ccf448Sdan 1919*89ccf448Sdando_test pager1-23.5.1 { 1920*89ccf448Sdan faultsim_delete_and_reopen 1921*89ccf448Sdan sqlite3 db :memory: 1922*89ccf448Sdan} {} 1923*89ccf448Sdanforeach {tn mode possible} { 1924*89ccf448Sdan 2 off 1 1925*89ccf448Sdan 3 memory 1 1926*89ccf448Sdan 4 persist 0 1927*89ccf448Sdan 5 delete 0 1928*89ccf448Sdan 6 wal 0 1929*89ccf448Sdan 7 truncate 0 1930*89ccf448Sdan} { 1931*89ccf448Sdan do_test pager1-23.5.$tn.1 { 1932*89ccf448Sdan execsql "PRAGMA journal_mode = off" 1933*89ccf448Sdan execsql "PRAGMA journal_mode = $mode" 1934*89ccf448Sdan } [if $possible {list $mode} {list off}] 1935*89ccf448Sdan do_test pager1-23.5.$tn.2 { 1936*89ccf448Sdan execsql "PRAGMA journal_mode = memory" 1937*89ccf448Sdan execsql "PRAGMA journal_mode = $mode" 1938*89ccf448Sdan } [if $possible {list $mode} {list memory}] 1939*89ccf448Sdan} 1940*89ccf448Sdando_test pager1-23.8.1 { 1941*89ccf448Sdan execsql {PRAGMA locking_mode = normal} 1942*89ccf448Sdan} {exclusive} 1943*89ccf448Sdando_test pager1-23.8.2 { 1944*89ccf448Sdan execsql {PRAGMA locking_mode = exclusive} 1945*89ccf448Sdan} {exclusive} 1946*89ccf448Sdando_test pager1-23.8.3 { 1947*89ccf448Sdan execsql {PRAGMA locking_mode} 1948*89ccf448Sdan} {exclusive} 1949*89ccf448Sdando_test pager1-23.8.4 { 1950*89ccf448Sdan execsql {PRAGMA main.locking_mode} 1951*89ccf448Sdan} {exclusive} 19526b63ab47Sdan 19536b63ab47Sdan 1954d353331aSdanfinish_test 1955c8ce3972Sdan 1956