github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/walfault.test (about) 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 16 set testdir [file dirname $argv0] 17 source $testdir/tester.tcl 18 source $testdir/malloc_common.tcl 19 source $testdir/lock_common.tcl 20 21 ifcapable !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 # 30 do_test walfault-1-pre-1 { 31 faultsim_delete_and_reopen 32 faultsim_save_and_close 33 } {} 34 do_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 # 68 do_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} 86 do_test walfault-2-pre-2 { 87 faultsim_save_and_close 88 faultsim_restore_and_reopen 89 execsql { SELECT count(*) FROM x } 90 } {8} 91 do_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 # 103 do_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 } {} 114 do_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 set {} {} 122 } -test { 123 faultsim_test_result {0 {}} 124 } 125 126 #-------------------------------------------------------------------------- 127 # 128 if {[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 auto_vacuum = 0; 136 PRAGMA journal_mode = WAL; 137 CREATE TABLE t1(a PRIMARY KEY, b); 138 INSERT INTO t1 VALUES('a', 'b'); 139 PRAGMA wal_checkpoint; 140 SELECT * FROM t1; 141 } 142 } -test { 143 # Update: The following changed from {0 {wal 0 7 7 a b}} as a result 144 # of PSOW being set by default. 145 faultsim_test_result {0 {wal 0 5 5 a b}} 146 faultsim_integrity_check 147 } 148 } 149 150 #-------------------------------------------------------------------------- 151 # 152 do_test walfault-5-pre-1 { 153 faultsim_delete_and_reopen 154 execsql { 155 PRAGMA page_size = 512; 156 PRAGMA journal_mode = WAL; 157 } 158 faultsim_save_and_close 159 } {} 160 do_faultsim_test walfault-5 -faults shmerr* -prep { 161 faultsim_restore_and_reopen 162 execsql { PRAGMA wal_autocheckpoint = 0 } 163 shmfault filter xShmMap 164 } -body { 165 execsql { 166 CREATE TABLE t1(x); 167 BEGIN; 168 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 169 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 170 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 171 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 172 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 173 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 174 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 175 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 176 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 177 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 178 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 179 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 180 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 181 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 182 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 183 COMMIT; 184 SELECT count(*) FROM t1; 185 } 186 } -test { 187 faultsim_test_result {0 16384} 188 faultsim_integrity_check 189 } 190 191 #-------------------------------------------------------------------------- 192 # 193 do_test walfault-6-pre-1 { 194 faultsim_delete_and_reopen 195 execsql { 196 PRAGMA page_size = 512; 197 PRAGMA journal_mode = WAL; 198 PRAGMA wal_autocheckpoint = 0; 199 CREATE TABLE t1(x); 200 BEGIN; 201 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 202 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 203 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 204 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8 */ 205 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16 */ 206 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 32 */ 207 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 64 */ 208 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 128 */ 209 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 256 */ 210 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 512 */ 211 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 1024 */ 212 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2048 */ 213 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4096 */ 214 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */ 215 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */ 216 COMMIT; 217 } 218 faultsim_save_and_close 219 } {} 220 do_faultsim_test walfault-6 -faults shmerr* -prep { 221 faultsim_restore_and_reopen 222 shmfault filter xShmMap 223 } -body { 224 execsql { SELECT count(*) FROM t1 } 225 } -test { 226 faultsim_test_result {0 16384} 227 faultsim_integrity_check 228 set n [db one {SELECT count(*) FROM t1}] 229 if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" } 230 } 231 232 #-------------------------------------------------------------------------- 233 # 234 do_test walfault-7-pre-1 { 235 faultsim_delete_and_reopen 236 execsql { 237 PRAGMA page_size = 512; 238 PRAGMA journal_mode = WAL; 239 PRAGMA wal_autocheckpoint = 0; 240 CREATE TABLE t1(x); 241 BEGIN; 242 INSERT INTO t1 VALUES(randomblob(400)); /* 1 */ 243 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 2 */ 244 INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */ 245 COMMIT; 246 } 247 faultsim_save_and_close 248 } {} 249 do_faultsim_test walfault-7 -prep { 250 faultsim_restore_and_reopen 251 } -body { 252 execsql { SELECT count(*) FROM t1 } 253 } -test { 254 faultsim_test_result {0 4} 255 set n [db one {SELECT count(*) FROM t1}] 256 if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" } 257 } 258 259 #-------------------------------------------------------------------------- 260 # 261 do_test walfault-8-pre-1 { 262 faultsim_delete_and_reopen 263 execsql { 264 PRAGMA journal_mode = WAL; 265 CREATE TABLE abc(a PRIMARY KEY); 266 INSERT INTO abc VALUES(randomblob(900)); 267 } 268 faultsim_save_and_close 269 } {} 270 do_faultsim_test walfault-8 -prep { 271 faultsim_restore_and_reopen 272 execsql { PRAGMA cache_size = 10 } 273 } -body { 274 execsql { 275 BEGIN; 276 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 277 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 278 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 279 --INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 280 ROLLBACK; 281 SELECT count(*) FROM abc; 282 } 283 } -test { 284 faultsim_test_result {0 1} 285 286 faultsim_integrity_check 287 catch { db eval ROLLBACK } 288 faultsim_integrity_check 289 290 set n [db one {SELECT count(*) FROM abc}] 291 if {$n != 1} { error "Incorrect number of rows: $n" } 292 } 293 294 #-------------------------------------------------------------------------- 295 # 296 do_test walfault-9-pre-1 { 297 faultsim_delete_and_reopen 298 execsql { 299 PRAGMA journal_mode = WAL; 300 CREATE TABLE abc(a PRIMARY KEY); 301 INSERT INTO abc VALUES(randomblob(900)); 302 } 303 faultsim_save_and_close 304 } {} 305 do_faultsim_test walfault-9 -prep { 306 #if {$iFail<73} { set iFail 73 } 307 #if {$iFail>73} { exit } 308 309 faultsim_restore_and_reopen 310 execsql { PRAGMA cache_size = 10 } 311 } -body { 312 execsql { 313 BEGIN; 314 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */ 315 SAVEPOINT spoint; 316 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 2 */ 317 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */ 318 INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */ 319 ROLLBACK TO spoint; 320 COMMIT; 321 SELECT count(*) FROM abc; 322 } 323 } -test { 324 faultsim_test_result {0 2} 325 faultsim_integrity_check 326 327 catch { db eval { ROLLBACK TO spoint } } 328 catch { db eval { COMMIT } } 329 set n [db one {SELECT count(*) FROM abc}] 330 if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } 331 } 332 333 do_test walfault-10-pre1 { 334 faultsim_delete_and_reopen 335 execsql { 336 PRAGMA journal_mode = WAL; 337 PRAGMA wal_autocheckpoint = 0; 338 CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB); 339 CREATE INDEX zzzz ON z(zzz); 340 INSERT INTO z VALUES(NULL, randomblob(800)); 341 INSERT INTO z VALUES(NULL, randomblob(800)); 342 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 343 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 344 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 345 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 346 INSERT INTO z SELECT NULL, randomblob(800) FROM z; 347 } 348 faultsim_save_and_close 349 } {} 350 do_faultsim_test walfault-10 -prep { 351 faultsim_restore_and_reopen 352 execsql { 353 PRAGMA cache_size = 10; 354 BEGIN; 355 UPDATE z SET zzz = randomblob(799); 356 } 357 358 set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1] 359 sqlite3_step $::stmt 360 } -body { 361 execsql { INSERT INTO z VALUES(NULL, NULL) } 362 } -test { 363 sqlite3_finalize $::stmt 364 faultsim_integrity_check 365 366 faultsim_test_result {0 {}} 367 catch { db eval { ROLLBACK } } 368 faultsim_integrity_check 369 370 set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}] 371 if {$n != "64 51200"} { error "Incorrect data: $n" } 372 } 373 374 #-------------------------------------------------------------------------- 375 # Test fault injection while checkpointing a large WAL file, if the 376 # checkpoint is the first operation run after opening the database. 377 # This means that some of the required wal-index pages are mapped as part of 378 # the checkpoint process, which means there are a few more opportunities 379 # for IO errors. 380 # 381 # To speed this up, IO errors are only simulated within xShmMap() calls. 382 # 383 do_test walfault-11-pre-1 { 384 sqlite3 db test.db 385 execsql { 386 PRAGMA journal_mode = WAL; 387 PRAGMA wal_autocheckpoint = 0; 388 BEGIN; 389 CREATE TABLE abc(a PRIMARY KEY); 390 INSERT INTO abc VALUES(randomblob(1500)); 391 INSERT INTO abc VALUES(randomblob(1500)); 392 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4 393 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 8 394 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 16 395 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 32 396 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 64 397 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 128 398 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 256 399 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 512 400 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 1024 401 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 2048 402 INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4096 403 COMMIT; 404 } 405 faultsim_save_and_close 406 } {} 407 do_faultsim_test walfault-11 -faults shmerr* -prep { 408 catch { db2 close } 409 faultsim_restore_and_reopen 410 shmfault filter xShmMap 411 } -body { 412 db eval { SELECT count(*) FROM abc } 413 sqlite3 db2 test.db -vfs shmfault 414 db2 eval { PRAGMA wal_checkpoint } 415 set {} {} 416 } -test { 417 faultsim_test_result {0 {}} 418 } 419 420 #------------------------------------------------------------------------- 421 # Test the handling of the various IO/OOM/SHM errors that may occur during 422 # a log recovery operation undertaken as part of a call to 423 # sqlite3_wal_checkpoint(). 424 # 425 do_test walfault-12-pre-1 { 426 faultsim_delete_and_reopen 427 execsql { 428 PRAGMA journal_mode = WAL; 429 PRAGMA wal_autocheckpoint = 0; 430 BEGIN; 431 CREATE TABLE abc(a PRIMARY KEY); 432 INSERT INTO abc VALUES(randomblob(1500)); 433 INSERT INTO abc VALUES(randomblob(1500)); 434 COMMIT; 435 } 436 faultsim_save_and_close 437 } {} 438 do_faultsim_test walfault-12 -prep { 439 if {[info commands shmfault] == ""} { 440 testvfs shmfault -default true 441 } 442 faultsim_restore_and_reopen 443 db eval { SELECT * FROM sqlite_master } 444 shmfault shm test.db [string repeat "\000" 40] 445 } -body { 446 set rc [sqlite3_wal_checkpoint db] 447 if {$rc != "SQLITE_OK"} { error [sqlite3_errmsg db] } 448 } -test { 449 db close 450 faultsim_test_result {0 {}} 451 } 452 453 #------------------------------------------------------------------------- 454 # Test simple recovery, reading and writing a database file using a 455 # heap-memory wal-index. 456 # 457 do_test walfault-13-pre-1 { 458 faultsim_delete_and_reopen 459 execsql { 460 PRAGMA journal_mode = WAL; 461 PRAGMA wal_autocheckpoint = 0; 462 BEGIN; 463 CREATE TABLE abc(a PRIMARY KEY); 464 INSERT INTO abc VALUES(randomblob(1500)); 465 INSERT INTO abc VALUES(randomblob(1500)); 466 COMMIT; 467 } 468 faultsim_save_and_close 469 delete_file sv_test.db-shm 470 } {} 471 472 do_faultsim_test walfault-13.1 -prep { 473 faultsim_restore_and_reopen 474 } -body { 475 db eval { PRAGMA locking_mode = exclusive } 476 db eval { SELECT count(*) FROM abc } 477 } -test { 478 faultsim_test_result {0 2} 479 if {[file exists test.db-shm]} { error "Not using heap-memory mode" } 480 faultsim_integrity_check 481 } 482 483 do_faultsim_test walfault-13.2 -prep { 484 faultsim_restore_and_reopen 485 db eval { PRAGMA locking_mode = exclusive } 486 } -body { 487 db eval { PRAGMA journal_mode = delete } 488 } -test { 489 faultsim_test_result {0 delete} 490 if {[file exists test.db-shm]} { error "Not using heap-memory mode" } 491 faultsim_integrity_check 492 } 493 494 do_test walfault-13-pre-2 { 495 faultsim_delete_and_reopen 496 execsql { 497 BEGIN; 498 CREATE TABLE abc(a PRIMARY KEY); 499 INSERT INTO abc VALUES(randomblob(1500)); 500 INSERT INTO abc VALUES(randomblob(1500)); 501 COMMIT; 502 } 503 faultsim_save_and_close 504 } {} 505 506 do_faultsim_test walfault-13.3 -prep { 507 faultsim_restore_and_reopen 508 } -body { 509 db eval { 510 PRAGMA locking_mode = exclusive; 511 PRAGMA journal_mode = WAL; 512 INSERT INTO abc VALUES(randomblob(1500)); 513 } 514 } -test { 515 faultsim_test_result {0 {exclusive wal}} 516 if {[file exists test.db-shm]} { error "Not using heap-memory mode" } 517 faultsim_integrity_check 518 set nRow [db eval {SELECT count(*) FROM abc}] 519 if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" } 520 } 521 522 #------------------------------------------------------------------------- 523 # Test fault-handling when wrapping around to the start of a WAL file. 524 # 525 do_test walfault-14-pre { 526 faultsim_delete_and_reopen 527 execsql { 528 PRAGMA auto_vacuum = 0; 529 PRAGMA journal_mode = WAL; 530 BEGIN; 531 CREATE TABLE abc(a PRIMARY KEY); 532 INSERT INTO abc VALUES(randomblob(1500)); 533 INSERT INTO abc VALUES(randomblob(1500)); 534 COMMIT; 535 } 536 faultsim_save_and_close 537 } {} 538 do_faultsim_test walfault-14 -prep { 539 faultsim_restore_and_reopen 540 } -body { 541 db eval { 542 PRAGMA wal_checkpoint = full; 543 INSERT INTO abc VALUES(randomblob(1500)); 544 } 545 } -test { 546 faultsim_test_result {0 {0 9 9}} 547 faultsim_integrity_check 548 set nRow [db eval {SELECT count(*) FROM abc}] 549 if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" } 550 } 551 552 #------------------------------------------------------------------------- 553 # Test fault-handling when switching out of exclusive-locking mode. 554 # 555 do_test walfault-15-pre { 556 faultsim_delete_and_reopen 557 execsql { 558 PRAGMA auto_vacuum = 0; 559 PRAGMA journal_mode = WAL; 560 BEGIN; 561 CREATE TABLE abc(a PRIMARY KEY); 562 INSERT INTO abc VALUES(randomblob(1500)); 563 INSERT INTO abc VALUES(randomblob(1500)); 564 COMMIT; 565 } 566 faultsim_save_and_close 567 } {} 568 do_faultsim_test walfault-15 -prep { 569 faultsim_restore_and_reopen 570 execsql { 571 SELECT count(*) FROM abc; 572 PRAGMA locking_mode = exclusive; 573 BEGIN; 574 INSERT INTO abc VALUES(randomblob(1500)); 575 COMMIT; 576 } 577 } -body { 578 db eval { 579 PRAGMA locking_mode = normal; 580 BEGIN; 581 INSERT INTO abc VALUES(randomblob(1500)); 582 COMMIT; 583 } 584 } -test { 585 faultsim_integrity_check 586 set nRow [db eval {SELECT count(*) FROM abc}] 587 if {$nRow!=3 && $nRow!=4} { error "Bad db content" } 588 } 589 590 finish_test