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 109689ccf448Sdando_test pager1-7.2.1 { 109789ccf448Sdan faultsim_delete_and_reopen 109889ccf448Sdan execsql { 109989ccf448Sdan PRAGMA locking_mode = EXCLUSIVE; 110089ccf448Sdan CREATE TABLE t1(a, b); 110189ccf448Sdan BEGIN; 110289ccf448Sdan PRAGMA journal_mode = delete; 110389ccf448Sdan PRAGMA journal_mode = truncate; 110489ccf448Sdan } 110589ccf448Sdan} {exclusive delete truncate} 110689ccf448Sdando_test pager1-7.2.2 { 110789ccf448Sdan execsql { INSERT INTO t1 VALUES(1, 2) } 110889ccf448Sdan execsql { PRAGMA journal_mode = persist } 110989ccf448Sdan} {truncate} 111089ccf448Sdando_test pager1-7.2.3 { 111189ccf448Sdan execsql { COMMIT } 111289ccf448Sdan execsql { 111389ccf448Sdan PRAGMA journal_mode = persist; 111489ccf448Sdan PRAGMA journal_size_limit; 111589ccf448Sdan } 111689ccf448Sdan} {persist -1} 111789ccf448Sdan 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 1226*d0b0d4dcSdanproc recursive_select {id table {script {}}} { 1227*d0b0d4dcSdan set cnt 0 1228*d0b0d4dcSdan db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" { 1229*d0b0d4dcSdan recursive_select $rowid $table $script 1230*d0b0d4dcSdan incr cnt 1231*d0b0d4dcSdan } 1232*d0b0d4dcSdan if {$cnt==0} { eval $script } 1233*d0b0d4dcSdan} 1234*d0b0d4dcSdan 1235ec6ffc1aSdan#------------------------------------------------------------------------- 1236ec6ffc1aSdan# Test that regardless of the value returned by xSectorSize(), the 1237ec6ffc1aSdan# minimum effective sector-size is 512 and the maximum 65536 bytes. 1238ec6ffc1aSdan# 1239ec6ffc1aSdantestvfs tv -default 1 1240ec6ffc1aSdanforeach sectorsize { 1241ec6ffc1aSdan 32 64 128 256 512 1024 2048 1242ec6ffc1aSdan 4096 8192 16384 32768 65536 131072 262144 1243ec6ffc1aSdan} { 1244ec6ffc1aSdan tv sectorsize $sectorsize 1245ec6ffc1aSdan set eff $sectorsize 1246ec6ffc1aSdan if {$sectorsize < 512} { set eff 512 } 1247ec6ffc1aSdan if {$sectorsize > 65536} { set eff 65536 } 1248ec6ffc1aSdan 1249*d0b0d4dcSdan do_test pager1-10.$sectorsize.1 { 1250ec6ffc1aSdan faultsim_delete_and_reopen 1251*d0b0d4dcSdan db func a_string a_string 1252ec6ffc1aSdan execsql { 1253ec6ffc1aSdan PRAGMA journal_mode = PERSIST; 1254ec6ffc1aSdan PRAGMA page_size = 1024; 1255*d0b0d4dcSdan BEGIN; 1256ec6ffc1aSdan CREATE TABLE t1(a, b); 1257*d0b0d4dcSdan CREATE TABLE t2(a, b); 1258*d0b0d4dcSdan CREATE TABLE t3(a, b); 1259*d0b0d4dcSdan COMMIT; 1260ec6ffc1aSdan } 1261ec6ffc1aSdan file size test.db-journal 1262ec6ffc1aSdan } [expr $sectorsize > 65536 ? 65536 : $sectorsize] 1263*d0b0d4dcSdan 1264*d0b0d4dcSdan do_test pager1-10.$sectorsize.2 { 1265*d0b0d4dcSdan execsql { 1266*d0b0d4dcSdan INSERT INTO t3 VALUES(a_string(300), a_string(300)); 1267*d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 2 */ 1268*d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 4 */ 1269*d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 8 */ 1270*d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 16 */ 1271*d0b0d4dcSdan INSERT INTO t3 SELECT * FROM t3; /* 32 */ 1272ec6ffc1aSdan } 1273*d0b0d4dcSdan } {} 1274*d0b0d4dcSdan 1275*d0b0d4dcSdan do_test pager1-10.$sectorsize.3 { 1276*d0b0d4dcSdan db close 1277*d0b0d4dcSdan sqlite3 db test.db 1278*d0b0d4dcSdan execsql { 1279*d0b0d4dcSdan PRAGMA cache_size = 10; 1280*d0b0d4dcSdan BEGIN; 1281*d0b0d4dcSdan } 1282*d0b0d4dcSdan recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"} 1283*d0b0d4dcSdan execsql { 1284*d0b0d4dcSdan COMMIT; 1285*d0b0d4dcSdan SELECT * FROM t2; 1286*d0b0d4dcSdan } 1287*d0b0d4dcSdan } {1 2} 1288*d0b0d4dcSdan 1289*d0b0d4dcSdan do_test pager1-10.$sectorsize.4 { 1290*d0b0d4dcSdan execsql { 1291*d0b0d4dcSdan CREATE TABLE t6(a, b); 1292*d0b0d4dcSdan CREATE TABLE t7(a, b); 1293*d0b0d4dcSdan CREATE TABLE t5(a, b); 1294*d0b0d4dcSdan DROP TABLE t6; 1295*d0b0d4dcSdan DROP TABLE t7; 1296*d0b0d4dcSdan } 1297*d0b0d4dcSdan if {$eff==65536} breakpoint 1298*d0b0d4dcSdan execsql { 1299*d0b0d4dcSdan BEGIN; 1300*d0b0d4dcSdan CREATE TABLE t6(a, b); 1301*d0b0d4dcSdan } 1302*d0b0d4dcSdan recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"} 1303*d0b0d4dcSdan execsql { 1304*d0b0d4dcSdan COMMIT; 1305*d0b0d4dcSdan SELECT * FROM t5; 1306*d0b0d4dcSdan } 1307*d0b0d4dcSdan } {1 2} 1308*d0b0d4dcSdan 1309*d0b0d4dcSdan} 1310*d0b0d4dcSdandb close 1311*d0b0d4dcSdan 1312*d0b0d4dcSdantv sectorsize 4096 1313*d0b0d4dcSdando_test pager1.10.x.1 { 1314*d0b0d4dcSdan faultsim_delete_and_reopen 1315*d0b0d4dcSdan execsql { 1316*d0b0d4dcSdan PRAGMA page_size = 1024; 1317*d0b0d4dcSdan CREATE TABLE t1(x); 1318*d0b0d4dcSdan } 1319*d0b0d4dcSdan for {set i 0} {$i<30} {incr i} { 1320*d0b0d4dcSdan execsql { INSERT INTO t1 VALUES(zeroblob(900)) } 1321*d0b0d4dcSdan } 1322*d0b0d4dcSdan file size test.db 1323*d0b0d4dcSdan} {32768} 1324*d0b0d4dcSdando_test pager1.10.x.2 { 1325*d0b0d4dcSdan execsql { 1326*d0b0d4dcSdan CREATE TABLE t2(x); 1327*d0b0d4dcSdan DROP TABLE t2; 1328*d0b0d4dcSdan } 1329*d0b0d4dcSdan file size test.db 1330*d0b0d4dcSdan} {33792} 1331*d0b0d4dcSdando_test pager1.10.x.3 { 1332*d0b0d4dcSdan execsql { 1333*d0b0d4dcSdan BEGIN; 1334*d0b0d4dcSdan CREATE TABLE t2(x); 1335*d0b0d4dcSdan } 1336*d0b0d4dcSdan recursive_select 30 t1 1337*d0b0d4dcSdan execsql { 1338*d0b0d4dcSdan CREATE TABLE t3(x); 1339*d0b0d4dcSdan COMMIT; 1340*d0b0d4dcSdan } 1341*d0b0d4dcSdan} {} 1342*d0b0d4dcSdan 1343ec6ffc1aSdandb close 1344ec6ffc1aSdantv delete 1345ec6ffc1aSdan 1346ec6ffc1aSdantestvfs tv -default 1 1347ec6ffc1aSdanfaultsim_delete_and_reopen 1348ec6ffc1aSdandb func a_string a_string 1349ec6ffc1aSdando_execsql_test pager1-11.1 { 1350ec6ffc1aSdan PRAGMA cache_size = 10; 1351ec6ffc1aSdan BEGIN; 1352ec6ffc1aSdan CREATE TABLE zz(top PRIMARY KEY); 1353ec6ffc1aSdan INSERT INTO zz VALUES(a_string(222)); 1354ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1355ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1356ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1357ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1358ec6ffc1aSdan INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz; 1359ec6ffc1aSdan COMMIT; 1360ec6ffc1aSdan BEGIN; 1361ec6ffc1aSdan UPDATE zz SET top = a_string(345); 1362ec6ffc1aSdan} {} 1363ec6ffc1aSdan 1364ec6ffc1aSdanproc lockout {method args} { return SQLITE_IOERR } 1365ec6ffc1aSdantv script lockout 1366ec6ffc1aSdantv filter {xWrite xTruncate xSync} 1367ec6ffc1aSdando_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}} 1368ec6ffc1aSdan 1369ec6ffc1aSdantv script {} 1370ec6ffc1aSdando_test pager1-11.3 { 1371ec6ffc1aSdan sqlite3 db2 test.db 1372ec6ffc1aSdan execsql { 1373ec6ffc1aSdan PRAGMA journal_mode = TRUNCATE; 1374ec6ffc1aSdan PRAGMA integrity_check; 1375ec6ffc1aSdan } db2 1376ec6ffc1aSdan} {truncate ok} 1377ec6ffc1aSdando_test pager1-11.4 { 1378ec6ffc1aSdan db2 close 1379ec6ffc1aSdan file size test.db-journal 1380ec6ffc1aSdan} {0} 1381ec6ffc1aSdando_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} 1382f9b4419dSdandb close 1383f9b4419dSdantv delete 1384ec6ffc1aSdan 1385f9b4419dSdan#------------------------------------------------------------------------- 1386f9b4419dSdan# Test "PRAGMA page_size" 1387f9b4419dSdan# 1388f9b4419dSdanforeach pagesize { 1389f9b4419dSdan 512 1024 2048 4096 8192 16384 32768 1390f9b4419dSdan} { 1391f9b4419dSdan faultsim_delete_and_reopen 1392f9b4419dSdan 1393f9b4419dSdan do_test pager1-12.$pagesize.1 { 1394f9b4419dSdan sqlite3 db2 test.db 1395f9b4419dSdan execsql " 1396f9b4419dSdan PRAGMA page_size = $pagesize; 1397f9b4419dSdan CREATE VIEW v AS SELECT * FROM sqlite_master; 1398f9b4419dSdan " db2 1399f9b4419dSdan file size test.db 1400f9b4419dSdan } $pagesize 1401f9b4419dSdan do_test pager1-12.$pagesize.2 { 1402f9b4419dSdan sqlite3 db2 test.db 1403f9b4419dSdan execsql { 1404f9b4419dSdan SELECT count(*) FROM v; 1405f9b4419dSdan PRAGMA main.page_size; 1406f9b4419dSdan } db2 1407f9b4419dSdan } [list 1 $pagesize] 1408f9b4419dSdan do_test pager1-12.$pagesize.3 { 1409f9b4419dSdan execsql { 1410f9b4419dSdan SELECT count(*) FROM v; 1411f9b4419dSdan PRAGMA main.page_size; 1412f9b4419dSdan } 1413f9b4419dSdan } [list 1 $pagesize] 1414f9b4419dSdan db2 close 1415f9b4419dSdan} 1416dca321aeSdan 1417d353331aSdan#------------------------------------------------------------------------- 1418d353331aSdan# Test specal "PRAGMA journal_mode=PERSIST" test cases. 1419d353331aSdan# 1420d353331aSdan# pager1-13.1.*: This tests a special case encountered in persistent 1421d353331aSdan# journal mode: If the journal associated with a transaction 1422d353331aSdan# is smaller than the journal file (because a previous 1423d353331aSdan# transaction left a very large non-hot journal file in the 1424d353331aSdan# file-system), then SQLite has to be careful that there is 1425d353331aSdan# not a journal-header left over from a previous transaction 1426d353331aSdan# immediately following the journal content just written. 1427d353331aSdan# If there is, and the process crashes so that the journal 1428d353331aSdan# becomes a hot-journal and must be rolled back by another 1429d353331aSdan# process, there is a danger that the other process may roll 1430d353331aSdan# back the aborted transaction, then continue copying data 1431d353331aSdan# from an older transaction from the remainder of the journal. 1432d353331aSdan# See the syncJournal() function for details. 1433d353331aSdan# 1434d353331aSdan# pager1-13.2.*: Same test as the previous. This time, throw an index into 1435d353331aSdan# the mix to make the integrity-check more likely to catch 1436d353331aSdan# errors. 1437d353331aSdan# 1438d353331aSdantestvfs tv -default 1 1439d353331aSdantv script xSyncCb 1440d353331aSdantv filter xSync 1441d353331aSdanproc xSyncCb {method filename args} { 1442d353331aSdan set t [file tail $filename] 1443d353331aSdan if {$t == "test.db"} faultsim_save 1444d353331aSdan return SQLITE_OK 1445d353331aSdan} 1446d353331aSdanfaultsim_delete_and_reopen 1447d353331aSdandb func a_string a_string 1448e91a54e1Sdan 1449d353331aSdan# The UPDATE statement at the end of this test case creates a really big 1450d353331aSdan# journal. Since the cache-size is only 10 pages, the journal contains 1451d353331aSdan# frequent journal headers. 1452d353331aSdan# 1453d353331aSdando_execsql_test pager1-13.1.1 { 1454d353331aSdan PRAGMA page_size = 1024; 1455d353331aSdan PRAGMA journal_mode = PERSIST; 1456d353331aSdan PRAGMA cache_size = 10; 1457d353331aSdan BEGIN; 1458d353331aSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); 1459d353331aSdan INSERT INTO t1 VALUES(NULL, a_string(400)); 1460d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 2 */ 1461d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 4 */ 1462d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 8 */ 1463d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 16 */ 1464d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 32 */ 1465d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 64 */ 1466d353331aSdan INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 128 */ 1467d353331aSdan COMMIT; 1468d353331aSdan UPDATE t1 SET b = a_string(400); 1469d353331aSdan} {persist} 1470d353331aSdan 1471d353331aSdan# Run transactions of increasing sizes. Eventually, one (or more than one) 1472d353331aSdan# of these will write just enough content that one of the old headers created 1473d353331aSdan# by the transaction in the block above lies immediately after the content 1474d353331aSdan# journalled by the current transaction. 1475d353331aSdan# 1476d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1477d353331aSdan do_execsql_test pager1-13.1.2.$nUp.1 { 1478d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1479d353331aSdan } {} 1480d353331aSdan do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok} 1481d353331aSdan 1482d353331aSdan # Try to access the snapshot of the file-system. 1483d353331aSdan # 1484d353331aSdan sqlite3 db2 sv_test.db 1485d353331aSdan do_test pager1-13.1.2.$nUp.3 { 1486d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1487d353331aSdan } [expr {128*400 - ($nUp-1)}] 1488d353331aSdan do_test pager1-13.1.2.$nUp.4 { 1489d353331aSdan execsql { PRAGMA integrity_check } db2 1490d353331aSdan } {ok} 1491d353331aSdan db2 close 1492d353331aSdan} 1493d353331aSdan 1494d353331aSdan# Same test as above. But this time with an index on the table. 1495d353331aSdan# 1496d353331aSdando_execsql_test pager1-13.2.1 { 1497d353331aSdan CREATE INDEX i1 ON t1(b); 1498d353331aSdan UPDATE t1 SET b = a_string(400); 1499d353331aSdan} {} 1500d353331aSdanfor {set nUp 1} {$nUp<64} {incr nUp} { 1501d353331aSdan do_execsql_test pager1-13.2.2.$nUp.1 { 1502d353331aSdan UPDATE t1 SET b = a_string(399) WHERE a <= $nUp 1503d353331aSdan } {} 1504d353331aSdan do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok} 1505d353331aSdan sqlite3 db2 sv_test.db 1506d353331aSdan do_test pager1-13.2.2.$nUp.3 { 1507d353331aSdan execsql { SELECT sum(length(b)) FROM t1 } db2 1508d353331aSdan } [expr {128*400 - ($nUp-1)}] 1509d353331aSdan do_test pager1-13.2.2.$nUp.4 { 1510d353331aSdan execsql { PRAGMA integrity_check } db2 1511d353331aSdan } {ok} 1512d353331aSdan db2 close 1513d353331aSdan} 1514d353331aSdan 1515d353331aSdandb close 1516d353331aSdantv delete 1517d353331aSdan 1518d353331aSdan#------------------------------------------------------------------------- 1519d353331aSdan# Test specal "PRAGMA journal_mode=OFF" test cases. 1520d353331aSdan# 1521d353331aSdanfaultsim_delete_and_reopen 1522d353331aSdando_execsql_test pager1-14.1.1 { 1523d353331aSdan PRAGMA journal_mode = OFF; 1524d353331aSdan CREATE TABLE t1(a, b); 1525d353331aSdan BEGIN; 1526d353331aSdan INSERT INTO t1 VALUES(1, 2); 1527d353331aSdan COMMIT; 1528d353331aSdan SELECT * FROM t1; 1529d353331aSdan} {off 1 2} 1530d353331aSdando_catchsql_test pager1-14.1.2 { 1531d353331aSdan BEGIN; 1532d353331aSdan INSERT INTO t1 VALUES(3, 4); 1533d353331aSdan ROLLBACK; 1534d353331aSdan} {0 {}} 1535d353331aSdando_execsql_test pager1-14.1.3 { 1536d353331aSdan SELECT * FROM t1; 1537d353331aSdan} {1 2 3 4} 1538d353331aSdando_catchsql_test pager1-14.1.4 { 1539d353331aSdan BEGIN; 1540d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1541d353331aSdan INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; 1542d353331aSdan} {1 {PRIMARY KEY must be unique}} 1543d353331aSdando_execsql_test pager1-14.1.5 { 1544d353331aSdan COMMIT; 1545d353331aSdan SELECT * FROM t1; 1546d353331aSdan} {1 2 3 4 2 2 4 4} 1547d353331aSdan 1548c8ce3972Sdan#------------------------------------------------------------------------- 1549c8ce3972Sdan# Test opening and closing the pager sub-system with different values 1550c8ce3972Sdan# for the sqlite3_vfs.szOsFile variable. 1551c8ce3972Sdan# 1552c8ce3972Sdanfaultsim_delete_and_reopen 1553c8ce3972Sdando_execsql_test pager1-15.0 { 1554c8ce3972Sdan CREATE TABLE tx(y, z); 1555c8ce3972Sdan INSERT INTO tx VALUES('Ayutthaya', 'Beijing'); 1556c8ce3972Sdan INSERT INTO tx VALUES('London', 'Tokyo'); 1557c8ce3972Sdan} {} 1558c8ce3972Sdandb close 1559c8ce3972Sdanfor {set i 0} {$i<513} {incr i 3} { 1560c8ce3972Sdan testvfs tv -default 1 -szosfile $i 1561c8ce3972Sdan sqlite3 db test.db 1562c8ce3972Sdan do_execsql_test pager1-15.$i.1 { 1563c8ce3972Sdan SELECT * FROM tx; 1564c8ce3972Sdan } {Ayutthaya Beijing London Tokyo} 1565c8ce3972Sdan db close 1566c8ce3972Sdan tv delete 1567c8ce3972Sdan} 1568c8ce3972Sdan 1569c8ce3972Sdan#------------------------------------------------------------------------- 1570c8ce3972Sdan# Check that it is not possible to open a database file if the full path 1571c8ce3972Sdan# to the associated journal file will be longer than sqlite3_vfs.mxPathname. 1572c8ce3972Sdan# 1573c8ce3972Sdantestvfs tv -default 1 1574c8ce3972Sdantv script xOpenCb 1575c8ce3972Sdantv filter xOpen 1576c8ce3972Sdanproc xOpenCb {method filename} { 1577c8ce3972Sdan set ::file_len [string length $filename] 1578c8ce3972Sdan} 1579c8ce3972Sdansqlite3 db test.db 1580c8ce3972Sdandb close 1581c8ce3972Sdantv delete 1582c8ce3972Sdan 1583c8ce3972Sdanfor {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} { 1584c8ce3972Sdan testvfs tv -default 1 -mxpathname $ii 1585c8ce3972Sdan 1586c8ce3972Sdan # The length of the full path to file "test.db-journal" is ($::file_len+8). 1587c8ce3972Sdan # If the configured sqlite3_vfs.mxPathname value greater than or equal to 1588c8ce3972Sdan # this, then the file can be opened. Otherwise, it cannot. 1589c8ce3972Sdan # 1590c8ce3972Sdan if {$ii >= [expr $::file_len+8]} { 1591c8ce3972Sdan set res {0 {}} 1592c8ce3972Sdan } else { 1593c8ce3972Sdan set res {1 {unable to open database file}} 1594c8ce3972Sdan } 1595c8ce3972Sdan 1596c8ce3972Sdan do_test pager1-16.1.$ii { 1597c8ce3972Sdan list [catch { sqlite3 db test.db } msg] $msg 1598c8ce3972Sdan } $res 1599c8ce3972Sdan 1600c8ce3972Sdan catch {db close} 1601c8ce3972Sdan tv delete 1602c8ce3972Sdan} 1603c8ce3972Sdan 1604c8ce3972Sdan#------------------------------------------------------------------------- 1605c8ce3972Sdan# Test "PRAGMA omit_readlock". 1606c8ce3972Sdan# 1607c8ce3972Sdan# pager1-17.$tn.1.*: Test that if a second connection has an open 1608c8ce3972Sdan# read-transaction, it is not usually possible to write 1609c8ce3972Sdan# the database. 1610c8ce3972Sdan# 1611c8ce3972Sdan# pager1-17.$tn.2.*: Test that if the second connection was opened with 1612c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, and 1613c8ce3972Sdan# "PRAGMA omit_readlock = 1" is executed before attaching 1614c8ce3972Sdan# the database and opening a read-transaction on it, it is 1615c8ce3972Sdan# possible to write the db. 1616c8ce3972Sdan# 1617c8ce3972Sdan# pager1-17.$tn.3.*: Test that if the second connection was *not* opened with 1618c8ce3972Sdan# the SQLITE_OPEN_READONLY flag, executing 1619c8ce3972Sdan# "PRAGMA omit_readlock = 1" has no effect. 1620c8ce3972Sdan# 1621c8ce3972Sdando_multiclient_test tn { 1622c8ce3972Sdan do_test pager1-17.$tn.1.1 { 1623c8ce3972Sdan sql1 { 1624c8ce3972Sdan CREATE TABLE t1(a, b); 1625c8ce3972Sdan INSERT INTO t1 VALUES(1, 2); 1626c8ce3972Sdan } 1627c8ce3972Sdan sql2 { 1628c8ce3972Sdan BEGIN; 1629c8ce3972Sdan SELECT * FROM t1; 1630c8ce3972Sdan } 1631c8ce3972Sdan } {1 2} 1632c8ce3972Sdan do_test pager1-17.$tn.1.2 { 1633c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1634c8ce3972Sdan } {1 {database is locked}} 1635c8ce3972Sdan do_test pager1-17.$tn.1.3 { 1636c8ce3972Sdan sql2 { COMMIT } 1637c8ce3972Sdan sql1 { INSERT INTO t1 VALUES(3, 4) } 1638c8ce3972Sdan } {} 1639c8ce3972Sdan 1640c8ce3972Sdan do_test pager1-17.$tn.2.1 { 1641c8ce3972Sdan code2 { 1642c8ce3972Sdan db2 close 1643c8ce3972Sdan sqlite3 db2 :memory: -readonly 1 1644c8ce3972Sdan } 1645c8ce3972Sdan sql2 { 1646c8ce3972Sdan PRAGMA omit_readlock = 1; 1647c8ce3972Sdan ATTACH 'test.db' AS two; 1648c8ce3972Sdan BEGIN; 1649c8ce3972Sdan SELECT * FROM t1; 1650c8ce3972Sdan } 1651c8ce3972Sdan } {1 2 3 4} 1652c8ce3972Sdan do_test pager1-17.$tn.2.2 { sql1 "INSERT INTO t1 VALUES(5, 6)" } {} 1653c8ce3972Sdan do_test pager1-17.$tn.2.3 { sql2 "SELECT * FROM t1" } {1 2 3 4} 1654c8ce3972Sdan do_test pager1-17.$tn.2.4 { sql2 "COMMIT ; SELECT * FROM t1" } {1 2 3 4 5 6} 1655c8ce3972Sdan 1656c8ce3972Sdan do_test pager1-17.$tn.3.1 { 1657c8ce3972Sdan code2 { 1658c8ce3972Sdan db2 close 1659c8ce3972Sdan sqlite3 db2 :memory: 1660c8ce3972Sdan } 1661c8ce3972Sdan sql2 { 1662c8ce3972Sdan PRAGMA omit_readlock = 1; 1663c8ce3972Sdan ATTACH 'test.db' AS two; 1664c8ce3972Sdan BEGIN; 1665c8ce3972Sdan SELECT * FROM t1; 1666c8ce3972Sdan } 1667c8ce3972Sdan } {1 2 3 4 5 6} 1668c8ce3972Sdan do_test pager1-17.$tn.3.2 { 1669c8ce3972Sdan csql1 { INSERT INTO t1 VALUES(3, 4) } 1670c8ce3972Sdan } {1 {database is locked}} 1671c8ce3972Sdan do_test pager1-17.$tn.3.3 { sql2 COMMIT } {} 1672c8ce3972Sdan} 1673c8ce3972Sdan 1674c8ce3972Sdan#------------------------------------------------------------------------- 1675c8ce3972Sdan# Test the pagers response to the b-tree layer requesting illegal page 1676c8ce3972Sdan# numbers: 1677c8ce3972Sdan# 1678c8ce3972Sdan# + The locking page, 1679c8ce3972Sdan# + Page 0, 1680c8ce3972Sdan# + A page with a page number greater than (2^31-1). 1681c8ce3972Sdan# 1682c8ce3972Sdando_test pager1-18.1 { 1683c8ce3972Sdan faultsim_delete_and_reopen 1684c8ce3972Sdan db func a_string a_string 1685c8ce3972Sdan execsql { 1686c8ce3972Sdan PRAGMA page_size = 1024; 1687c8ce3972Sdan CREATE TABLE t1(a, b); 1688c8ce3972Sdan INSERT INTO t1 VALUES(a_string(500), a_string(200)); 1689c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1690c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1691c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1692c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1693c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1694c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1695c8ce3972Sdan INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1; 1696c8ce3972Sdan } 1697c8ce3972Sdan} {} 1698c8ce3972Sdando_test pager1-18.2 { 1699c8ce3972Sdan set root [db one "SELECT rootpage FROM sqlite_master"] 1700c8ce3972Sdan set lockingpage [expr (0x10000/1024) + 1] 1701c8ce3972Sdan execsql { 1702c8ce3972Sdan PRAGMA writable_schema = 1; 1703c8ce3972Sdan UPDATE sqlite_master SET rootpage = $lockingpage; 1704c8ce3972Sdan } 1705c8ce3972Sdan sqlite3 db2 test.db 1706c8ce3972Sdan catchsql { SELECT count(*) FROM t1 } db2 1707c8ce3972Sdan} {1 {database disk image is malformed}} 1708c8ce3972Sdandb2 close 1709c8ce3972Sdando_test pager1-18.3 { 1710c8ce3972Sdan execsql { 1711c8ce3972Sdan CREATE TABLE t2(x); 1712c8ce3972Sdan INSERT INTO t2 VALUES(a_string(5000)); 1713c8ce3972Sdan } 1714c8ce3972Sdan set pgno [expr ([file size test.db] / 1024)-2] 1715c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 00000000 1716c8ce3972Sdan sqlite3 db2 test.db 1717c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1718c8ce3972Sdan} {1 {database disk image is malformed}} 1719c8ce3972Sdandb2 close 1720c8ce3972Sdando_test pager1-18.4 { 1721c8ce3972Sdan hexio_write test.db [expr ($pgno-1)*1024] 90000000 1722c8ce3972Sdan sqlite3 db2 test.db 1723c8ce3972Sdan catchsql { SELECT length(x) FROM t2 } db2 1724c8ce3972Sdan} {1 {database disk image is malformed}} 1725c8ce3972Sdandb2 close 1726c8ce3972Sdando_test pager1-18.5 { 1727c8ce3972Sdan sqlite3 db "" 1728c8ce3972Sdan execsql { 1729c8ce3972Sdan CREATE TABLE t1(a, b); 1730c8ce3972Sdan CREATE TABLE t2(a, b); 1731c8ce3972Sdan PRAGMA writable_schema = 1; 1732c8ce3972Sdan UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; 1733c8ce3972Sdan PRAGMA writable_schema = 0; 1734c8ce3972Sdan ALTER TABLE t1 RENAME TO x1; 1735c8ce3972Sdan } 1736c8ce3972Sdan catchsql { SELECT * FROM x1 } 1737ba3cbf3dSdan} {1 {database disk image is malformed}} 1738c8ce3972Sdandb close 1739c8ce3972Sdan 1740ba3cbf3dSdando_test pager1-18.6 { 1741ba3cbf3dSdan faultsim_delete_and_reopen 1742ba3cbf3dSdan db func a_string a_string 1743ba3cbf3dSdan execsql { 1744ba3cbf3dSdan PRAGMA page_size = 1024; 1745ba3cbf3dSdan CREATE TABLE t1(x); 1746ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1747ba3cbf3dSdan INSERT INTO t1 VALUES(a_string(800)); 1748ba3cbf3dSdan } 1749ba3cbf3dSdan 1750ba3cbf3dSdan set root [db one "SELECT rootpage FROM sqlite_master"] 1751ba3cbf3dSdan db close 1752ba3cbf3dSdan 1753ba3cbf3dSdan hexio_write test.db [expr ($root-1)*1024 + 8] 00000000 1754ba3cbf3dSdan sqlite3 db test.db 1755ba3cbf3dSdan catchsql { SELECT length(x) FROM t1 } 1756ba3cbf3dSdan} {1 {database disk image is malformed}} 1757ba3cbf3dSdan 1758ba3cbf3dSdando_test pager1-19.1 { 1759ba3cbf3dSdan sqlite3 db "" 1760ba3cbf3dSdan db func a_string a_string 1761ba3cbf3dSdan execsql { 1762ba3cbf3dSdan PRAGMA page_size = 512; 1763ba3cbf3dSdan PRAGMA auto_vacuum = 1; 1764ba3cbf3dSdan CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1765ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1766ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1767ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1768ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1769ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1770ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1771ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1772ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1773ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1774ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1775ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1776ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1777ba3cbf3dSdan ); 1778ba3cbf3dSdan CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, 1779ba3cbf3dSdan ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, 1780ba3cbf3dSdan ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, 1781ba3cbf3dSdan da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn, 1782ba3cbf3dSdan ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en, 1783ba3cbf3dSdan fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn, 1784ba3cbf3dSdan ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn, 1785ba3cbf3dSdan ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn, 1786ba3cbf3dSdan ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix, 1787ba3cbf3dSdan ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn, 1788ba3cbf3dSdan ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn, 1789ba3cbf3dSdan la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln, 1790ba3cbf3dSdan ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn 1791ba3cbf3dSdan ); 1792ba3cbf3dSdan INSERT INTO t1(aa) VALUES( a_string(100000) ); 1793ba3cbf3dSdan INSERT INTO t2(aa) VALUES( a_string(100000) ); 1794ba3cbf3dSdan VACUUM; 1795ba3cbf3dSdan } 1796ba3cbf3dSdan} {} 1797ba3cbf3dSdan 17986b63ab47Sdan#------------------------------------------------------------------------- 17996b63ab47Sdan# Test a couple of special cases that come up while committing 18006b63ab47Sdan# transactions: 18016b63ab47Sdan# 18026b63ab47Sdan# pager1-20.1.*: Committing an in-memory database transaction when the 18036b63ab47Sdan# database has not been modified at all. 18046b63ab47Sdan# 18056b63ab47Sdan# pager1-20.2.*: As above, but with a normal db in exclusive-locking mode. 18066b63ab47Sdan# 18076b63ab47Sdan# pager1-20.3.*: Committing a transaction in WAL mode where the database has 18086b63ab47Sdan# been modified, but all dirty pages have been flushed to 18096b63ab47Sdan# disk before the commit. 18106b63ab47Sdan# 18116b63ab47Sdando_test pager1-20.1.1 { 18126b63ab47Sdan catch {db close} 18136b63ab47Sdan sqlite3 db :memory: 18146b63ab47Sdan execsql { 18156b63ab47Sdan CREATE TABLE one(two, three); 18166b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 18176b63ab47Sdan } 18186b63ab47Sdan} {} 18196b63ab47Sdando_test pager1-20.1.2 { 18206b63ab47Sdan execsql { 18216b63ab47Sdan BEGIN EXCLUSIVE; 18226b63ab47Sdan COMMIT; 18236b63ab47Sdan } 18246b63ab47Sdan} {} 18256b63ab47Sdan 18266b63ab47Sdando_test pager1-20.2.1 { 18276b63ab47Sdan faultsim_delete_and_reopen 18286b63ab47Sdan execsql { 18296b63ab47Sdan PRAGMA locking_mode = exclusive; 18306b63ab47Sdan PRAGMA journal_mode = persist; 18316b63ab47Sdan CREATE TABLE one(two, three); 18326b63ab47Sdan INSERT INTO one VALUES('a', 'b'); 18336b63ab47Sdan } 18346b63ab47Sdan} {exclusive persist} 18356b63ab47Sdando_test pager1-20.2.2 { 18366b63ab47Sdan execsql { 18376b63ab47Sdan BEGIN EXCLUSIVE; 18386b63ab47Sdan COMMIT; 18396b63ab47Sdan } 18406b63ab47Sdan} {} 18416b63ab47Sdan 18426b63ab47Sdando_test pager1-20.3.1 { 18436b63ab47Sdan faultsim_delete_and_reopen 18446b63ab47Sdan db func a_string a_string 18456b63ab47Sdan execsql { 18466b63ab47Sdan PRAGMA cache_size = 10; 18476b63ab47Sdan PRAGMA journal_mode = wal; 18486b63ab47Sdan BEGIN; 18496b63ab47Sdan CREATE TABLE t1(x); 18506b63ab47Sdan CREATE TABLE t2(y); 18516b63ab47Sdan INSERT INTO t1 VALUES(a_string(800)); 18526b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */ 18536b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */ 18546b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */ 18556b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */ 18566b63ab47Sdan INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */ 18576b63ab47Sdan COMMIT; 18586b63ab47Sdan } 18596b63ab47Sdan} {wal} 18606b63ab47Sdando_test pager1-20.3.2 { 18616b63ab47Sdan proc recursive_select {id} { 18626b63ab47Sdan db eval {SELECT rowid, x FROM t1 WHERE rowid = ($id-1)} { 18636b63ab47Sdan recursive_select $rowid 18646b63ab47Sdan } 18656b63ab47Sdan } 18666b63ab47Sdan execsql { 18676b63ab47Sdan BEGIN; 18686b63ab47Sdan INSERT INTO t2 VALUES('xxxx'); 18696b63ab47Sdan } 18706b63ab47Sdan recursive_select 32 18716b63ab47Sdan execsql COMMIT 18726b63ab47Sdan} {} 18736b63ab47Sdan 187489ccf448Sdan#------------------------------------------------------------------------- 187589ccf448Sdan# Test that a WAL database may not be opened if: 187689ccf448Sdan# 187789ccf448Sdan# pager1-21.1.*: The VFS has an iVersion less than 2, or 187889ccf448Sdan# pager1-21.2.*: The VFS does not provide xShmXXX() methods. 187989ccf448Sdan# 188089ccf448Sdando_test pager1-21.0 { 188189ccf448Sdan faultsim_delete_and_reopen 188289ccf448Sdan execsql { 188389ccf448Sdan PRAGMA journal_mode = WAL; 188489ccf448Sdan CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); 188589ccf448Sdan INSERT INTO ko DEFAULT VALUES; 188689ccf448Sdan } 188789ccf448Sdan} {wal} 188889ccf448Sdando_test pager1-21.1 { 188989ccf448Sdan testvfs tv -noshm 1 189089ccf448Sdan sqlite3 db2 test.db -vfs tv 189189ccf448Sdan catchsql { SELECT * FROM ko } db2 189289ccf448Sdan} {1 {unable to open database file}} 189389ccf448Sdandb2 close 189489ccf448Sdantv delete 189589ccf448Sdando_test pager1-21.2 { 189689ccf448Sdan testvfs tv -iversion 1 189789ccf448Sdan sqlite3 db2 test.db -vfs tv 189889ccf448Sdan catchsql { SELECT * FROM ko } db2 189989ccf448Sdan} {1 {unable to open database file}} 190089ccf448Sdandb2 close 190189ccf448Sdantv delete 190289ccf448Sdan 190389ccf448Sdan#------------------------------------------------------------------------- 190489ccf448Sdan# Test that a "PRAGMA wal_checkpoint": 190589ccf448Sdan# 190689ccf448Sdan# pager1-22.1.*: is a no-op on a non-WAL db, and 190789ccf448Sdan# pager1-22.2.*: does not cause xSync calls with a synchronous=off db. 190889ccf448Sdan# 190989ccf448Sdando_test pager1-22.1.1 { 191089ccf448Sdan faultsim_delete_and_reopen 191189ccf448Sdan execsql { 191289ccf448Sdan CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def'); 191389ccf448Sdan INSERT INTO ko DEFAULT VALUES; 191489ccf448Sdan } 191589ccf448Sdan execsql { PRAGMA wal_checkpoint } 191689ccf448Sdan} {} 191789ccf448Sdando_test pager1-22.2.1 { 191889ccf448Sdan testvfs tv -default 1 191989ccf448Sdan tv filter xSync 192089ccf448Sdan tv script xSyncCb 192189ccf448Sdan proc xSyncCb {args} {incr ::synccount} 192289ccf448Sdan set ::synccount 0 192389ccf448Sdan sqlite3 db test.db 192489ccf448Sdan execsql { 192589ccf448Sdan PRAGMA synchronous = off; 192689ccf448Sdan PRAGMA journal_mode = WAL; 192789ccf448Sdan INSERT INTO ko DEFAULT VALUES; 192889ccf448Sdan } 192989ccf448Sdan execsql { PRAGMA wal_checkpoint } 193089ccf448Sdan set synccount 193189ccf448Sdan} {0} 193289ccf448Sdandb close 193389ccf448Sdantv delete 193489ccf448Sdan 193589ccf448Sdan#------------------------------------------------------------------------- 193689ccf448Sdan# Tests for changing journal mode. 193789ccf448Sdan# 193889ccf448Sdan# pager1-23.1.*: Test that when changing from PERSIST to DELETE mode, 193989ccf448Sdan# the journal file is deleted. 194089ccf448Sdan# 194189ccf448Sdan# pager1-23.2.*: Same test as above, but while a shared lock is held 194289ccf448Sdan# on the database file. 194389ccf448Sdan# 194489ccf448Sdan# pager1-23.3.*: Same test as above, but while a reserved lock is held 194589ccf448Sdan# on the database file. 194689ccf448Sdan# 194789ccf448Sdan# pager1-23.4.*: And, for fun, while holding an exclusive lock. 194889ccf448Sdan# 194989ccf448Sdan# pager1-23.5.*: Try to set various different journal modes with an 195089ccf448Sdan# in-memory database (only MEMORY and OFF should work). 195189ccf448Sdan# 1952*d0b0d4dcSdan# pager1-23.6.*: Try to set locking_mode=normal on an in-memory database 1953*d0b0d4dcSdan# (doesn't work - in-memory databases always use 1954*d0b0d4dcSdan# locking_mode=exclusive). 1955*d0b0d4dcSdan# 195689ccf448Sdando_test pager1-23.1.1 { 195789ccf448Sdan faultsim_delete_and_reopen 195889ccf448Sdan execsql { 195989ccf448Sdan PRAGMA journal_mode = PERSIST; 196089ccf448Sdan CREATE TABLE t1(a, b); 196189ccf448Sdan } 196289ccf448Sdan file exists test.db-journal 196389ccf448Sdan} {1} 196489ccf448Sdando_test pager1-23.1.2 { 196589ccf448Sdan execsql { PRAGMA journal_mode = DELETE } 196689ccf448Sdan file exists test.db-journal 196789ccf448Sdan} {0} 196889ccf448Sdan 196989ccf448Sdando_test pager1-23.2.1 { 197089ccf448Sdan execsql { 197189ccf448Sdan PRAGMA journal_mode = PERSIST; 197289ccf448Sdan INSERT INTO t1 VALUES('Canberra', 'ACT'); 197389ccf448Sdan } 197489ccf448Sdan db eval { SELECT * FROM t1 } { 197589ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 197689ccf448Sdan } 197789ccf448Sdan execsql { PRAGMA journal_mode } 197889ccf448Sdan} {delete} 197989ccf448Sdando_test pager1-23.2.2 { 198089ccf448Sdan file exists test.db-journal 198189ccf448Sdan} {0} 198289ccf448Sdan 198389ccf448Sdando_test pager1-23.3.1 { 198489ccf448Sdan execsql { 198589ccf448Sdan PRAGMA journal_mode = PERSIST; 198689ccf448Sdan INSERT INTO t1 VALUES('Darwin', 'NT'); 198789ccf448Sdan BEGIN IMMEDIATE; 198889ccf448Sdan } 198989ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 199089ccf448Sdan execsql { PRAGMA journal_mode } 199189ccf448Sdan} {delete} 199289ccf448Sdando_test pager1-23.3.2 { 199389ccf448Sdan file exists test.db-journal 199489ccf448Sdan} {0} 199589ccf448Sdando_test pager1-23.3.3 { 199689ccf448Sdan execsql COMMIT 199789ccf448Sdan} {} 199889ccf448Sdan 199989ccf448Sdando_test pager1-23.4.1 { 200089ccf448Sdan execsql { 200189ccf448Sdan PRAGMA journal_mode = PERSIST; 200289ccf448Sdan INSERT INTO t1 VALUES('Adelaide', 'SA'); 200389ccf448Sdan BEGIN EXCLUSIVE; 200489ccf448Sdan } 200589ccf448Sdan db eval { PRAGMA journal_mode = DELETE } 200689ccf448Sdan execsql { PRAGMA journal_mode } 200789ccf448Sdan} {delete} 200889ccf448Sdando_test pager1-23.4.2 { 200989ccf448Sdan file exists test.db-journal 201089ccf448Sdan} {0} 201189ccf448Sdando_test pager1-23.4.3 { 201289ccf448Sdan execsql COMMIT 201389ccf448Sdan} {} 201489ccf448Sdan 201589ccf448Sdando_test pager1-23.5.1 { 201689ccf448Sdan faultsim_delete_and_reopen 201789ccf448Sdan sqlite3 db :memory: 201889ccf448Sdan} {} 201989ccf448Sdanforeach {tn mode possible} { 202089ccf448Sdan 2 off 1 202189ccf448Sdan 3 memory 1 202289ccf448Sdan 4 persist 0 202389ccf448Sdan 5 delete 0 202489ccf448Sdan 6 wal 0 202589ccf448Sdan 7 truncate 0 202689ccf448Sdan} { 202789ccf448Sdan do_test pager1-23.5.$tn.1 { 202889ccf448Sdan execsql "PRAGMA journal_mode = off" 202989ccf448Sdan execsql "PRAGMA journal_mode = $mode" 203089ccf448Sdan } [if $possible {list $mode} {list off}] 203189ccf448Sdan do_test pager1-23.5.$tn.2 { 203289ccf448Sdan execsql "PRAGMA journal_mode = memory" 203389ccf448Sdan execsql "PRAGMA journal_mode = $mode" 203489ccf448Sdan } [if $possible {list $mode} {list memory}] 203589ccf448Sdan} 2036*d0b0d4dcSdando_test pager1-23.6.1 { 203789ccf448Sdan execsql {PRAGMA locking_mode = normal} 203889ccf448Sdan} {exclusive} 2039*d0b0d4dcSdando_test pager1-23.6.2 { 204089ccf448Sdan execsql {PRAGMA locking_mode = exclusive} 204189ccf448Sdan} {exclusive} 2042*d0b0d4dcSdando_test pager1-23.6.3 { 204389ccf448Sdan execsql {PRAGMA locking_mode} 204489ccf448Sdan} {exclusive} 2045*d0b0d4dcSdando_test pager1-23.6.4 { 204689ccf448Sdan execsql {PRAGMA main.locking_mode} 204789ccf448Sdan} {exclusive} 20486b63ab47Sdan 2049*d0b0d4dcSdan#------------------------------------------------------------------------- 2050*d0b0d4dcSdan# 2051*d0b0d4dcSdando_test pager1-24.1.1 { 2052*d0b0d4dcSdan faultsim_delete_and_reopen 2053*d0b0d4dcSdan db func a_string a_string 2054*d0b0d4dcSdan execsql { 2055*d0b0d4dcSdan PRAGMA cache_size = 10; 2056*d0b0d4dcSdan PRAGMA auto_vacuum = FULL; 2057*d0b0d4dcSdan CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z)); 2058*d0b0d4dcSdan CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z)); 2059*d0b0d4dcSdan INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600)); 2060*d0b0d4dcSdan INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2; 2061*d0b0d4dcSdan INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2; 2062*d0b0d4dcSdan INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2; 2063*d0b0d4dcSdan INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2; 2064*d0b0d4dcSdan INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2; 2065*d0b0d4dcSdan INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2; 2066*d0b0d4dcSdan INSERT INTO x1 SELECT * FROM x2; 2067*d0b0d4dcSdan } 2068*d0b0d4dcSdan} {} 2069*d0b0d4dcSdanproc recursive_select {id {script {}}} { 2070*d0b0d4dcSdan set cnt 0 2071*d0b0d4dcSdan db eval {SELECT rowid, x,y,z FROM x2 WHERE rowid = ($id-1)} { 2072*d0b0d4dcSdan recursive_select $rowid $script 2073*d0b0d4dcSdan incr cnt 2074*d0b0d4dcSdan } 2075*d0b0d4dcSdan if {$cnt==0} { eval $script } 2076*d0b0d4dcSdan} 2077*d0b0d4dcSdando_test pager1-24.1.2 { 2078*d0b0d4dcSdan execsql { 2079*d0b0d4dcSdan BEGIN; 2080*d0b0d4dcSdan DELETE FROM x1 WHERE rowid<32; 2081*d0b0d4dcSdan } 2082*d0b0d4dcSdan recursive_select 64 2083*d0b0d4dcSdan} {} 2084*d0b0d4dcSdando_test pager1-24.1.3 { 2085*d0b0d4dcSdan execsql { 2086*d0b0d4dcSdan UPDATE x1 SET z = a_string(300) WHERE rowid>40; 2087*d0b0d4dcSdan COMMIT; 2088*d0b0d4dcSdan PRAGMA integrity_check; 2089*d0b0d4dcSdan SELECT count(*) FROM x1; 2090*d0b0d4dcSdan } 2091*d0b0d4dcSdan} {ok 33} 2092*d0b0d4dcSdan 2093*d0b0d4dcSdando_test pager1-24.1.4 { 2094*d0b0d4dcSdan execsql { 2095*d0b0d4dcSdan DELETE FROM x1; 2096*d0b0d4dcSdan INSERT INTO x1 SELECT * FROM x2; 2097*d0b0d4dcSdan BEGIN; 2098*d0b0d4dcSdan DELETE FROM x1 WHERE rowid<32; 2099*d0b0d4dcSdan UPDATE x1 SET z = a_string(299) WHERE rowid>40; 2100*d0b0d4dcSdan } 2101*d0b0d4dcSdan recursive_select 64 {db eval COMMIT} 2102*d0b0d4dcSdan execsql { 2103*d0b0d4dcSdan PRAGMA integrity_check; 2104*d0b0d4dcSdan SELECT count(*) FROM x1; 2105*d0b0d4dcSdan } 2106*d0b0d4dcSdan} {ok 33} 2107*d0b0d4dcSdan 2108*d0b0d4dcSdando_test pager1-24.1.5 { 2109*d0b0d4dcSdan execsql { 2110*d0b0d4dcSdan DELETE FROM x1; 2111*d0b0d4dcSdan INSERT INTO x1 SELECT * FROM x2; 2112*d0b0d4dcSdan } 2113*d0b0d4dcSdan recursive_select 64 { db eval {CREATE TABLE x3(x, y, z)} } 2114*d0b0d4dcSdan execsql { SELECT * FROM x3 } 2115*d0b0d4dcSdan} {} 2116*d0b0d4dcSdan 2117*d0b0d4dcSdan#------------------------------------------------------------------------- 2118*d0b0d4dcSdan# 2119*d0b0d4dcSdando_test pager1-25-1 { 2120*d0b0d4dcSdan faultsim_delete_and_reopen 2121*d0b0d4dcSdan execsql { 2122*d0b0d4dcSdan BEGIN; 2123*d0b0d4dcSdan SAVEPOINT abc; 2124*d0b0d4dcSdan CREATE TABLE t1(a, b); 2125*d0b0d4dcSdan ROLLBACK TO abc; 2126*d0b0d4dcSdan COMMIT; 2127*d0b0d4dcSdan } 2128*d0b0d4dcSdan db close 2129*d0b0d4dcSdan} {} 2130*d0b0d4dcSdanbreakpoint 2131*d0b0d4dcSdando_test pager1-25-2 { 2132*d0b0d4dcSdan faultsim_delete_and_reopen 2133*d0b0d4dcSdan execsql { 2134*d0b0d4dcSdan SAVEPOINT abc; 2135*d0b0d4dcSdan CREATE TABLE t1(a, b); 2136*d0b0d4dcSdan ROLLBACK TO abc; 2137*d0b0d4dcSdan COMMIT; 2138*d0b0d4dcSdan } 2139*d0b0d4dcSdan db close 2140*d0b0d4dcSdan} {} 21416b63ab47Sdan 2142d353331aSdanfinish_test 2143