1# 2010 May 03 2# 3# The author disclaims copyright to this source code. In place of 4# a legal notice, here is a blessing: 5# 6# May you do good and not evil. 7# May you find forgiveness for yourself and forgive others. 8# May you share freely, never taking more than you give. 9# 10#*********************************************************************** 11# This file implements regression tests for SQLite library. The 12# focus of this file is testing the operation of the library in 13# "PRAGMA journal_mode=WAL" mode. 14# 15 16set testdir [file dirname $argv0] 17source $testdir/tester.tcl 18source $testdir/malloc_common.tcl 19source $testdir/lock_common.tcl 20 21ifcapable !wal {finish_test ; return } 22 23#------------------------------------------------------------------------- 24# This test case, walfault-1-*, simulates faults while executing a 25# 26# PRAGMA journal_mode = WAL; 27# 28# statement immediately after creating a new database. 29# 30do_test walfault-1-pre-1 { 31 faultsim_delete_and_reopen 32 faultsim_save_and_close 33} {} 34do_faultsim_test walfault-1 -prep { 35 faultsim_restore_and_reopen 36} -body { 37 db eval { PRAGMA main.journal_mode = WAL } 38} -test { 39 40 faultsim_test_result {0 wal} 41 42 # Test that the connection that encountered an error as part of 43 # "PRAGMA journal_mode = WAL" and a new connection use the same 44 # journal mode when accessing the database. 45 # 46 # If "PRAGMA journal_mode" is executed immediately, connection [db] (the 47 # one that hit the error in journal_mode="WAL") might return "wal" even 48 # if it failed to switch the database to WAL mode. This is not considered 49 # a problem. When it tries to read the database, connection [db] correctly 50 # recognizes that it is a rollback database and switches back to a 51 # rollback compatible journal mode. 52 # 53 if {[permutation] != "inmemory_journal"} { 54 set jm [db one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}] 55 sqlite3 db2 test.db 56 set jm2 [db2 one {SELECT * FROM sqlite_master ; PRAGMA main.journal_mode}] 57 db2 close 58 59 if { $jm!=$jm2 } { error "Journal modes do not match: $jm $jm2" } 60 if { $testrc==0 && $jm!="wal" } { error "Journal mode is not WAL" } 61 } 62} 63 64#-------------------------------------------------------------------------- 65# Test case walfault-2-* tests fault injection during recovery of a 66# short WAL file (a dozen frames or thereabouts). 67# 68do_test walfault-2-pre-1 { 69 sqlite3 db test.db 70 execsql { 71 PRAGMA journal_mode = WAL; 72 BEGIN; 73 CREATE TABLE x(y, z, UNIQUE(y, z)); 74 INSERT INTO x VALUES(randomblob(100), randomblob(100)); 75 COMMIT; 76 PRAGMA wal_checkpoint; 77 78 INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 79 INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 80 INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; 81 } 82 execsql { 83 SELECT count(*) FROM x 84 } 85} {8} 86do_test walfault-2-pre-2 { 87 faultsim_save_and_close 88 faultsim_restore_and_reopen 89 execsql { SELECT count(*) FROM x } 90} {8} 91do_faultsim_test walfault-2 -prep { 92 faultsim_restore_and_reopen 93} -body { 94 execsql { SELECT count(*) FROM x } 95} -test { 96 faultsim_test_result {0 8} 97 faultsim_integrity_check 98} 99 100#-------------------------------------------------------------------------- 101# Test fault injection while writing and checkpointing a small WAL file. 102# 103do_test walfault-3-pre-1 { 104 sqlite3 db test.db 105 execsql { 106 PRAGMA auto_vacuum = 1; 107 PRAGMA journal_mode = WAL; 108 CREATE TABLE abc(a PRIMARY KEY); 109 INSERT INTO abc VALUES(randomblob(1500)); 110 } 111 db close 112 faultsim_save_and_close 113} {} 114do_faultsim_test walfault-3 -prep { 115 faultsim_restore_and_reopen 116} -body { 117 db eval { 118 DELETE FROM abc; 119 PRAGMA wal_checkpoint; 120 } 121} -test { 122 faultsim_test_result {0 {}} 123} 124 125 126#-------------------------------------------------------------------------- 127# 128if {[permutation] != "inmemory_journal"} { 129 faultsim_delete_and_reopen 130 faultsim_save_and_close 131 do_faultsim_test walfault-4 -prep { 132 faultsim_restore_and_reopen 133 } -body { 134 execsql { 135 PRAGMA journal_mode = WAL; 136 CREATE TABLE t1(a PRIMARY KEY, b); 137 INSERT INTO t1 VALUES('a', 'b'); 138 PRAGMA wal_checkpoint; 139 SELECT * FROM t1; 140 } 141 } -test { 142 faultsim_test_result {0 {wal a b}} 143 faultsim_integrity_check 144 } 145} 146 147#-------------------------------------------------------------------------- 148# 149do_test walfault-5-pre-1 { 150 faultsim_delete_and_reopen 151 execsql { 152 PRAGMA page_size = 512; 153 PRAGMA journal_mode = WAL; 154 } 155 faultsim_save_and_close 156} {} 157do_faultsim_test walfault-5 -faults shmerr* -prep { 158 faultsim_restore_and_reopen 159 execsql { PRAGMA wal_autocheckpoint = 0 } 160 shmfault filter xShmMap 161} -body { 162 execsql { 163 CREATE TABLE t1(x); 164 BEGIN; 165 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 166 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 167 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 168 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 169 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 170 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 171 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 172 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 173 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 174 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 175 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 176 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 177 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 178 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 179 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 180 COMMIT; 181 SELECT count(*) FROM t1; 182 } 183} -test { 184 faultsim_test_result {0 16384} 185 faultsim_integrity_check 186} 187 188#-------------------------------------------------------------------------- 189# 190do_test walfault-6-pre-1 { 191 faultsim_delete_and_reopen 192 execsql { 193 PRAGMA page_size = 512; 194 PRAGMA journal_mode = WAL; 195 PRAGMA wal_autocheckpoint = 0; 196 CREATE TABLE t1(x); 197 BEGIN; 198 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 199 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 200 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 201 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 202 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 203 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 204 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 205 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 206 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 207 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 208 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 209 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 210 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 211 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 212 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 213 COMMIT; 214 } 215 faultsim_save_and_close 216} {} 217do_faultsim_test walfault-6 -faults shmerr* -prep { 218 faultsim_restore_and_reopen 219 shmfault filter xShmMap 220} -body { 221 execsql { SELECT count(*) FROM t1 } 222} -test { 223 faultsim_test_result {0 16384} 224 faultsim_integrity_check 225 set n [db one {SELECT count(*) FROM t1}] 226 if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" } 227} 228 229#-------------------------------------------------------------------------- 230# 231do_test walfault-7-pre-1 { 232 faultsim_delete_and_reopen 233 execsql { 234 PRAGMA page_size = 512; 235 PRAGMA journal_mode = WAL; 236 PRAGMA wal_autocheckpoint = 0; 237 CREATE TABLE t1(x); 238 BEGIN; 239 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 240 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 241 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 242 COMMIT; 243 } 244 faultsim_save_and_close 245} {} 246do_faultsim_test walfault-7 -prep { 247 faultsim_restore_and_reopen 248} -body { 249 execsql { SELECT count(*) FROM t1 } 250} -test { 251 faultsim_test_result {0 4} 252 set n [db one {SELECT count(*) FROM t1}] 253 if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" } 254} 255 256#-------------------------------------------------------------------------- 257# 258do_test walfault-8-pre-1 { 259 faultsim_delete_and_reopen 260 execsql { 261 PRAGMA journal_mode = WAL; 262 CREATE TABLE abc(a PRIMARY KEY); 263 INSERT INTO abc VALUES(randomblob(900)); 264 } 265 faultsim_save_and_close 266} {} 267do_faultsim_test walfault-8 -prep { 268 faultsim_restore_and_reopen 269 execsql { PRAGMA cache_size = 10 } 270} -body { 271 execsql { 272 BEGIN; 273 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 274 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 275 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 276 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 277 ROLLBACK; 278 SELECT count(*) FROM abc; 279 } 280} -test { 281 faultsim_test_result {0 1} 282 283 faultsim_integrity_check 284 catch { db eval ROLLBACK } 285 faultsim_integrity_check 286 287 set n [db one {SELECT count(*) FROM abc}] 288 if {$n != 1} { error "Incorrect number of rows: $n" } 289} 290 291#-------------------------------------------------------------------------- 292# 293do_test walfault-9-pre-1 { 294 faultsim_delete_and_reopen 295 execsql { 296 PRAGMA journal_mode = WAL; 297 CREATE TABLE abc(a PRIMARY KEY); 298 INSERT INTO abc VALUES(randomblob(900)); 299 } 300 faultsim_save_and_close 301} {} 302do_faultsim_test walfault-9 -prep { 303 #if {$iFail<73} { set iFail 73 } 304 #if {$iFail>73} { exit } 305 306 faultsim_restore_and_reopen 307 execsql { PRAGMA cache_size = 10 } 308} -body { 309 execsql { 310 BEGIN; 311 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 312 SAVEPOINT spoint; 313 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 314 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 315 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 316 ROLLBACK TO spoint; 317 COMMIT; 318 SELECT count(*) FROM abc; 319 } 320} -test { 321 faultsim_test_result {0 2} 322 faultsim_integrity_check 323 324 catch { db eval { ROLLBACK TO spoint } } 325 catch { db eval { COMMIT } } 326 set n [db one {SELECT count(*) FROM abc}] 327 if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } 328} 329 330do_test walfault-10-pre1 { 331 faultsim_delete_and_reopen 332 execsql { 333 PRAGMA journal_mode = WAL; 334 PRAGMA wal_autocheckpoint = 0; 335 CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB); 336 CREATE INDEX zzzz ON z(zzz); 337 INSERT INTO z VALUES(NULL, randomblob(800)); 338 INSERT INTO z VALUES(NULL, randomblob(800)); 339 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 340 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 341 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 342 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 343 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 344 } 345 faultsim_save_and_close 346} {} 347do_faultsim_test walfault-10 -prep { 348 faultsim_restore_and_reopen 349 execsql { 350 PRAGMA cache_size = 10; 351 BEGIN; 352 UPDATE z SET zzz = randomblob(799); 353 } 354 355 set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1] 356 sqlite3_step $::stmt 357} -body { 358 execsql { INSERT INTO z VALUES(NULL, NULL) } 359} -test { 360 sqlite3_finalize $::stmt 361 faultsim_integrity_check 362 363 faultsim_test_result {0 {}} 364 catch { db eval { ROLLBACK } } 365 faultsim_integrity_check 366 367 set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}] 368 if {$n != "64 51200"} { error "Incorrect data: $n" } 369} 370 371#-------------------------------------------------------------------------- 372# Test fault injection while checkpointing a large WAL file, if the 373# checkpoint is the first operation run after opening the database. 374# This means that some of the required wal-index pages are mapped as part of 375# the checkpoint process, which means there are a few more opportunities 376# for IO errors. 377# 378# To speed this up, IO errors are only simulated within xShmMap() calls. 379# 380do_test walfault-11-pre-1 { 381 sqlite3 db test.db 382 execsql { 383 PRAGMA journal_mode = WAL; 384 PRAGMA wal_autocheckpoint = 0; 385 BEGIN; 386 CREATE TABLE abc(a PRIMARY KEY); 387 INSERT INTO abc VALUES(randomblob(1500)); 388 INSERT INTO abc VALUES(randomblob(1500)); 389 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4 390 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 8 391 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 16 392 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 32 393 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 64 394 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 128 395 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 256 396 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 512 397 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 1024 398 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 2048 399 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4096 400 COMMIT; 401 } 402 faultsim_save_and_close 403} {} 404do_faultsim_test walfault-11 -faults shmerr* -prep { 405 catch { db2 close } 406 faultsim_restore_and_reopen 407 shmfault filter xShmMap 408} -body { 409 db eval { SELECT count(*) FROM abc } 410 sqlite3 db2 test.db -vfs shmfault 411 db2 eval { PRAGMA wal_checkpoint } 412} -test { 413 faultsim_test_result {0 {}} 414} 415 416#------------------------------------------------------------------------- 417# Test the handling of the various IO/OOM/SHM errors that may occur during 418# a log recovery operation undertaken as part of a call to 419# sqlite3_wal_checkpoint(). 420# 421do_test walfault-12-pre-1 { 422 faultsim_delete_and_reopen 423 execsql { 424 PRAGMA journal_mode = WAL; 425 PRAGMA wal_autocheckpoint = 0; 426 BEGIN; 427 CREATE TABLE abc(a PRIMARY KEY); 428 INSERT INTO abc VALUES(randomblob(1500)); 429 INSERT INTO abc VALUES(randomblob(1500)); 430 COMMIT; 431 } 432 faultsim_save_and_close 433} {} 434do_faultsim_test walfault-12 -prep { 435 if {[info commands shmfault] == ""} { 436 testvfs shmfault -default true 437 } 438 faultsim_restore_and_reopen 439 db eval { SELECT * FROM sqlite_master } 440 shmfault shm test.db [string repeat "\000" 40] 441} -body { 442 set rc [sqlite3_wal_checkpoint db] 443 if {$rc != "SQLITE_OK"} { error [sqlite3_errmsg db] } 444} -test { 445 db close 446 faultsim_test_result {0 {}} 447} 448 449 450finish_test 451