176ed3bc0Sdan# 2010 May 03 276ed3bc0Sdan# 376ed3bc0Sdan# The author disclaims copyright to this source code. In place of 476ed3bc0Sdan# a legal notice, here is a blessing: 576ed3bc0Sdan# 676ed3bc0Sdan# May you do good and not evil. 776ed3bc0Sdan# May you find forgiveness for yourself and forgive others. 876ed3bc0Sdan# May you share freely, never taking more than you give. 976ed3bc0Sdan# 1076ed3bc0Sdan#*********************************************************************** 1176ed3bc0Sdan# This file implements regression tests for SQLite library. The 1276ed3bc0Sdan# focus of this file is testing the operation of the library in 1376ed3bc0Sdan# "PRAGMA journal_mode=WAL" mode. 1476ed3bc0Sdan# 1576ed3bc0Sdan 1676ed3bc0Sdanset testdir [file dirname $argv0] 1776ed3bc0Sdansource $testdir/tester.tcl 1876ed3bc0Sdansource $testdir/malloc_common.tcl 1976ed3bc0Sdan 2076ed3bc0Sdanifcapable !wal {finish_test ; return } 2176ed3bc0Sdan 22a4bc123fSdan#------------------------------------------------------------------------- 23a4bc123fSdan# This test case, walfault-1-*, simulates faults while executing a 24a4bc123fSdan# 25a4bc123fSdan# PRAGMA journal_mode = WAL; 26a4bc123fSdan# 27a4bc123fSdan# statement immediately after creating a new database. 28a4bc123fSdan# 29a4bc123fSdando_test walfault-1-pre-1 { 30a4bc123fSdan db close 318521abfdSdan file delete -force test.db test.db-wal test.db-journal 32a4bc123fSdan faultsim_save_and_close 33a4bc123fSdan} {} 34a4bc123fSdando_faultsim_test walfault-1 -prep { 35a4bc123fSdan faultsim_restore_and_reopen 368521abfdSdan} -body { 378521abfdSdan db eval { PRAGMA main.journal_mode = WAL } 388521abfdSdan} -test { 398521abfdSdan 408521abfdSdan faultsim_test_result {0 wal} 418521abfdSdan 428521abfdSdan # Test that the connection that encountered an error as part of 438521abfdSdan # "PRAGMA journal_mode = WAL" and a new connection use the same 448521abfdSdan # journal mode when accessing the database. 458521abfdSdan # 468521abfdSdan # If "PRAGMA journal_mode" is executed immediately, connection [db] (the 478521abfdSdan # one that hit the error in journal_mode="WAL") might return "wal" even 488521abfdSdan # if it failed to switch the database to WAL mode. This is not considered 498521abfdSdan # a problem. When it tries to read the database, connection [db] correctly 508521abfdSdan # recognizes that it is a rollback database and switches back to a 518521abfdSdan # rollback compatible journal mode. 528521abfdSdan # 538521abfdSdan set jm [db one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}] 548521abfdSdan sqlite3 db2 test.db 558521abfdSdan set jm2 [db2 one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}] 568521abfdSdan db2 close 578521abfdSdan 588521abfdSdan if { $jm!=$jm2 } { error "Journal modes do not match: $jm $jm2" } 598521abfdSdan if { $testrc==0 && $jm!="wal" } { error "Journal mode is not WAL" } 6076ed3bc0Sdan} 6176ed3bc0Sdan 62a4bc123fSdan#-------------------------------------------------------------------------- 63a4bc123fSdan# Test case walfault-2-* tests fault injection during recovery of a 64a4bc123fSdan# short WAL file (a dozen frames or thereabouts). 65a4bc123fSdan# 66a4bc123fSdando_test walfault-2-pre-1 { 67a4bc123fSdan sqlite3 db test.db 685e9e482fSdan execsql { 695e9e482fSdan PRAGMA journal_mode = WAL; 705e9e482fSdan BEGIN; 715e9e482fSdan CREATE TABLE x(y, z, UNIQUE(y, z)); 725e9e482fSdan INSERT INTO x VALUES(randomblob(100), randomblob(100)); 735e9e482fSdan COMMIT; 745e9e482fSdan PRAGMA wal_checkpoint; 755e9e482fSdan 765e9e482fSdan INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 775e9e482fSdan INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 785e9e482fSdan INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 795e9e482fSdan } 80a4bc123fSdan execsql { 81a4bc123fSdan SELECT count(*) FROM x 82a4bc123fSdan } 83a4bc123fSdan} {8} 84a4bc123fSdando_test walfault-2-pre-2 { 85a4bc123fSdan faultsim_save_and_close 86a4bc123fSdan faultsim_restore_and_reopen 87a4bc123fSdan execsql { SELECT count(*) FROM x } 88a4bc123fSdan} {8} 89a4bc123fSdando_faultsim_test walfault-2 -prep { 90a4bc123fSdan faultsim_restore_and_reopen 91a4bc123fSdan} -body { 92a4bc123fSdan execsql { SELECT count(*) FROM x } 93a4bc123fSdan} -test { 94a4bc123fSdan faultsim_test_result {0 8} 95*1f55e28dSdan faultsim_integrity_check 965e9e482fSdan} 975e9e482fSdan 98a4bc123fSdan#-------------------------------------------------------------------------- 99a4bc123fSdan# Test fault injection while writing and checkpointing a small WAL file. 100a4bc123fSdan# 101a4bc123fSdando_test walfault-3-pre-1 { 102a4bc123fSdan sqlite3 db test.db 103a4bc123fSdan execsql { 1049a6b4e9aSdan PRAGMA auto_vacuum = 1; 1059a6b4e9aSdan PRAGMA journal_mode = WAL; 1069a6b4e9aSdan CREATE TABLE abc(a PRIMARY KEY); 1079a6b4e9aSdan INSERT INTO abc VALUES(randomblob(1500)); 108a4bc123fSdan } 109a4bc123fSdan db close 110a4bc123fSdan faultsim_save_and_close 111a4bc123fSdan} {} 112a4bc123fSdan 113a4bc123fSdando_faultsim_test walfault-3 -prep { 114a4bc123fSdan faultsim_restore_and_reopen 115a4bc123fSdan} -body { 116a4bc123fSdan db eval { 1179a6b4e9aSdan DELETE FROM abc; 1189a6b4e9aSdan PRAGMA wal_checkpoint; 1199a6b4e9aSdan } 120a4bc123fSdan} -test { 121a4bc123fSdan faultsim_test_result {0 {}} 122a4bc123fSdan} 1239a6b4e9aSdan 124c7991bdfSdanfile delete -force test.db test.db-wal test.db-journal 125*1f55e28dSdanfaultsim_save_and_close 126*1f55e28dSdando_faultsim_test walfault-4 -prep { 127*1f55e28dSdan faultsim_restore_and_reopen 128*1f55e28dSdan} -body { 129*1f55e28dSdan execsql { 130c7991bdfSdan PRAGMA journal_mode = WAL; 131c7991bdfSdan CREATE TABLE t1(a PRIMARY KEY, b); 132c7991bdfSdan INSERT INTO t1 VALUES('a', 'b'); 133c7991bdfSdan PRAGMA wal_checkpoint; 134*1f55e28dSdan SELECT * FROM t1; 135*1f55e28dSdan } 136*1f55e28dSdan} -test { 137*1f55e28dSdan faultsim_test_result {0 {wal a b}} 138*1f55e28dSdan faultsim_integrity_check 139c7991bdfSdan} 14076ed3bc0Sdan 141*1f55e28dSdando_test walfault-5-pre-1 { 142*1f55e28dSdan catch { db close } 143*1f55e28dSdan file delete -force test.db test.db-wal test.db-journal 144*1f55e28dSdan sqlite3 db test.db 145*1f55e28dSdan execsql { 1468f6097c2Sdan PRAGMA page_size = 512; 1478f6097c2Sdan PRAGMA journal_mode = WAL; 148*1f55e28dSdan } 149*1f55e28dSdan faultsim_save_and_close 150*1f55e28dSdan} {} 151*1f55e28dSdando_faultsim_test walfault-5 -faults shmerr* -prep { 152*1f55e28dSdan faultsim_restore_and_reopen 153*1f55e28dSdan execsql { PRAGMA wal_autocheckpoint = 0 } 154*1f55e28dSdan shmfault filter xShmSize 155*1f55e28dSdan} -body { 156*1f55e28dSdan execsql { 1578f6097c2Sdan CREATE TABLE t1(x); 1588f6097c2Sdan BEGIN; 1598f6097c2Sdan INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 1608f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 1618f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 1628f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 1638f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 1648f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 1658f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 1668f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 1678f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 1688f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 1698f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 1708f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 1718f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 1728f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 1738f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 1748f6097c2Sdan COMMIT; 175*1f55e28dSdan SELECT count(*) FROM t1; 176*1f55e28dSdan } 177*1f55e28dSdan} -test { 178*1f55e28dSdan faultsim_test_result {0 16384} 179*1f55e28dSdan faultsim_integrity_check 1808f6097c2Sdan} 1818f6097c2Sdan 182*1f55e28dSdan 183*1f55e28dSdando_test walfault-6-pre-1 { 184*1f55e28dSdan catch { db close } 185*1f55e28dSdan file delete -force test.db test.db-wal test.db-journal 186*1f55e28dSdan sqlite3 db test.db 187*1f55e28dSdan execsql { 1888f6097c2Sdan PRAGMA page_size = 512; 1898f6097c2Sdan PRAGMA journal_mode = WAL; 1908f6097c2Sdan PRAGMA wal_autocheckpoint = 0; 1918f6097c2Sdan CREATE TABLE t1(x); 1928f6097c2Sdan BEGIN; 1938f6097c2Sdan INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 1948f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 1958f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 1968f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 1978f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 1988f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 1998f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 2008f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 2018f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 2028f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 2038f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 2048f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 2058f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 2068f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 2078f6097c2Sdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 2088f6097c2Sdan COMMIT; 2098f6097c2Sdan } 210*1f55e28dSdan faultsim_save_and_close 211*1f55e28dSdan} {} 212*1f55e28dSdando_faultsim_test walfault-6 -faults shmerr* -prep { 213*1f55e28dSdan faultsim_restore_and_reopen 214*1f55e28dSdan shmfault filter xShmSize 215*1f55e28dSdan} -body { 216*1f55e28dSdan execsql { SELECT count(*) FROM t1 } 217*1f55e28dSdan} -test { 218*1f55e28dSdan faultsim_test_result {0 16384} 219*1f55e28dSdan faultsim_integrity_check 220*1f55e28dSdan set n [db one {SELECT count(*) FROM t1}] 221*1f55e28dSdan if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" } 2228f6097c2Sdan} 2238f6097c2Sdan 224*1f55e28dSdando_test walfault-7-pre-1 { 225*1f55e28dSdan faultsim_delete_and_reopen 226*1f55e28dSdan execsql { 227a861469aSdan PRAGMA page_size = 512; 228a861469aSdan PRAGMA journal_mode = WAL; 229a861469aSdan PRAGMA wal_autocheckpoint = 0; 230a861469aSdan CREATE TABLE t1(x); 231a861469aSdan BEGIN; 232a861469aSdan INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 233a861469aSdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 234a861469aSdan INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 235a861469aSdan COMMIT; 236a861469aSdan } 237*1f55e28dSdan faultsim_save_and_close 238*1f55e28dSdan} {} 239*1f55e28dSdando_faultsim_test walfault-7 -prep { 240*1f55e28dSdan faultsim_restore_and_reopen 241*1f55e28dSdan} -body { 242*1f55e28dSdan execsql { SELECT count(*) FROM t1 } 243*1f55e28dSdan} -test { 244*1f55e28dSdan faultsim_test_result {0 4} 245*1f55e28dSdan set n [db one {SELECT count(*) FROM t1}] 246*1f55e28dSdan if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" } 247a861469aSdan} 248a861469aSdan 249*1f55e28dSdando_test walfault-8-pre-1 { 250*1f55e28dSdan faultsim_delete_and_reopen 251*1f55e28dSdan execsql { 252d41a29a6Sdan PRAGMA journal_mode = WAL; 253d41a29a6Sdan CREATE TABLE abc(a PRIMARY KEY); 254d41a29a6Sdan INSERT INTO abc VALUES(randomblob(900)); 255*1f55e28dSdan } 256*1f55e28dSdan faultsim_save_and_close 257*1f55e28dSdan} {} 258*1f55e28dSdando_faultsim_test walfault-8 -prep { 259*1f55e28dSdan faultsim_restore_and_reopen 260*1f55e28dSdan execsql { PRAGMA cache_size = 10 } 261*1f55e28dSdan} -body { 262*1f55e28dSdan execsql { 263d41a29a6Sdan BEGIN; 264d41a29a6Sdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 265*1f55e28dSdan --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 266*1f55e28dSdan --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 267*1f55e28dSdan --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 268d41a29a6Sdan ROLLBACK; 269*1f55e28dSdan SELECT count(*) FROM abc; 270*1f55e28dSdan } 271*1f55e28dSdan} -test { 272*1f55e28dSdan faultsim_test_result {0 1} 273*1f55e28dSdan 274*1f55e28dSdan faultsim_integrity_check 275*1f55e28dSdan catch { db eval ROLLBACK } 276*1f55e28dSdan faultsim_integrity_check 277*1f55e28dSdan 278*1f55e28dSdan set n [db one {SELECT count(*) FROM abc}] 279*1f55e28dSdan if {$n != 1} { error "Incorrect number of rows: $n" } 280d41a29a6Sdan} 281d41a29a6Sdan 282*1f55e28dSdando_test walfault-9-pre-1 { 283*1f55e28dSdan faultsim_delete_and_reopen 284*1f55e28dSdan execsql { 2858067adbcSdan PRAGMA journal_mode = WAL; 2868067adbcSdan CREATE TABLE abc(a PRIMARY KEY); 2878067adbcSdan INSERT INTO abc VALUES(randomblob(900)); 288*1f55e28dSdan } 289*1f55e28dSdan faultsim_save_and_close 290*1f55e28dSdan} {} 291*1f55e28dSdando_faultsim_test walfault-9 -prep { 292*1f55e28dSdan #if {$iFail<73} { set iFail 73 } 293*1f55e28dSdan #if {$iFail>73} { exit } 294*1f55e28dSdan 295*1f55e28dSdan faultsim_restore_and_reopen 296*1f55e28dSdan execsql { PRAGMA cache_size = 10 } 297*1f55e28dSdan} -body { 298*1f55e28dSdan execsql { 2998067adbcSdan BEGIN; 3008067adbcSdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 3018067adbcSdan SAVEPOINT spoint; 3028067adbcSdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 3038067adbcSdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 3048067adbcSdan INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 3058067adbcSdan ROLLBACK TO spoint; 3068067adbcSdan COMMIT; 307*1f55e28dSdan SELECT count(*) FROM abc; 308*1f55e28dSdan } 309*1f55e28dSdan} -test { 310*1f55e28dSdan faultsim_test_result {0 2} 311*1f55e28dSdan faultsim_integrity_check 312*1f55e28dSdan 313*1f55e28dSdan catch { db eval { ROLLBACK TO spoint } } 314*1f55e28dSdan catch { db eval { COMMIT } } 315*1f55e28dSdan set n [db one {SELECT count(*) FROM abc}] 316*1f55e28dSdan if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } 3178067adbcSdan} 3188067adbcSdan 31965f2ac58Sdan#------------------------------------------------------------------------- 32065f2ac58Sdan# When a database is checkpointed, SQLite does the following: 32165f2ac58Sdan# 32265f2ac58Sdan# 1. xShmLock(CHECKPOINT) to lock the WAL. 32365f2ac58Sdan# 2. xShmGet(-1) to get a mapping to read the wal-index header. 32465f2ac58Sdan# 3. If the mapping obtained in (2) is not large enough to cover the 32565f2ac58Sdan# entire wal-index, call xShmGet(nReq) to get a larger mapping. 32665f2ac58Sdan# 4. Do the checkpoint. 32765f2ac58Sdan# 5. Release the lock and mapping. 32865f2ac58Sdan# 32965f2ac58Sdan# This test case tests the outcome of an IO error in step 2. 33065f2ac58Sdan# 33165f2ac58Sdanproc shmfault_vfs_cb_6 {method args} { 33265f2ac58Sdan switch -- $::shm_state { 33365f2ac58Sdan 0 { return SQLITE_OK } 33465f2ac58Sdan 1 { 33565f2ac58Sdan if {$method == "xShmGet"} { 33665f2ac58Sdan set ::wal_index [tvfs shm [lindex $args 0]] 33765f2ac58Sdan tvfs shm [lindex $args 0] [string range $::wal_index 0 65535] 33865f2ac58Sdan set ::shm_state 2 33965f2ac58Sdan } 34065f2ac58Sdan } 34165f2ac58Sdan 2 { 34265f2ac58Sdan if {$method == "xShmGet"} { 34365f2ac58Sdan tvfs shm [lindex $args 0] $::wal_index 34465f2ac58Sdan return SQLITE_IOERR 34565f2ac58Sdan } 34665f2ac58Sdan } 34765f2ac58Sdan } 34865f2ac58Sdan return SQLITE_OK 34965f2ac58Sdan} 35065f2ac58Sdando_test walfault-shm-6.1 { 35165f2ac58Sdan set ::shm_state 0 352*1f55e28dSdan testvfs tvfs 353*1f55e28dSdan tvfs script shmfault_vfs_cb_6 35465f2ac58Sdan 35565f2ac58Sdan sqlite3 db test.db -vfs tvfs 35665f2ac58Sdan sqlite3 db2 test.db -vfs tvfs 35765f2ac58Sdan 35865f2ac58Sdan execsql { 35965f2ac58Sdan PRAGMA journal_mode = WAL; 36065f2ac58Sdan PRAGMA wal_autocheckpoint = 0; 36165f2ac58Sdan CREATE TABLE t1(x); 36265f2ac58Sdan INSERT INTO t1 VALUES(randomblob(900)); 36365f2ac58Sdan } 36465f2ac58Sdan} {wal 0} 36565f2ac58Sdando_test walfault-shm-6.2 { 36665f2ac58Sdan execsql { 36765f2ac58Sdan PRAGMA wal_autocheckpoint = 0; 36865f2ac58Sdan BEGIN; 36965f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */ 37065f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */ 37165f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */ 37265f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */ 37365f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */ 37465f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */ 37565f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */ 37665f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */ 37765f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */ 37865f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */ 37965f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */ 38065f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */ 38165f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */ 38265f2ac58Sdan INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */ 38365f2ac58Sdan COMMIT; 38465f2ac58Sdan } db2 38565f2ac58Sdan} {0} 38665f2ac58Sdando_test walfault-shm-6.3 { 38765f2ac58Sdan set ::shm_state 1 38865f2ac58Sdan catchsql { PRAGMA wal_checkpoint } db2 38965f2ac58Sdan} {1 {disk I/O error}} 39065f2ac58Sdanset ::shm_state 0 39165f2ac58Sdandb close 39265f2ac58Sdandb2 close 39365f2ac58Sdantvfs delete 39465f2ac58Sdanunset -nocomplain ::wal_index ::shm_state 39565f2ac58Sdan 39676ed3bc0Sdanfinish_test 397c7991bdfSdan 398