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 } 284*6b63ab47Sdan 14 { PRAGMA locking_mode = EXCLUSIVE } { 285*6b63ab47Sdan } 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 1096d353331aSdan#------------------------------------------------------------------------- 1097d353331aSdan# The following tests, pager1-8.*, test that the special filenames 1098d353331aSdan# ":memory:" and "" open temporary databases. 1099d353331aSdan# 11000e986f51Sdanforeach {tn filename} { 11010e986f51Sdan 1 :memory: 11020e986f51Sdan 2 "" 11030e986f51Sdan} { 11040e986f51Sdan do_test pager1-8.$tn.1 { 1105153eda0aSdan faultsim_delete_and_reopen 1106153eda0aSdan db close 11070e986f51Sdan sqlite3 db $filename 1108153eda0aSdan execsql { 1109c8ce3972Sdan PRAGMA auto_vacuum = 1; 1110153eda0aSdan CREATE TABLE x1(x); 1111153eda0aSdan INSERT INTO x1 VALUES('Charles'); 1112153eda0aSdan INSERT INTO x1 VALUES('James'); 1113153eda0aSdan INSERT INTO x1 VALUES('Mary'); 1114153eda0aSdan SELECT * FROM x1; 1115153eda0aSdan } 1116153eda0aSdan } {Charles James Mary} 11170e986f51Sdan 11180e986f51Sdan do_test pager1-8.$tn.2 { 11190e986f51Sdan sqlite3 db2 $filename 11200e986f51Sdan catchsql { SELECT * FROM x1 } db2 1121153eda0aSdan } {1 {no such table: x1}} 1122153eda0aSdan 11230e986f51Sdan do_execsql_test pager1-8.$tn.3 { 11240e986f51Sdan BEGIN; 11250e986f51Sdan INSERT INTO x1 VALUES('William'); 11260e986f51Sdan INSERT INTO x1 VALUES('Anne'); 11270e986f51Sdan ROLLBACK; 11280e986f51Sdan } {} 11290e986f51Sdan} 11300e986f51Sdan 1131dca321aeSdan#------------------------------------------------------------------------- 1132dca321aeSdan# The next block of tests - pager1-9.* - deal with interactions between 1133dca321aeSdan# the pager and the backup API. Test cases: 1134dca321aeSdan# 1135dca321aeSdan# pager1-9.1.*: Test that a backup completes successfully even if the 1136dca321aeSdan# source db is written to during the backup op. 1137dca321aeSdan# 1138dca321aeSdan# pager1-9.2.*: Test that a backup completes successfully even if the 1139dca321aeSdan# source db is written to and then rolled back during a 1140dca321aeSdan# backup operation. 1141dca321aeSdan# 1142dca321aeSdando_test pager1-9.0.1 { 1143dca321aeSdan faultsim_delete_and_reopen 1144dca321aeSdan db func a_string a_string 1145dca321aeSdan execsql { 1146dca321aeSdan PRAGMA cache_size = 10; 1147dca321aeSdan BEGIN; 1148dca321aeSdan CREATE TABLE ab(a, b, UNIQUE(a, b)); 1149dca321aeSdan INSERT INTO ab VALUES( a_string(200), a_string(300) ); 1150dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1151dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1152dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1153dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1154dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1155dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1156dca321aeSdan INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab; 1157dca321aeSdan COMMIT; 1158dca321aeSdan } 1159dca321aeSdan} {} 1160dca321aeSdando_test pager1-9.0.2 { 1161dca321aeSdan sqlite3 db2 test.db2 1162dca321aeSdan db2 eval { PRAGMA cache_size = 10 } 1163dca321aeSdan sqlite3_backup B db2 main db main 1164dca321aeSdan list [B step 10000] [B finish] 1165dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1166dca321aeSdando_test pager1-9.0.3 { 1167dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1168dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1169dca321aeSdan 1170dca321aeSdando_test pager1-9.1.1 { 1171dca321aeSdan execsql { UPDATE ab SET a = a_string(201) } 1172dca321aeSdan sqlite3_backup B db2 main db main 1173dca321aeSdan B step 30 1174dca321aeSdan} {SQLITE_OK} 1175dca321aeSdando_test pager1-9.1.2 { 1176dca321aeSdan execsql { UPDATE ab SET b = a_string(301) } 1177dca321aeSdan list [B step 10000] [B finish] 1178dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1179dca321aeSdando_test pager1-9.1.3 { 1180dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1181dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1182dca321aeSdando_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128} 1183dca321aeSdan 1184dca321aeSdando_test pager1-9.2.1 { 1185dca321aeSdan execsql { UPDATE ab SET a = a_string(202) } 1186dca321aeSdan sqlite3_backup B db2 main db main 1187dca321aeSdan B step 30 1188dca321aeSdan} {SQLITE_OK} 1189dca321aeSdando_test pager1-9.2.2 { 1190dca321aeSdan execsql { 1191dca321aeSdan BEGIN; 1192dca321aeSdan UPDATE ab SET b = a_string(301); 1193dca321aeSdan ROLLBACK; 1194dca321aeSdan } 1195dca321aeSdan list [B step 10000] [B finish] 1196dca321aeSdan} {SQLITE_DONE SQLITE_OK} 1197dca321aeSdando_test pager1-9.2.3 { 1198dca321aeSdan db one {SELECT md5sum(a, b) FROM ab} 1199dca321aeSdan} [db2 one {SELECT md5sum(a, b) FROM ab}] 1200dca321aeSdando_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128} 1201ec6ffc1aSdandb close 1202ec6ffc1aSdandb2 close 1203ec6ffc1aSdan 1204ec6ffc1aSdan#------------------------------------------------------------------------- 1205ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the 1206ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes. 1207ec6ffc1aSdan# 1208ec6ffc1aSdantestvfs tv -default 1 1209ec6ffc1aSdanforeach sectorsize { 1210ec6ffc1aSdan 32 64 128 256 512 1024 2048 1211ec6ffc1aSdan 4096 8192 16384 32768 65536 131072 262144 1212ec6ffc1aSdan} { 1213ec6ffc1aSdan tv sectorsize $sectorsize 1214ec6ffc1aSdan set eff $sectorsize 1215ec6ffc1aSdan if {$sectorsize < 512} { set eff 512 } 1216ec6ffc1aSdan if {$sectorsize > 65536} { set eff 65536 } 1217ec6ffc1aSdan 1218ec6ffc1aSdan do_test pager1-10.$sectorsize { 1219ec6ffc1aSdan faultsim_delete_and_reopen 1220ec6ffc1aSdan execsql { 1221ec6ffc1aSdan PRAGMA journal_mode = PERSIST; 1222ec6ffc1aSdan PRAGMA page_size = 1024; 1223ec6ffc1aSdan CREATE TABLE t1(a, b); 1224ec6ffc1aSdan } 1225ec6ffc1aSdan file size test.db-journal 1226ec6ffc1aSdan } [expr $sectorsize > 65536 ? 65536 : $sectorsize] 1227ec6ffc1aSdan} 1228ec6ffc1aSdandb close 1229ec6ffc1aSdantv delete 1230ec6ffc1aSdan 1231ec6ffc1aSdantestvfs tv -default 1 1232ec6ffc1aSdanfaultsim_delete_and_reopen 1233ec6ffc1aSdandb func a_string a_string 1234ec6ffc1aSdando_execsql_test pager1-11.1 { 1235ec6ffc1aSdan PRAGMA cache_size = 10; 1236ec6ffc1aSdan BEGIN; 1237ec6ffc1aSdan CREATE TABLE zz(top PRIMARY KEY); 1238ec6ffc1aSdan INSERT INTO zz VALUES(a_string(222)); 1239ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1240ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1241ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1242ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1243ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1244ec6ffc1aSdan COMMIT; 1245ec6ffc1aSdan BEGIN; 1246ec6ffc1aSdan UPDATE zz SET top = a_string(345); 1247ec6ffc1aSdan} {} 1248ec6ffc1aSdan 1249ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR } 1250ec6ffc1aSdantv script lockout 1251ec6ffc1aSdantv filter {xWrite xTruncate xSync} 1252ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}} 1253ec6ffc1aSdan 1254ec6ffc1aSdantv script {} 1255ec6ffc1aSdando_test pager1-11.3 { 1256ec6ffc1aSdan sqlite3 db2 test.db 1257ec6ffc1aSdan execsql { 1258ec6ffc1aSdan PRAGMA journal_mode = TRUNCATE; 1259ec6ffc1aSdan PRAGMA integrity_check; 1260ec6ffc1aSdan } db2 1261ec6ffc1aSdan} {truncate ok} 1262ec6ffc1aSdando_test pager1-11.4 { 1263ec6ffc1aSdan db2 close 1264ec6ffc1aSdan file size test.db-journal 1265ec6ffc1aSdan} {0} 1266ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} 1267f9b4419dSdandb close 1268f9b4419dSdantv delete 1269ec6ffc1aSdan 1270f9b4419dSdan#------------------------------------------------------------------------- 1271f9b4419dSdan# Test "PRAGMA page_size" 1272f9b4419dSdan# 1273f9b4419dSdanforeach pagesize { 1274f9b4419dSdan 512 1024 2048 4096 8192 16384 32768 1275f9b4419dSdan} { 1276f9b4419dSdan faultsim_delete_and_reopen 1277f9b4419dSdan 1278f9b4419dSdan do_test pager1-12.$pagesize.1 { 1279f9b4419dSdan sqlite3 db2 test.db 1280f9b4419dSdan execsql " 1281f9b4419dSdan PRAGMA page_size = $pagesize; 1282f9b4419dSdan CREATE VIEW v AS SELECT * FROM sqlite_master; 1283f9b4419dSdan " db2 1284f9b4419dSdan file size test.db 1285f9b4419dSdan } $pagesize 1286f9b4419dSdan do_test pager1-12.$pagesize.2 { 1287f9b4419dSdan sqlite3 db2 test.db 1288f9b4419dSdan execsql { 1289f9b4419dSdan SELECT count(*) FROM v; 1290f9b4419dSdan PRAGMA main.page_size; 1291f9b4419dSdan } db2 1292f9b4419dSdan } [list 1 $pagesize] 1293f9b4419dSdan do_test pager1-12.$pagesize.3 { 1294f9b4419dSdan execsql { 1295f9b4419dSdan SELECT count(*) FROM v; 1296f9b4419dSdan PRAGMA main.page_size; 1297f9b4419dSdan } 1298f9b4419dSdan } [list 1 $pagesize] 1299f9b4419dSdan db2 close 1300f9b4419dSdan} 1301dca321aeSdan 1302d353331aSdan#------------------------------------------------------------------------- 1303d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases. 1304d353331aSdan# 1305d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent 1306d353331aSdan# journal mode: If the journal associated with a transaction 1307d353331aSdan# is smaller than the journal file (because a previous 1308d353331aSdan# transaction left a very large non-hot journal file in the 1309d353331aSdan# file-system), then SQLite has to be careful that there is 1310d353331aSdan# not a journal-header left over from a previous transaction 1311d353331aSdan# immediately following the journal content just written. 1312d353331aSdan# If there is, and the process crashes so that the journal 1313d353331aSdan# becomes a hot-journal and must be rolled back by another 1314d353331aSdan# process, there is a danger that the other process may roll 1315d353331aSdan# back the aborted transaction, then continue copying data 1316d353331aSdan# from an older transaction from the remainder of the journal. 1317d353331aSdan# See the syncJournal() function for details. 1318d353331aSdan# 1319d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into 1320d353331aSdan# the mix to make the integrity-check more likely to catch 1321d353331aSdan# errors. 1322d353331aSdan# 1323d353331aSdantestvfs tv -default 1 1324d353331aSdantv script xSyncCb 1325d353331aSdantv filter xSync 1326d353331aSdanproc xSyncCb {method filename args} { 1327d353331aSdan set t [file tail $filename] 1328d353331aSdan if {$t == "test.db"} faultsim_save 1329d353331aSdan return SQLITE_OK 1330d353331aSdan} 1331d353331aSdanfaultsim_delete_and_reopen 1332d353331aSdandb func a_string a_string 1333e91a54e1Sdan 1334d353331aSdan# The UPDATE statement at the end of this test case creates a really big 1335d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains 1336d353331aSdan# frequent journal headers. 1337d353331aSdan# 1338d353331aSdando_execsql_test pager1-13.1.1 { 1339d353331aSdan PRAGMA page_size = 1024; 1340d353331aSdan PRAGMA journal_mode = PERSIST; 1341d353331aSdan PRAGMA cache_size = 10; 1342d353331aSdan BEGIN; 1343d353331aSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); 1344d353331aSdan INSERT INTO t1 VALUES(NULL, a_string(400)); 1345d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 2 */ 1346d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 4 */ 1347d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 8 */ 1348d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 16 */ 1349d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 32 */ 1350d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 64 */ 1351d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 128 */ 1352d353331aSdan COMMIT; 1353d353331aSdan UPDATE t1 SET b = a_string(400); 1354d353331aSdan} {persist} 1355d353331aSdan 1356d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one) 1357d353331aSdan# of these will write just enough content that one of the old headers created 1358d353331aSdan# by the transaction in the block above lies immediately after the content 1359d353331aSdan# journalled by the current transaction. 1360d353331aSdan# 1361d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1362d353331aSdan do_execsql_test pager1-13.1.2.$nUp.1 { 1363d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1364d353331aSdan } {} 1365d353331aSdan do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok} 1366d353331aSdan 1367d353331aSdan # Try to access the snapshot of the file-system. 1368d353331aSdan # 1369d353331aSdan sqlite3 db2 sv_test.db 1370d353331aSdan do_test pager1-13.1.2.$nUp.3 { 1371d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1372d353331aSdan } [expr {128*400 - ($nUp-1)}] 1373d353331aSdan do_test pager1-13.1.2.$nUp.4 { 1374d353331aSdan execsql { PRAGMA integrity_check } db2 1375d353331aSdan } {ok} 1376d353331aSdan db2 close 1377d353331aSdan} 1378d353331aSdan 1379d353331aSdan# Same test as above. But this time with an index on the table. 1380d353331aSdan# 1381d353331aSdando_execsql_test pager1-13.2.1 { 1382d353331aSdan CREATE INDEX i1 ON t1(b); 1383d353331aSdan UPDATE t1 SET b = a_string(400); 1384d353331aSdan} {} 1385d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1386d353331aSdan do_execsql_test pager1-13.2.2.$nUp.1 { 1387d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1388d353331aSdan } {} 1389d353331aSdan do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok} 1390d353331aSdan sqlite3 db2 sv_test.db 1391d353331aSdan do_test pager1-13.2.2.$nUp.3 { 1392d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1393d353331aSdan } [expr {128*400 - ($nUp-1)}] 1394d353331aSdan do_test pager1-13.2.2.$nUp.4 { 1395d353331aSdan execsql { PRAGMA integrity_check } db2 1396d353331aSdan } {ok} 1397d353331aSdan db2 close 1398d353331aSdan} 1399d353331aSdan 1400d353331aSdandb close 1401d353331aSdantv delete 1402d353331aSdan 1403d353331aSdan#------------------------------------------------------------------------- 1404d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases. 1405d353331aSdan# 1406d353331aSdanfaultsim_delete_and_reopen 1407d353331aSdando_execsql_test pager1-14.1.1 { 1408d353331aSdan PRAGMA journal_mode = OFF; 1409d353331aSdan CREATE TABLE t1(a, b); 1410d353331aSdan BEGIN; 1411d353331aSdan INSERT INTO t1 VALUES(1, 2); 1412d353331aSdan COMMIT; 1413d353331aSdan SELECT * FROM t1; 1414d353331aSdan} {off 1 2} 1415d353331aSdando_catchsql_test pager1-14.1.2 { 1416d353331aSdan BEGIN; 1417d353331aSdan INSERT INTO t1 VALUES(3, 4); 1418d353331aSdan ROLLBACK; 1419d353331aSdan} {0 {}} 1420d353331aSdando_execsql_test pager1-14.1.3 { 1421d353331aSdan SELECT * FROM t1; 1422d353331aSdan} {1 2 3 4} 1423d353331aSdando_catchsql_test pager1-14.1.4 { 1424d353331aSdan BEGIN; 1425d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1426d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1427d353331aSdan} {1 {PRIMARY KEY must be unique}} 1428d353331aSdando_execsql_test pager1-14.1.5 { 1429d353331aSdan COMMIT; 1430d353331aSdan SELECT * FROM t1; 1431d353331aSdan} {1 2 3 4 2 2 4 4} 1432d353331aSdan 1433c8ce3972Sdan#------------------------------------------------------------------------- 1434c8ce3972Sdan# Test opening and closing the pager sub-system with different values 1435c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable. 1436c8ce3972Sdan# 1437c8ce3972Sdanfaultsim_delete_and_reopen 1438c8ce3972Sdando_execsql_test pager1-15.0 { 1439c8ce3972Sdan CREATE TABLE tx(y, z); 1440c8ce3972Sdan INSERT INTO tx VALUES('Ayutthaya', 'Beijing'); 1441c8ce3972Sdan INSERT INTO tx VALUES('London', 'Tokyo'); 1442c8ce3972Sdan} {} 1443c8ce3972Sdandb close 1444c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} { 1445c8ce3972Sdan testvfs tv -default 1 -szosfile $i 1446c8ce3972Sdan sqlite3 db test.db 1447c8ce3972Sdan do_execsql_test pager1-15.$i.1 { 1448c8ce3972Sdan SELECT * FROM tx; 1449c8ce3972Sdan } {Ayutthaya Beijing London Tokyo} 1450c8ce3972Sdan db close 1451c8ce3972Sdan tv delete 1452c8ce3972Sdan} 1453c8ce3972Sdan 1454c8ce3972Sdan#------------------------------------------------------------------------- 1455c8ce3972Sdan# Check that it is not possible to open a database file if the full path 1456c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname. 1457c8ce3972Sdan# 1458c8ce3972Sdantestvfs tv -default 1 1459c8ce3972Sdantv script xOpenCb 1460c8ce3972Sdantv filter xOpen 1461c8ce3972Sdanproc xOpenCb {method filename} { 1462c8ce3972Sdan set ::file_len [string length $filename] 1463c8ce3972Sdan} 1464c8ce3972Sdansqlite3 db test.db 1465c8ce3972Sdandb close 1466c8ce3972Sdantv delete 1467c8ce3972Sdan 1468c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} { 1469c8ce3972Sdan testvfs tv -default 1 -mxpathname $ii 1470c8ce3972Sdan 1471c8ce3972Sdan # The length of the full path to file "test.db-journal" is ($::file_len+8). 1472c8ce3972Sdan # If the configured sqlite3_vfs.mxPathname value greater than or equal to 1473c8ce3972Sdan # this, then the file can be opened. Otherwise, it cannot. 1474c8ce3972Sdan # 1475c8ce3972Sdan if {$ii >= [expr $::file_len+8]} { 1476c8ce3972Sdan set res {0 {}} 1477c8ce3972Sdan } else { 1478c8ce3972Sdan set res {1 {unable to open database file}} 1479c8ce3972Sdan } 1480c8ce3972Sdan 1481c8ce3972Sdan do_test pager1-16.1.$ii { 1482c8ce3972Sdan list [catch { sqlite3 db test.db } msg] $msg 1483c8ce3972Sdan } $res 1484c8ce3972Sdan 1485c8ce3972Sdan catch {db close} 1486c8ce3972Sdan tv delete 1487c8ce3972Sdan} 1488c8ce3972Sdan 1489c8ce3972Sdan#------------------------------------------------------------------------- 1490c8ce3972Sdan# Test "PRAGMA omit_readlock". 1491c8ce3972Sdan# 1492c8ce3972Sdan# pager1-17.$tn.1.*: Test that if a second connection has an open 1493c8ce3972Sdan# read-transaction, it is not usually possible to write 1494c8ce3972Sdan# the database. 1495c8ce3972Sdan# 1496c8ce3972Sdan# pager1-17.$tn.2.*: Test that if the second connection was opened with 1497c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, and 1498c8ce3972Sdan# "PRAGMA omit_readlock = 1" is executed before attaching 1499c8ce3972Sdan# the database and opening a read-transaction on it, it is 1500c8ce3972Sdan# possible to write the db. 1501c8ce3972Sdan# 1502c8ce3972Sdan# pager1-17.$tn.3.*: Test that if the second connection was *not* opened with 1503c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, executing 1504c8ce3972Sdan# "PRAGMA omit_readlock = 1" has no effect. 1505c8ce3972Sdan# 1506c8ce3972Sdando_multiclient_test tn { 1507c8ce3972Sdan do_test pager1-17.$tn.1.1 { 1508c8ce3972Sdan sql1 { 1509c8ce3972Sdan CREATE TABLE t1(a, b); 1510c8ce3972Sdan INSERT INTO t1 VALUES(1, 2); 1511c8ce3972Sdan } 1512c8ce3972Sdan sql2 { 1513c8ce3972Sdan BEGIN; 1514c8ce3972Sdan SELECT * FROM t1; 1515c8ce3972Sdan } 1516c8ce3972Sdan } {1 2} 1517c8ce3972Sdan do_test pager1-17.$tn.1.2 { 1518c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1519c8ce3972Sdan } {1 {database is locked}} 1520c8ce3972Sdan do_test pager1-17.$tn.1.3 { 1521c8ce3972Sdan sql2 { COMMIT } 1522c8ce3972Sdan sql1 { INSERT INTO t1 VALUES(3, 4) } 1523c8ce3972Sdan } {} 1524c8ce3972Sdan 1525c8ce3972Sdan do_test pager1-17.$tn.2.1 { 1526c8ce3972Sdan code2 { 1527c8ce3972Sdan db2 close 1528c8ce3972Sdan sqlite3 db2 :memory: -readonly 1 1529c8ce3972Sdan } 1530c8ce3972Sdan sql2 { 1531c8ce3972Sdan PRAGMA omit_readlock = 1; 1532c8ce3972Sdan ATTACH 'test.db' AS two; 1533c8ce3972Sdan BEGIN; 1534c8ce3972Sdan SELECT * FROM t1; 1535c8ce3972Sdan } 1536c8ce3972Sdan } {1 2 3 4} 1537c8ce3972Sdan do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {} 1538c8ce3972Sdan do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" } {1 2 3 4} 1539c8ce3972Sdan do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" } {1 2 3 4 5 6} 1540c8ce3972Sdan 1541c8ce3972Sdan do_test pager1-17.$tn.3.1 { 1542c8ce3972Sdan code2 { 1543c8ce3972Sdan db2 close 1544c8ce3972Sdan sqlite3 db2 :memory: 1545c8ce3972Sdan } 1546c8ce3972Sdan sql2 { 1547c8ce3972Sdan PRAGMA omit_readlock = 1; 1548c8ce3972Sdan ATTACH 'test.db' AS two; 1549c8ce3972Sdan BEGIN; 1550c8ce3972Sdan SELECT * FROM t1; 1551c8ce3972Sdan } 1552c8ce3972Sdan } {1 2 3 4 5 6} 1553c8ce3972Sdan do_test pager1-17.$tn.3.2 { 1554c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1555c8ce3972Sdan } {1 {database is locked}} 1556c8ce3972Sdan do_test pager1-17.$tn.3.3 { sql2 COMMIT } {} 1557c8ce3972Sdan} 1558c8ce3972Sdan 1559c8ce3972Sdan#------------------------------------------------------------------------- 1560c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page 1561c8ce3972Sdan# numbers: 1562c8ce3972Sdan# 1563c8ce3972Sdan# + The locking page, 1564c8ce3972Sdan# + Page 0, 1565c8ce3972Sdan# + A page with a page number greater than (2^31-1). 1566c8ce3972Sdan# 1567c8ce3972Sdando_test pager1-18.1 { 1568c8ce3972Sdan faultsim_delete_and_reopen 1569c8ce3972Sdan db func a_string a_string 1570c8ce3972Sdan execsql { 1571c8ce3972Sdan PRAGMA page_size = 1024; 1572c8ce3972Sdan CREATE TABLE t1(a, b); 1573c8ce3972Sdan INSERT INTO t1 VALUES(a_string(500), a_string(200)); 1574c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1575c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1576c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1577c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1578c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1579c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1580c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1581c8ce3972Sdan } 1582c8ce3972Sdan} {} 1583c8ce3972Sdando_test pager1-18.2 { 1584c8ce3972Sdan set root [db one "SELECT rootpage FROM sqlite_master"] 1585c8ce3972Sdan set lockingpage [expr (0x10000/1024) + 1] 1586c8ce3972Sdan execsql { 1587c8ce3972Sdan PRAGMA writable_schema = 1; 1588c8ce3972Sdan UPDATE sqlite_master SET rootpage = $lockingpage; 1589c8ce3972Sdan } 1590c8ce3972Sdan sqlite3 db2 test.db 1591c8ce3972Sdan catchsql { SELECT count(*) FROM t1 } db2 1592c8ce3972Sdan} {1 {database disk image is malformed}} 1593c8ce3972Sdandb2 close 1594c8ce3972Sdando_test pager1-18.3 { 1595c8ce3972Sdan execsql { 1596c8ce3972Sdan CREATE TABLE t2(x); 1597c8ce3972Sdan INSERT INTO t2 VALUES(a_string(5000)); 1598c8ce3972Sdan } 1599c8ce3972Sdan set pgno [expr ([file size test.db] / 1024)-2] 1600c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 00000000 1601c8ce3972Sdan sqlite3 db2 test.db 1602c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1603c8ce3972Sdan} {1 {database disk image is malformed}} 1604c8ce3972Sdandb2 close 1605c8ce3972Sdando_test pager1-18.4 { 1606c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 90000000 1607c8ce3972Sdan sqlite3 db2 test.db 1608c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1609c8ce3972Sdan} {1 {database disk image is malformed}} 1610c8ce3972Sdandb2 close 1611c8ce3972Sdando_test pager1-18.5 { 1612c8ce3972Sdan sqlite3 db "" 1613c8ce3972Sdan execsql { 1614c8ce3972Sdan CREATE TABLE t1(a, b); 1615c8ce3972Sdan CREATE TABLE t2(a, b); 1616c8ce3972Sdan PRAGMA writable_schema = 1; 1617c8ce3972Sdan UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; 1618c8ce3972Sdan PRAGMA writable_schema = 0; 1619c8ce3972Sdan ALTER TABLE t1 RENAME TO x1; 1620c8ce3972Sdan } 1621c8ce3972Sdan catchsql { SELECT * FROM x1 } 1622ba3cbf3dSdan} {1 {database disk image is malformed}} 1623c8ce3972Sdandb close 1624c8ce3972Sdan 1625ba3cbf3dSdando_test pager1-18.6 { 1626ba3cbf3dSdan faultsim_delete_and_reopen 1627ba3cbf3dSdan db func a_string a_string 1628ba3cbf3dSdan execsql { 1629ba3cbf3dSdan PRAGMA page_size = 1024; 1630ba3cbf3dSdan CREATE TABLE t1(x); 1631ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1632ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1633ba3cbf3dSdan } 1634ba3cbf3dSdan 1635ba3cbf3dSdan set root [db one "SELECT rootpage FROM sqlite_master"] 1636ba3cbf3dSdan db close 1637ba3cbf3dSdan 1638ba3cbf3dSdan hexio_write test.db [expr ($root-1)*1024 + 8] 00000000 1639ba3cbf3dSdan sqlite3 db test.db 1640ba3cbf3dSdan catchsql { SELECT length(x) FROM t1 } 1641ba3cbf3dSdan} {1 {database disk image is malformed}} 1642ba3cbf3dSdan 1643ba3cbf3dSdando_test pager1-19.1 { 1644ba3cbf3dSdan sqlite3 db "" 1645ba3cbf3dSdan db func a_string a_string 1646ba3cbf3dSdan execsql { 1647ba3cbf3dSdan PRAGMA page_size = 512; 1648ba3cbf3dSdan PRAGMA auto_vacuum = 1; 1649ba3cbf3dSdan CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1650ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1651ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1652ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1653ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1654ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1655ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1656ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1657ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1658ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1659ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1660ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1661ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1662ba3cbf3dSdan ); 1663ba3cbf3dSdan CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1664ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1665ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1666ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1667ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1668ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1669ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1670ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1671ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1672ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1673ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1674ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1675ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1676ba3cbf3dSdan ); 1677ba3cbf3dSdan INSERT INTO t1(aa) VALUES( a_string(100000) ); 1678ba3cbf3dSdan INSERT INTO t2(aa) VALUES( a_string(100000) ); 1679ba3cbf3dSdan VACUUM; 1680ba3cbf3dSdan } 1681ba3cbf3dSdan} {} 1682ba3cbf3dSdan 1683*6b63ab47Sdan#------------------------------------------------------------------------- 1684*6b63ab47Sdan# Test a couple of special cases that come up while committing 1685*6b63ab47Sdan# transactions: 1686*6b63ab47Sdan# 1687*6b63ab47Sdan# pager1-20.1.*: Committing an in-memory database transaction when the 1688*6b63ab47Sdan# database has not been modified at all. 1689*6b63ab47Sdan# 1690*6b63ab47Sdan# pager1-20.2.*: As above, but with a normal db in exclusive-locking mode. 1691*6b63ab47Sdan# 1692*6b63ab47Sdan# pager1-20.3.*: Committing a transaction in WAL mode where the database has 1693*6b63ab47Sdan# been modified, but all dirty pages have been flushed to 1694*6b63ab47Sdan# disk before the commit. 1695*6b63ab47Sdan# 1696*6b63ab47Sdando_test pager1-20.1.1 { 1697*6b63ab47Sdan catch {db close} 1698*6b63ab47Sdan sqlite3 db :memory: 1699*6b63ab47Sdan execsql { 1700*6b63ab47Sdan CREATE TABLE one(two, three); 1701*6b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 1702*6b63ab47Sdan } 1703*6b63ab47Sdan} {} 1704*6b63ab47Sdando_test pager1-20.1.2 { 1705*6b63ab47Sdan execsql { 1706*6b63ab47Sdan BEGIN EXCLUSIVE; 1707*6b63ab47Sdan COMMIT; 1708*6b63ab47Sdan } 1709*6b63ab47Sdan} {} 1710*6b63ab47Sdan 1711*6b63ab47Sdando_test pager1-20.2.1 { 1712*6b63ab47Sdan faultsim_delete_and_reopen 1713*6b63ab47Sdan execsql { 1714*6b63ab47Sdan PRAGMA locking_mode = exclusive; 1715*6b63ab47Sdan PRAGMA journal_mode = persist; 1716*6b63ab47Sdan CREATE TABLE one(two, three); 1717*6b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 1718*6b63ab47Sdan } 1719*6b63ab47Sdan} {exclusive persist} 1720*6b63ab47Sdando_test pager1-20.2.2 { 1721*6b63ab47Sdan execsql { 1722*6b63ab47Sdan BEGIN EXCLUSIVE; 1723*6b63ab47Sdan COMMIT; 1724*6b63ab47Sdan } 1725*6b63ab47Sdan} {} 1726*6b63ab47Sdan 1727*6b63ab47Sdando_test pager1-20.3.1 { 1728*6b63ab47Sdan faultsim_delete_and_reopen 1729*6b63ab47Sdan db func a_string a_string 1730*6b63ab47Sdan execsql { 1731*6b63ab47Sdan PRAGMA cache_size = 10; 1732*6b63ab47Sdan PRAGMA journal_mode = wal; 1733*6b63ab47Sdan BEGIN; 1734*6b63ab47Sdan CREATE TABLE t1(x); 1735*6b63ab47Sdan CREATE TABLE t2(y); 1736*6b63ab47Sdan INSERT INTO t1 VALUES(a_string(800)); 1737*6b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */ 1738*6b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */ 1739*6b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */ 1740*6b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */ 1741*6b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */ 1742*6b63ab47Sdan COMMIT; 1743*6b63ab47Sdan } 1744*6b63ab47Sdan} {wal} 1745*6b63ab47Sdando_test pager1-20.3.2 { 1746*6b63ab47Sdan proc recursive_select {id} { 1747*6b63ab47Sdan db eval {SELECT rowid, x FROM t1 WHERE rowid = ($id-1)} { 1748*6b63ab47Sdan recursive_select $rowid 1749*6b63ab47Sdan } 1750*6b63ab47Sdan } 1751*6b63ab47Sdan execsql { 1752*6b63ab47Sdan BEGIN; 1753*6b63ab47Sdan INSERT INTO t2 VALUES('xxxx'); 1754*6b63ab47Sdan } 1755*6b63ab47Sdan recursive_select 32 1756*6b63ab47Sdan execsql COMMIT 1757*6b63ab47Sdan} {} 1758*6b63ab47Sdan 1759*6b63ab47Sdan 1760*6b63ab47Sdan 1761d353331aSdanfinish_test 1762c8ce3972Sdan 1763