github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/pagerfault.test (about) 1 # 2010 June 15 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 # 12 13 set testdir [file dirname $argv0] 14 source $testdir/tester.tcl 15 source $testdir/lock_common.tcl 16 source $testdir/malloc_common.tcl 17 18 if {[permutation] == "inmemory_journal"} { 19 finish_test 20 return 21 } 22 23 if {$::tcl_platform(platform)=="windows"} { 24 finish_test 25 return 26 } 27 28 set a_string_counter 1 29 proc a_string {n} { 30 global a_string_counter 31 incr a_string_counter 32 string range [string repeat "${a_string_counter}." $n] 1 $n 33 } 34 db func a_string a_string 35 36 #------------------------------------------------------------------------- 37 # Test fault-injection while rolling back a hot-journal file. 38 # 39 do_test pagerfault-1-pre1 { 40 execsql { 41 PRAGMA journal_mode = DELETE; 42 PRAGMA cache_size = 10; 43 CREATE TABLE t1(a UNIQUE, b UNIQUE); 44 INSERT INTO t1 VALUES(a_string(200), a_string(300)); 45 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 46 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 47 BEGIN; 48 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; 49 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; 50 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; 51 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; 52 } 53 faultsim_save_and_close 54 } {} 55 do_faultsim_test pagerfault-1 -prep { 56 faultsim_restore_and_reopen 57 } -body { 58 execsql { SELECT count(*) FROM t1 } 59 } -test { 60 faultsim_test_result {0 4} 61 faultsim_integrity_check 62 if {[db one { SELECT count(*) FROM t1 }] != 4} { 63 error "Database content appears incorrect" 64 } 65 } 66 67 #------------------------------------------------------------------------- 68 # Test fault-injection while rolling back a hot-journal file with a 69 # page-size different from the current value stored on page 1 of the 70 # database file. 71 # 72 do_test pagerfault-2-pre1 { 73 testvfs tv -default 1 74 tv filter xSync 75 tv script xSyncCb 76 proc xSyncCb {filename args} { 77 if {[string match *journal filename]==0} faultsim_save 78 } 79 faultsim_delete_and_reopen 80 execsql { 81 PRAGMA page_size = 4096; 82 BEGIN; 83 CREATE TABLE abc(a, b, c); 84 INSERT INTO abc VALUES('o', 't', 't'); 85 INSERT INTO abc VALUES('f', 'f', 's'); 86 INSERT INTO abc SELECT * FROM abc; -- 4 87 INSERT INTO abc SELECT * FROM abc; -- 8 88 INSERT INTO abc SELECT * FROM abc; -- 16 89 INSERT INTO abc SELECT * FROM abc; -- 32 90 INSERT INTO abc SELECT * FROM abc; -- 64 91 INSERT INTO abc SELECT * FROM abc; -- 128 92 INSERT INTO abc SELECT * FROM abc; -- 256 93 COMMIT; 94 PRAGMA page_size = 1024; 95 VACUUM; 96 } 97 db close 98 tv delete 99 } {} 100 do_faultsim_test pagerfault-2 -prep { 101 faultsim_restore_and_reopen 102 } -body { 103 execsql { SELECT * FROM abc } 104 } -test { 105 set answer [split [string repeat "ottffs" 128] ""] 106 faultsim_test_result [list 0 $answer] 107 faultsim_integrity_check 108 set res [db eval { SELECT * FROM abc }] 109 if {$res != $answer} { error "Database content appears incorrect ($res)" } 110 } 111 112 #------------------------------------------------------------------------- 113 # Test fault-injection while rolling back hot-journals that were created 114 # as part of a multi-file transaction. 115 # 116 do_test pagerfault-3-pre1 { 117 testvfs tstvfs -default 1 118 tstvfs filter xDelete 119 tstvfs script xDeleteCallback 120 121 proc xDeleteCallback {method file args} { 122 set file [file tail $file] 123 if { [string match *mj* $file] } { faultsim_save } 124 } 125 126 faultsim_delete_and_reopen 127 db func a_string a_string 128 129 execsql { 130 ATTACH 'test.db2' AS aux; 131 PRAGMA journal_mode = DELETE; 132 PRAGMA main.cache_size = 10; 133 PRAGMA aux.cache_size = 10; 134 135 CREATE TABLE t1(a UNIQUE, b UNIQUE); 136 CREATE TABLE aux.t2(a UNIQUE, b UNIQUE); 137 INSERT INTO t1 VALUES(a_string(200), a_string(300)); 138 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 139 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 140 INSERT INTO t2 SELECT * FROM t1; 141 142 BEGIN; 143 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; 144 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; 145 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; 146 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; 147 REPLACE INTO t2 SELECT * FROM t1; 148 COMMIT; 149 } 150 151 db close 152 tstvfs delete 153 } {} 154 do_faultsim_test pagerfault-3 -prep { 155 faultsim_restore_and_reopen 156 } -body { 157 execsql { 158 ATTACH 'test.db2' AS aux; 159 SELECT count(*) FROM t2; 160 SELECT count(*) FROM t1; 161 } 162 } -test { 163 faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}} 164 faultsim_integrity_check 165 catchsql { ATTACH 'test.db2' AS aux } 166 if {[db one { SELECT count(*) FROM t1 }] != 4 167 || [db one { SELECT count(*) FROM t2 }] != 4 168 } { 169 error "Database content appears incorrect" 170 } 171 } 172 173 #------------------------------------------------------------------------- 174 # Test fault-injection as part of a vanilla, no-transaction, INSERT 175 # statement. 176 # 177 do_faultsim_test pagerfault-4 -prep { 178 faultsim_delete_and_reopen 179 } -body { 180 execsql { 181 CREATE TABLE x(y); 182 INSERT INTO x VALUES('z'); 183 SELECT * FROM x; 184 } 185 } -test { 186 faultsim_test_result {0 z} 187 faultsim_integrity_check 188 } 189 190 #------------------------------------------------------------------------- 191 # Test fault-injection as part of a commit when using journal_mode=PERSIST. 192 # Three different cases: 193 # 194 # pagerfault-5.1: With no journal_size_limit configured. 195 # pagerfault-5.2: With a journal_size_limit configured. 196 # pagerfault-5.4: Multi-file transaction. One connection has a 197 # journal_size_limit of 0, the other has no limit. 198 # 199 do_test pagerfault-5-pre1 { 200 faultsim_delete_and_reopen 201 db func a_string a_string 202 execsql { 203 CREATE TABLE t1(a UNIQUE, b UNIQUE); 204 INSERT INTO t1 VALUES(a_string(200), a_string(300)); 205 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 206 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 207 } 208 faultsim_save_and_close 209 } {} 210 do_faultsim_test pagerfault-5.1 -prep { 211 faultsim_restore_and_reopen 212 db func a_string a_string 213 execsql { PRAGMA journal_mode = PERSIST } 214 } -body { 215 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } 216 } -test { 217 faultsim_test_result {0 {}} 218 faultsim_integrity_check 219 } 220 do_faultsim_test pagerfault-5.2 -prep { 221 faultsim_restore_and_reopen 222 db func a_string a_string 223 execsql { 224 PRAGMA journal_mode = PERSIST; 225 PRAGMA journal_size_limit = 2048; 226 } 227 } -body { 228 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } 229 } -test { 230 faultsim_test_result {0 {}} 231 faultsim_integrity_check 232 } 233 do_faultsim_test pagerfault-5.3 -faults oom-transient -prep { 234 faultsim_restore_and_reopen 235 db func a_string a_string 236 forcedelete test2.db test2.db-journal test2.db-wal 237 execsql { 238 PRAGMA journal_mode = PERSIST; 239 ATTACH 'test2.db' AS aux; 240 PRAGMA aux.journal_mode = PERSIST; 241 PRAGMA aux.journal_size_limit = 0; 242 } 243 } -body { 244 execsql { 245 BEGIN; 246 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; 247 CREATE TABLE aux.t2 AS SELECT * FROM t1; 248 COMMIT; 249 } 250 } -test { 251 faultsim_test_result {0 {}} 252 253 catchsql { COMMIT } 254 catchsql { ROLLBACK } 255 256 faultsim_integrity_check 257 set res "" 258 set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }] 259 if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"} 260 } 261 262 #------------------------------------------------------------------------- 263 # Test fault-injection as part of a commit when using 264 # journal_mode=TRUNCATE. 265 # 266 do_test pagerfault-6-pre1 { 267 faultsim_delete_and_reopen 268 db func a_string a_string 269 execsql { 270 CREATE TABLE t1(a UNIQUE, b UNIQUE); 271 INSERT INTO t1 VALUES(a_string(200), a_string(300)); 272 } 273 faultsim_save_and_close 274 } {} 275 276 do_faultsim_test pagerfault-6.1 -prep { 277 faultsim_restore_and_reopen 278 db func a_string a_string 279 execsql { PRAGMA journal_mode = TRUNCATE } 280 } -body { 281 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } 282 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } 283 } -test { 284 faultsim_test_result {0 {}} 285 faultsim_integrity_check 286 } 287 288 # The unix vfs xAccess() method considers a file zero bytes in size to 289 # "not exist". This proc overrides that behaviour so that a zero length 290 # file is considered to exist. 291 # 292 proc xAccess {method filename op args} { 293 if {$op != "SQLITE_ACCESS_EXISTS"} { return "" } 294 return [file exists $filename] 295 } 296 do_faultsim_test pagerfault-6.2 -faults cantopen-* -prep { 297 shmfault filter xAccess 298 shmfault script xAccess 299 300 faultsim_restore_and_reopen 301 db func a_string a_string 302 execsql { PRAGMA journal_mode = TRUNCATE } 303 } -body { 304 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } 305 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } 306 } -test { 307 faultsim_test_result {0 {}} 308 faultsim_integrity_check 309 } 310 311 # The following was an attempt to get a bitvec malloc to fail. Didn't work. 312 # 313 # do_test pagerfault-6-pre1 { 314 # faultsim_delete_and_reopen 315 # execsql { 316 # CREATE TABLE t1(x, y, UNIQUE(x, y)); 317 # INSERT INTO t1 VALUES(1, randomblob(1501)); 318 # INSERT INTO t1 VALUES(2, randomblob(1502)); 319 # INSERT INTO t1 VALUES(3, randomblob(1503)); 320 # INSERT INTO t1 VALUES(4, randomblob(1504)); 321 # INSERT INTO t1 322 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; 323 # INSERT INTO t1 324 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; 325 # INSERT INTO t1 326 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; 327 # INSERT INTO t1 328 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; 329 # } 330 # faultsim_save_and_close 331 # } {} 332 # do_faultsim_test pagerfault-6 -prep { 333 # faultsim_restore_and_reopen 334 # } -body { 335 # execsql { 336 # BEGIN; 337 # UPDATE t1 SET x=x+4 WHERE x=1; 338 # SAVEPOINT one; 339 # UPDATE t1 SET x=x+4 WHERE x=2; 340 # SAVEPOINT three; 341 # UPDATE t1 SET x=x+4 WHERE x=3; 342 # SAVEPOINT four; 343 # UPDATE t1 SET x=x+4 WHERE x=4; 344 # RELEASE three; 345 # COMMIT; 346 # SELECT DISTINCT x FROM t1; 347 # } 348 # } -test { 349 # faultsim_test_result {0 {5 6 7 8}} 350 # faultsim_integrity_check 351 # } 352 # 353 354 # This is designed to provoke a special case in the pager code: 355 # 356 # If an error (specifically, a FULL or IOERR error) occurs while writing a 357 # dirty page to the file-system in order to free up memory, the pager enters 358 # the "error state". An IO error causes SQLite to roll back the current 359 # transaction (exiting the error state). A FULL error, however, may only 360 # rollback the current statement. 361 # 362 # This block tests that nothing goes wrong if a FULL error occurs while 363 # writing a dirty page out to free memory from within a statement that has 364 # opened a statement transaction. 365 # 366 do_test pagerfault-7-pre1 { 367 faultsim_delete_and_reopen 368 execsql { 369 CREATE TABLE t2(a INTEGER PRIMARY KEY, b); 370 BEGIN; 371 INSERT INTO t2 VALUES(NULL, randomblob(1500)); 372 INSERT INTO t2 VALUES(NULL, randomblob(1500)); 373 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 4 374 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 8 375 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 16 376 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 32 377 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 64 378 COMMIT; 379 CREATE TABLE t1(a PRIMARY KEY, b); 380 INSERT INTO t1 SELECT * FROM t2; 381 DROP TABLE t2; 382 } 383 faultsim_save_and_close 384 } {} 385 do_faultsim_test pagerfault-7 -prep { 386 faultsim_restore_and_reopen 387 execsql { 388 PRAGMA cache_size = 10; 389 BEGIN; 390 UPDATE t1 SET b = randomblob(1500); 391 } 392 } -body { 393 execsql { UPDATE t1 SET a = 65, b = randomblob(1500) WHERE (a+1)>200 } 394 execsql COMMIT 395 } -test { 396 faultsim_test_result {0 {}} 397 faultsim_integrity_check 398 } 399 400 do_test pagerfault-8-pre1 { 401 faultsim_delete_and_reopen 402 execsql { 403 PRAGMA auto_vacuum = 1; 404 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 405 BEGIN; 406 INSERT INTO t1 VALUES(NULL, randomblob(1500)); 407 INSERT INTO t1 VALUES(NULL, randomblob(1500)); 408 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 4 409 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 8 410 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 16 411 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 32 412 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 64 413 COMMIT; 414 } 415 faultsim_save_and_close 416 set filesize [file size test.db] 417 set {} {} 418 } {} 419 do_test pagerfault-8-pre2 { 420 faultsim_restore_and_reopen 421 execsql { DELETE FROM t1 WHERE a>32 } 422 expr {[file size test.db] < $filesize} 423 } {1} 424 do_faultsim_test pagerfault-8 -prep { 425 faultsim_restore_and_reopen 426 execsql { 427 BEGIN; 428 DELETE FROM t1 WHERE a>32; 429 } 430 } -body { 431 execsql COMMIT 432 } -test { 433 faultsim_test_result {0 {}} 434 faultsim_integrity_check 435 } 436 437 #------------------------------------------------------------------------- 438 # This test case is specially designed so that during a savepoint 439 # rollback, a new cache entry must be allocated (see comments surrounding 440 # the call to sqlite3PagerAcquire() from within pager_playback_one_page() 441 # for details). Test the effects of injecting an OOM at this point. 442 # 443 do_test pagerfault-9-pre1 { 444 faultsim_delete_and_reopen 445 execsql { 446 PRAGMA auto_vacuum = incremental; 447 CREATE TABLE t1(x); 448 CREATE TABLE t2(y); 449 CREATE TABLE t3(z); 450 451 INSERT INTO t1 VALUES(randomblob(900)); 452 INSERT INTO t1 VALUES(randomblob(900)); 453 DELETE FROM t1; 454 } 455 faultsim_save_and_close 456 } {} 457 do_faultsim_test pagerfault-9.1 -prep { 458 faultsim_restore_and_reopen 459 execsql { 460 BEGIN; 461 INSERT INTO t1 VALUES(randomblob(900)); 462 INSERT INTO t1 VALUES(randomblob(900)); 463 DROP TABLE t3; 464 DROP TABLE t2; 465 SAVEPOINT abc; 466 PRAGMA incremental_vacuum; 467 } 468 } -body { 469 execsql { 470 ROLLBACK TO abc; 471 COMMIT; 472 PRAGMA freelist_count 473 } 474 } -test { 475 faultsim_test_result {0 2} 476 faultsim_integrity_check 477 478 set sl [db one { SELECT COALESCE(sum(length(x)), 'null') FROM t1 }] 479 if {$sl!="null" && $sl!=1800} { 480 error "Content looks no good... ($sl)" 481 } 482 } 483 484 #------------------------------------------------------------------------- 485 # Test fault injection with a temporary database file. 486 # 487 foreach v {a b} { 488 do_faultsim_test pagerfault-10$v -prep { 489 sqlite3 db "" 490 db func a_string a_string; 491 execsql { 492 PRAGMA cache_size = 10; 493 BEGIN; 494 CREATE TABLE xx(a, b, UNIQUE(a, b)); 495 INSERT INTO xx VALUES(a_string(200), a_string(200)); 496 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; 497 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; 498 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; 499 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; 500 COMMIT; 501 } 502 } -body { 503 execsql { UPDATE xx SET a = a_string(300) } 504 } -test { 505 faultsim_test_result {0 {}} 506 if {$::v == "b"} { execsql { PRAGMA journal_mode = TRUNCATE } } 507 faultsim_integrity_check 508 faultsim_integrity_check 509 } 510 } 511 512 #------------------------------------------------------------------------- 513 # Test fault injection with transaction savepoints (savepoints created 514 # when a SAVEPOINT command is executed outside of any other savepoint 515 # or transaction context). 516 # 517 do_test pagerfault-9-pre1 { 518 faultsim_delete_and_reopen 519 db func a_string a_string; 520 execsql { 521 PRAGMA auto_vacuum = on; 522 CREATE TABLE t1(x UNIQUE); 523 CREATE TABLE t2(y UNIQUE); 524 CREATE TABLE t3(z UNIQUE); 525 BEGIN; 526 INSERT INTO t1 VALUES(a_string(202)); 527 INSERT INTO t2 VALUES(a_string(203)); 528 INSERT INTO t3 VALUES(a_string(204)); 529 INSERT INTO t1 SELECT a_string(202) FROM t1; 530 INSERT INTO t1 SELECT a_string(203) FROM t1; 531 INSERT INTO t1 SELECT a_string(204) FROM t1; 532 INSERT INTO t1 SELECT a_string(205) FROM t1; 533 INSERT INTO t2 SELECT a_string(length(x)) FROM t1; 534 INSERT INTO t3 SELECT a_string(length(x)) FROM t1; 535 COMMIT; 536 } 537 faultsim_save_and_close 538 } {} 539 do_faultsim_test pagerfault-11 -prep { 540 faultsim_restore_and_reopen 541 execsql { PRAGMA cache_size = 10 } 542 } -body { 543 execsql { 544 SAVEPOINT trans; 545 UPDATE t2 SET y = y||'2'; 546 INSERT INTO t3 SELECT * FROM t2; 547 DELETE FROM t1; 548 ROLLBACK TO trans; 549 UPDATE t1 SET x = x||'3'; 550 INSERT INTO t2 SELECT * FROM t1; 551 DELETE FROM t3; 552 RELEASE trans; 553 } 554 } -test { 555 faultsim_test_result {0 {}} 556 faultsim_integrity_check 557 } 558 559 560 #------------------------------------------------------------------------- 561 # Test fault injection when writing to a database file that resides on 562 # a file-system with a sector-size larger than the database page-size. 563 # 564 do_test pagerfault-12-pre1 { 565 testvfs ss_layer -default 1 566 ss_layer sectorsize 4096 567 faultsim_delete_and_reopen 568 db func a_string a_string; 569 570 execsql { 571 PRAGMA page_size = 1024; 572 PRAGMA journal_mode = PERSIST; 573 PRAGMA cache_size = 10; 574 BEGIN; 575 CREATE TABLE t1(x, y UNIQUE); 576 INSERT INTO t1 VALUES(a_string(333), a_string(444)); 577 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; 578 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; 579 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; 580 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; 581 INSERT INTO t1 SELECT a_string(44), a_string(55) FROM t1 LIMIT 13; 582 COMMIT; 583 } 584 faultsim_save_and_close 585 } {} 586 587 do_faultsim_test pagerfault-12a -prep { 588 faultsim_restore_and_reopen 589 execsql { PRAGMA cache_size = 10 } 590 db func a_string a_string; 591 } -body { 592 execsql { 593 UPDATE t1 SET x = a_string(length(x)), y = a_string(length(y)); 594 } 595 } -test { 596 faultsim_test_result {0 {}} 597 faultsim_integrity_check 598 } 599 600 do_test pagerfault-12-pre2 { 601 faultsim_restore_and_reopen 602 execsql { 603 CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 10; 604 } 605 faultsim_save_and_close 606 } {} 607 do_faultsim_test pagerfault-12b -prep { 608 faultsim_restore_and_reopen 609 db func a_string a_string; 610 execsql { SELECT * FROM t1 } 611 } -body { 612 set sql(1) { UPDATE t2 SET x = a_string(280) } 613 set sql(2) { UPDATE t1 SET x = a_string(280) WHERE rowid = 5 } 614 615 db eval { SELECT rowid FROM t1 LIMIT 2 } { db eval $sql($rowid) } 616 617 } -test { 618 faultsim_test_result {0 {}} 619 faultsim_integrity_check 620 } 621 622 catch { db close } 623 ss_layer delete 624 625 626 #------------------------------------------------------------------------- 627 # Test fault injection when SQLite opens a database where the size of the 628 # database file is zero bytes but the accompanying journal file is larger 629 # than that. In this scenario SQLite should delete the journal file 630 # without rolling it back, even if it is in all other respects a valid 631 # hot-journal file. 632 # 633 do_test pagerfault-13-pre1 { 634 faultsim_delete_and_reopen 635 db func a_string a_string; 636 execsql { 637 PRAGMA journal_mode = PERSIST; 638 BEGIN; 639 CREATE TABLE t1(x, y UNIQUE); 640 INSERT INTO t1 VALUES(a_string(333), a_string(444)); 641 COMMIT; 642 } 643 db close 644 forcedelete test.db 645 faultsim_save 646 } {} 647 do_faultsim_test pagerfault-13 -prep { 648 faultsim_restore_and_reopen 649 } -body { 650 execsql { CREATE TABLE xx(a, b) } 651 } -test { 652 faultsim_test_result {0 {}} 653 } 654 655 #--------------------------------------------------------------------------- 656 # Test fault injection into a small backup operation. 657 # 658 do_test pagerfault-14-pre1 { 659 faultsim_delete_and_reopen 660 db func a_string a_string; 661 execsql { 662 PRAGMA journal_mode = PERSIST; 663 ATTACH 'test.db2' AS two; 664 BEGIN; 665 CREATE TABLE t1(x, y UNIQUE); 666 CREATE TABLE two.t2(x, y UNIQUE); 667 INSERT INTO t1 VALUES(a_string(333), a_string(444)); 668 INSERT INTO t2 VALUES(a_string(333), a_string(444)); 669 COMMIT; 670 } 671 faultsim_save_and_close 672 } {} 673 674 do_faultsim_test pagerfault-14a -prep { 675 faultsim_restore_and_reopen 676 } -body { 677 if {[catch {db backup test.db2} msg]} { error [regsub {.*: } $msg {}] } 678 } -test { 679 faultsim_test_result {0 {}} {1 {}} {1 {SQL logic error}} 680 } 681 682 # If TEMP_STORE is 2 or greater, then the database [db2] will be created 683 # as an in-memory database. This test will not work in that case, as it 684 # is not possible to change the page-size of an in-memory database. Even 685 # using the backup API. 686 # 687 # Update: It is no longer possible to change the page size of any temp 688 # database after it has been created. 689 # 690 do_faultsim_test pagerfault-14b -prep { 691 catch { db2 close } 692 faultsim_restore_and_reopen 693 sqlite3 db2 "" 694 db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) } 695 } -body { 696 sqlite3_backup B db2 main db main 697 B step 200 698 set rc [B finish] 699 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} 700 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } 701 set {} {} 702 } -test { 703 faultsim_test_result {1 {attempt to write a readonly database}} \ 704 {1 {sqlite3_backup_init() failed}} 705 } 706 707 do_faultsim_test pagerfault-14c -prep { 708 catch { db2 close } 709 faultsim_restore_and_reopen 710 sqlite3 db2 test.db2 711 db2 eval { 712 PRAGMA synchronous = off; 713 PRAGMA page_size = 4096; 714 CREATE TABLE xx(a); 715 } 716 } -body { 717 sqlite3_backup B db2 main db main 718 B step 200 719 set rc [B finish] 720 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} 721 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } 722 set {} {} 723 } -test { 724 faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}} 725 } 726 727 do_test pagerfault-15-pre1 { 728 faultsim_delete_and_reopen 729 db func a_string a_string; 730 execsql { 731 BEGIN; 732 CREATE TABLE t1(x, y UNIQUE); 733 INSERT INTO t1 VALUES(a_string(11), a_string(22)); 734 INSERT INTO t1 VALUES(a_string(11), a_string(22)); 735 COMMIT; 736 } 737 faultsim_save_and_close 738 } {} 739 do_faultsim_test pagerfault-15 -prep { 740 faultsim_restore_and_reopen 741 db func a_string a_string; 742 } -body { 743 db eval { SELECT * FROM t1 LIMIT 1 } { 744 execsql { 745 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; 746 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; 747 } 748 } 749 } -test { 750 faultsim_test_result {0 {}} 751 faultsim_integrity_check 752 } 753 754 755 do_test pagerfault-16-pre1 { 756 faultsim_delete_and_reopen 757 execsql { CREATE TABLE t1(x, y UNIQUE) } 758 faultsim_save_and_close 759 } {} 760 do_faultsim_test pagerfault-16 -prep { 761 faultsim_restore_and_reopen 762 } -body { 763 execsql { 764 PRAGMA locking_mode = exclusive; 765 PRAGMA journal_mode = wal; 766 INSERT INTO t1 VALUES(1, 2); 767 INSERT INTO t1 VALUES(3, 4); 768 PRAGMA journal_mode = delete; 769 INSERT INTO t1 VALUES(4, 5); 770 PRAGMA journal_mode = wal; 771 INSERT INTO t1 VALUES(6, 7); 772 PRAGMA journal_mode = persist; 773 INSERT INTO t1 VALUES(8, 9); 774 } 775 } -test { 776 faultsim_test_result {0 {exclusive wal delete wal persist}} 777 faultsim_integrity_check 778 } 779 780 781 #------------------------------------------------------------------------- 782 # Test fault injection while changing into and out of WAL mode. 783 # 784 do_test pagerfault-17-pre1 { 785 faultsim_delete_and_reopen 786 execsql { 787 CREATE TABLE t1(a PRIMARY KEY, b); 788 INSERT INTO t1 VALUES(1862, 'Botha'); 789 INSERT INTO t1 VALUES(1870, 'Smuts'); 790 INSERT INTO t1 VALUES(1866, 'Hertzog'); 791 } 792 faultsim_save_and_close 793 } {} 794 do_faultsim_test pagerfault-17a -prep { 795 faultsim_restore_and_reopen 796 } -body { 797 execsql { 798 PRAGMA journal_mode = wal; 799 PRAGMA journal_mode = delete; 800 } 801 } -test { 802 faultsim_test_result {0 {wal delete}} 803 faultsim_integrity_check 804 } 805 do_faultsim_test pagerfault-17b -prep { 806 faultsim_restore_and_reopen 807 execsql { PRAGMA synchronous = OFF } 808 } -body { 809 execsql { 810 PRAGMA journal_mode = wal; 811 INSERT INTO t1 VALUES(22, 'Clarke'); 812 PRAGMA journal_mode = delete; 813 } 814 } -test { 815 faultsim_test_result {0 {wal delete}} 816 faultsim_integrity_check 817 } 818 do_faultsim_test pagerfault-17c -prep { 819 faultsim_restore_and_reopen 820 execsql { 821 PRAGMA locking_mode = exclusive; 822 PRAGMA journal_mode = wal; 823 } 824 } -body { 825 execsql { PRAGMA journal_mode = delete } 826 } -test { 827 faultsim_test_result {0 delete} 828 faultsim_integrity_check 829 } 830 do_faultsim_test pagerfault-17d -prep { 831 catch { db2 close } 832 faultsim_restore_and_reopen 833 sqlite3 db2 test.db 834 execsql { PRAGMA journal_mode = delete } 835 execsql { PRAGMA journal_mode = wal } 836 execsql { INSERT INTO t1 VALUES(99, 'Bradman') } db2 837 } -body { 838 execsql { PRAGMA journal_mode = delete } 839 } -test { 840 faultsim_test_result {1 {database is locked}} 841 faultsim_integrity_check 842 } 843 do_faultsim_test pagerfault-17e -prep { 844 catch { db2 close } 845 faultsim_restore_and_reopen 846 sqlite3 db2 test.db 847 execsql { PRAGMA journal_mode = delete } 848 execsql { PRAGMA journal_mode = wal } 849 set ::chan [launch_testfixture] 850 testfixture $::chan { 851 sqlite3 db test.db 852 db eval { INSERT INTO t1 VALUES(101, 'Latham') } 853 } 854 catch { testfixture $::chan sqlite_abort } 855 catch { close $::chan } 856 } -body { 857 execsql { PRAGMA journal_mode = delete } 858 } -test { 859 faultsim_test_result {0 delete} 860 faultsim_integrity_check 861 } 862 863 #------------------------------------------------------------------------- 864 # Test fault-injection when changing from journal_mode=persist to 865 # journal_mode=delete (this involves deleting the journal file). 866 # 867 do_test pagerfault-18-pre1 { 868 faultsim_delete_and_reopen 869 execsql { 870 CREATE TABLE qq(x); 871 INSERT INTO qq VALUES('Herbert'); 872 INSERT INTO qq VALUES('Macalister'); 873 INSERT INTO qq VALUES('Mackenzie'); 874 INSERT INTO qq VALUES('Lilley'); 875 INSERT INTO qq VALUES('Palmer'); 876 } 877 faultsim_save_and_close 878 } {} 879 do_faultsim_test pagerfault-18 -prep { 880 faultsim_restore_and_reopen 881 execsql { 882 PRAGMA journal_mode = PERSIST; 883 INSERT INTO qq VALUES('Beatty'); 884 } 885 } -body { 886 execsql { PRAGMA journal_mode = delete } 887 } -test { 888 faultsim_test_result {0 delete} 889 faultsim_integrity_check 890 } 891 892 do_faultsim_test pagerfault-19a -prep { 893 sqlite3 db :memory: 894 db func a_string a_string 895 execsql { 896 PRAGMA auto_vacuum = FULL; 897 BEGIN; 898 CREATE TABLE t1(a, b); 899 INSERT INTO t1 VALUES(a_string(5000), a_string(6000)); 900 COMMIT; 901 } 902 } -body { 903 execsql { 904 CREATE TABLE t2(a, b); 905 INSERT INTO t2 SELECT * FROM t1; 906 DELETE FROM t1; 907 } 908 } -test { 909 faultsim_test_result {0 {}} 910 } 911 912 do_test pagerfault-19-pre1 { 913 faultsim_delete_and_reopen 914 execsql { 915 PRAGMA auto_vacuum = FULL; 916 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); 917 CREATE TABLE t2(x); INSERT INTO t2 VALUES(2); 918 CREATE TABLE t3(x); INSERT INTO t3 VALUES(3); 919 CREATE TABLE t4(x); INSERT INTO t4 VALUES(4); 920 CREATE TABLE t5(x); INSERT INTO t5 VALUES(5); 921 CREATE TABLE t6(x); INSERT INTO t6 VALUES(6); 922 } 923 faultsim_save_and_close 924 } {} 925 do_faultsim_test pagerfault-19b -prep { 926 faultsim_restore_and_reopen 927 } -body { 928 execsql { 929 BEGIN; 930 UPDATE t4 SET x = x+1; 931 UPDATE t6 SET x = x+1; 932 SAVEPOINT one; 933 UPDATE t3 SET x = x+1; 934 SAVEPOINT two; 935 DROP TABLE t2; 936 ROLLBACK TO one; 937 COMMIT; 938 SELECT * FROM t3; 939 SELECT * FROM t4; 940 SELECT * FROM t6; 941 } 942 } -test { 943 faultsim_test_result {0 {3 5 7}} 944 } 945 946 #------------------------------------------------------------------------- 947 # This tests fault-injection in a special case in the auto-vacuum code. 948 # 949 do_test pagerfault-20-pre1 { 950 faultsim_delete_and_reopen 951 execsql { 952 PRAGMA cache_size = 10; 953 PRAGMA auto_vacuum = FULL; 954 CREATE TABLE t0(a, b); 955 } 956 faultsim_save_and_close 957 } {} 958 do_faultsim_test pagerfault-20 -prep { 959 faultsim_restore_and_reopen 960 } -body { 961 execsql { 962 BEGIN; 963 CREATE TABLE t1(a, b); 964 CREATE TABLE t2(a, b); 965 DROP TABLE t1; 966 COMMIT; 967 } 968 } -test { 969 faultsim_test_result {0 {}} 970 } 971 972 do_test pagerfault-21-pre1 { 973 faultsim_delete_and_reopen 974 execsql { 975 PRAGMA cache_size = 10; 976 CREATE TABLE t0(a PRIMARY KEY, b); 977 INSERT INTO t0 VALUES(1, 2); 978 } 979 faultsim_save_and_close 980 } {} 981 do_faultsim_test pagerfault-21 -prep { 982 faultsim_restore_and_reopen 983 } -body { 984 db eval { SELECT * FROM t0 LIMIT 1 } { 985 db eval { INSERT INTO t0 SELECT a+1, b FROM t0 } 986 db eval { INSERT INTO t0 SELECT a+2, b FROM t0 } 987 } 988 } -test { 989 faultsim_test_result {0 {}} 990 } 991 992 993 #------------------------------------------------------------------------- 994 # Test fault-injection and rollback when the nReserve header value 995 # is non-zero. 996 # 997 do_test pagerfault-21-pre1 { 998 faultsim_delete_and_reopen 999 execsql { 1000 PRAGMA page_size = 1024; 1001 PRAGMA journal_mode = WAL; 1002 PRAGMA journal_mode = DELETE; 1003 } 1004 db close 1005 hexio_write test.db 20 10 1006 hexio_write test.db 105 03F0 1007 sqlite3 db test.db 1008 db func a_string a_string 1009 execsql { 1010 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); 1011 INSERT INTO t0 VALUES(a_string(222), a_string(333)); 1012 INSERT INTO t0 VALUES(a_string(223), a_string(334)); 1013 INSERT INTO t0 VALUES(a_string(224), a_string(335)); 1014 INSERT INTO t0 VALUES(a_string(225), a_string(336)); 1015 } 1016 faultsim_save_and_close 1017 } {} 1018 1019 do_faultsim_test pagerfault-21 -prep { 1020 faultsim_restore_and_reopen 1021 } -body { 1022 execsql { INSERT INTO t0 SELECT a||'x', b||'x' FROM t0 } 1023 } -test { 1024 faultsim_test_result {0 {}} 1025 faultsim_integrity_check 1026 } 1027 ifcapable crashtest { 1028 faultsim_delete_and_reopen 1029 execsql { 1030 PRAGMA page_size = 1024; 1031 PRAGMA journal_mode = WAL; 1032 PRAGMA journal_mode = DELETE; 1033 } 1034 db close 1035 hexio_write test.db 20 10 1036 hexio_write test.db 105 03F0 1037 1038 sqlite3 db test.db 1039 db func a_string a_string 1040 execsql { 1041 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); 1042 INSERT INTO t0 VALUES(a_string(222), a_string(333)); 1043 INSERT INTO t0 VALUES(a_string(223), a_string(334)); 1044 } 1045 faultsim_save_and_close 1046 1047 for {set iTest 1} {$iTest<50} {incr iTest} { 1048 do_test pagerfault-21.crash.$iTest.1 { 1049 crashsql -delay 1 -file test.db -seed $iTest { 1050 BEGIN; 1051 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); 1052 INSERT INTO t1 SELECT a, b FROM t0; 1053 COMMIT; 1054 } 1055 } {1 {child process exited abnormally}} 1056 do_test pagerfault-22.$iTest.2 { 1057 sqlite3 db test.db 1058 execsql { PRAGMA integrity_check } 1059 } {ok} 1060 db close 1061 } 1062 } 1063 1064 1065 #------------------------------------------------------------------------- 1066 # When a 3.7.0 client opens a write-transaction on a database file that 1067 # has been appended to or truncated by a pre-370 client, it updates 1068 # the db-size in the file header immediately. This test case provokes 1069 # errors during that operation. 1070 # 1071 do_test pagerfault-22-pre1 { 1072 faultsim_delete_and_reopen 1073 db func a_string a_string 1074 execsql { 1075 PRAGMA page_size = 1024; 1076 PRAGMA auto_vacuum = 0; 1077 CREATE TABLE t1(a); 1078 CREATE INDEX i1 ON t1(a); 1079 INSERT INTO t1 VALUES(a_string(3000)); 1080 CREATE TABLE t2(a); 1081 INSERT INTO t2 VALUES(1); 1082 } 1083 db close 1084 sql36231 { INSERT INTO t1 VALUES(a_string(3000)) } 1085 faultsim_save_and_close 1086 } {} 1087 do_faultsim_test pagerfault-22 -prep { 1088 faultsim_restore_and_reopen 1089 } -body { 1090 execsql { INSERT INTO t2 VALUES(2) } 1091 execsql { SELECT * FROM t2 } 1092 } -test { 1093 faultsim_test_result {0 {1 2}} 1094 faultsim_integrity_check 1095 } 1096 1097 #------------------------------------------------------------------------- 1098 # Provoke an OOM error during a commit of multi-file transaction. One of 1099 # the databases written during the transaction is an in-memory database. 1100 # This test causes rollback of the in-memory database after CommitPhaseOne() 1101 # has successfully returned. i.e. the series of calls for the aborted commit 1102 # is: 1103 # 1104 # PagerCommitPhaseOne(<in-memory-db>) -> SQLITE_OK 1105 # PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR 1106 # PagerRollback(<in-memory-db>) 1107 # PagerRollback(<file-db>) 1108 # 1109 do_faultsim_test pagerfault-23 -prep { 1110 sqlite3 db :memory: 1111 foreach f [glob -nocomplain test.db*] { forcedelete $f } 1112 db eval { 1113 ATTACH 'test.db2' AS aux; 1114 CREATE TABLE t1(a, b); 1115 CREATE TABLE aux.t2(a, b); 1116 } 1117 } -body { 1118 execsql { 1119 BEGIN; 1120 INSERT INTO t1 VALUES(1,2); 1121 INSERT INTO t2 VALUES(3,4); 1122 COMMIT; 1123 } 1124 } -test { 1125 faultsim_test_result {0 {}} 1126 faultsim_integrity_check 1127 } 1128 1129 do_faultsim_test pagerfault-24 -prep { 1130 faultsim_delete_and_reopen 1131 db eval { PRAGMA temp_store = file } 1132 execsql { CREATE TABLE x(a, b) } 1133 } -body { 1134 execsql { CREATE TEMP TABLE t1(a, b) } 1135 } -test { 1136 faultsim_test_result {0 {}} \ 1137 {1 {unable to open a temporary database file for storing temporary tables}} 1138 set ic [db eval { PRAGMA temp.integrity_check }] 1139 if {$ic != "ok"} { error "Integrity check: $ic" } 1140 } 1141 1142 proc lockrows {n} { 1143 if {$n==0} { return "" } 1144 db eval { SELECT * FROM t1 WHERE oid = $n } { 1145 return [lockrows [expr {$n-1}]] 1146 } 1147 } 1148 1149 1150 do_test pagerfault-25-pre1 { 1151 faultsim_delete_and_reopen 1152 db func a_string a_string 1153 execsql { 1154 PRAGMA page_size = 1024; 1155 PRAGMA auto_vacuum = 0; 1156 CREATE TABLE t1(a); 1157 INSERT INTO t1 VALUES(a_string(500)); 1158 INSERT INTO t1 SELECT a_string(500) FROM t1; 1159 INSERT INTO t1 SELECT a_string(500) FROM t1; 1160 INSERT INTO t1 SELECT a_string(500) FROM t1; 1161 INSERT INTO t1 SELECT a_string(500) FROM t1; 1162 INSERT INTO t1 SELECT a_string(500) FROM t1; 1163 } 1164 faultsim_save_and_close 1165 } {} 1166 do_faultsim_test pagerfault-25 -prep { 1167 faultsim_restore_and_reopen 1168 db func a_string a_string 1169 set ::channel [db incrblob -readonly t1 a 1] 1170 execsql { 1171 PRAGMA cache_size = 10; 1172 BEGIN; 1173 INSERT INTO t1 VALUES(a_string(3000)); 1174 INSERT INTO t1 VALUES(a_string(3000)); 1175 } 1176 } -body { 1177 lockrows 30 1178 } -test { 1179 catch { lockrows 30 } 1180 catch { db eval COMMIT } 1181 close $::channel 1182 faultsim_test_result {0 {}} 1183 } 1184 1185 do_faultsim_test pagerfault-26 -prep { 1186 faultsim_delete_and_reopen 1187 execsql { 1188 PRAGMA page_size = 1024; 1189 PRAGMA journal_mode = truncate; 1190 PRAGMA auto_vacuum = full; 1191 PRAGMA locking_mode=exclusive; 1192 CREATE TABLE t1(a, b); 1193 INSERT INTO t1 VALUES(1, 2); 1194 PRAGMA page_size = 4096; 1195 } 1196 } -body { 1197 execsql { 1198 VACUUM; 1199 } 1200 } -test { 1201 faultsim_test_result {0 {}} 1202 1203 set contents [db eval {SELECT * FROM t1}] 1204 if {$contents != "1 2"} { error "Bad database contents ($contents)" } 1205 1206 if {[atomic_batch_write test.db]==0} { 1207 set sz [file size test.db] 1208 if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 1209 error "Expected file size 3072 or 12288 bytes - actual size $sz bytes" 1210 } 1211 if {$testrc==0 && $sz!=4096*3} { 1212 error "Expected file size to be 12288 bytes - actual size $sz bytes" 1213 } 1214 } 1215 } 1216 1217 do_test pagerfault-27-pre { 1218 faultsim_delete_and_reopen 1219 db func a_string a_string 1220 execsql { 1221 PRAGMA page_size = 1024; 1222 CREATE TABLE t1(a, b); 1223 CREATE TABLE t2(a UNIQUE, b UNIQUE); 1224 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); 1225 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1226 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1227 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1228 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1229 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1230 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1231 INSERT INTO t1 VALUES (a_string(20000), a_string(20000)); 1232 } 1233 faultsim_save_and_close 1234 } {} 1235 do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep { 1236 faultsim_restore_and_reopen 1237 db func a_string a_string 1238 execsql { 1239 PRAGMA cache_size = 10; 1240 BEGIN EXCLUSIVE; 1241 } 1242 set ::channel [db incrblob t1 a 1] 1243 } -body { 1244 puts $::channel [string repeat abc 6000] 1245 flush $::channel 1246 } -test { 1247 catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) } 1248 catch { close $::channel } 1249 catchsql { ROLLBACK } 1250 faultsim_integrity_check 1251 } 1252 1253 1254 #------------------------------------------------------------------------- 1255 # 1256 do_test pagerfault-28-pre { 1257 faultsim_delete_and_reopen 1258 db func a_string a_string 1259 execsql { 1260 PRAGMA page_size = 512; 1261 1262 PRAGMA journal_mode = wal; 1263 PRAGMA wal_autocheckpoint = 0; 1264 PRAGMA cache_size = 100000; 1265 1266 BEGIN; 1267 CREATE TABLE t2(a UNIQUE, b UNIQUE); 1268 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); 1269 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1270 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1271 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1272 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1273 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1274 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1275 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1276 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1277 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1278 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1279 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1280 COMMIT; 1281 CREATE TABLE t1(a PRIMARY KEY, b); 1282 } 1283 expr {[file size test.db-shm] >= 96*1024} 1284 } {1} 1285 faultsim_save_and_close 1286 1287 do_faultsim_test pagerfault-28a -faults oom* -prep { 1288 faultsim_restore_and_reopen 1289 execsql { PRAGMA mmap_size=0 } 1290 1291 sqlite3 db2 test.db 1292 db2 eval { SELECT count(*) FROM t2 } 1293 1294 db func a_string a_string 1295 execsql { 1296 BEGIN; 1297 INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); 1298 INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); 1299 } 1300 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY] 1301 sqlite3_step $::STMT 1302 } -body { 1303 execsql { ROLLBACK } 1304 } -test { 1305 db2 close 1306 sqlite3_finalize $::STMT 1307 catchsql { ROLLBACK } 1308 faultsim_integrity_check 1309 } 1310 1311 faultsim_restore_and_reopen 1312 sqlite3 db2 test.db 1313 db2 eval {SELECT count(*) FROM t2} 1314 db close 1315 1316 do_faultsim_test pagerfault-28b -faults oom* -prep { 1317 sqlite3 db test.db 1318 } -body { 1319 execsql { SELECT count(*) FROM t2 } 1320 } -test { 1321 faultsim_test_result {0 2048} 1322 db close 1323 } 1324 1325 db2 close 1326 1327 #------------------------------------------------------------------------- 1328 # Try this: 1329 # 1330 # 1) Put the pager in ERROR state (error during rollback) 1331 # 1332 # 2) Next time the connection is used inject errors into all xWrite() and 1333 # xUnlock() calls. This causes the hot-journal rollback to fail and 1334 # the pager to declare its locking state UNKNOWN. 1335 # 1336 # 3) Same again. 1337 # 1338 # 4a) Stop injecting errors. Allow the rollback to succeed. Check that 1339 # the database is Ok. Or, 1340 # 1341 # 4b) Close and reopen the db. Check that the db is Ok. 1342 # 1343 proc custom_injectinstall {} { 1344 testvfs custom -default true 1345 custom filter {xWrite xUnlock} 1346 } 1347 proc custom_injectuninstall {} { 1348 catch {db close} 1349 catch {db2 close} 1350 custom delete 1351 } 1352 proc custom_injectstart {iFail} { 1353 custom ioerr $iFail 1 1354 } 1355 proc custom_injectstop {} { 1356 custom ioerr 1357 } 1358 set ::FAULTSIM(custom) [list \ 1359 -injectinstall custom_injectinstall \ 1360 -injectstart custom_injectstart \ 1361 -injectstop custom_injectstop \ 1362 -injecterrlist {{1 {disk I/O error}}} \ 1363 -injectuninstall custom_injectuninstall \ 1364 ] 1365 1366 do_test pagerfault-29-pre { 1367 faultsim_delete_and_reopen 1368 db func a_string a_string 1369 execsql { 1370 PRAGMA page_size = 1024; 1371 PRAGMA cache_size = 5; 1372 1373 BEGIN; 1374 CREATE TABLE t2(a UNIQUE, b UNIQUE); 1375 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); 1376 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1377 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1378 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1379 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; 1380 COMMIT; 1381 } 1382 expr {[file size test.db] >= 50*1024} 1383 } {1} 1384 faultsim_save_and_close 1385 foreach {tn tt} { 1386 29 { catchsql ROLLBACK } 1387 30 { db close ; sqlite3 db test.db } 1388 } { 1389 do_faultsim_test pagerfault-$tn -faults custom -prep { 1390 faultsim_restore_and_reopen 1391 db func a_string a_string 1392 execsql { 1393 PRAGMA cache_size = 5; 1394 BEGIN; 1395 UPDATE t2 SET a = a_string(799); 1396 } 1397 } -body { 1398 catchsql ROLLBACK 1399 catchsql ROLLBACK 1400 catchsql ROLLBACK 1401 } -test { 1402 eval $::tt 1403 if {"ok" != [db one {PRAGMA integrity_check}]} { 1404 error "integrity check failed" 1405 } 1406 } 1407 } 1408 1409 do_test pagerfault-31-pre { 1410 sqlite3_shutdown 1411 sqlite3_config_uri 1 1412 } {SQLITE_OK} 1413 do_faultsim_test pagerfault-31 -faults oom* -body { 1414 sqlite3 db {file:one?mode=memory&cache=shared} 1415 db eval { 1416 CREATE TABLE t1(x); 1417 INSERT INTO t1 VALUES(1); 1418 SELECT * FROM t1; 1419 } 1420 } -test { 1421 faultsim_test_result {0 1} {1 {}} 1422 catch { db close } 1423 } 1424 sqlite3_shutdown 1425 sqlite3_config_uri 0 1426 1427 do_test pagerfault-32-pre { 1428 reset_db 1429 execsql { 1430 CREATE TABLE t1(x); 1431 INSERT INTO t1 VALUES('one'); 1432 } 1433 } {} 1434 faultsim_save_and_close 1435 1436 do_faultsim_test pagerfault-32 -prep { 1437 faultsim_restore_and_reopen 1438 db eval { SELECT * FROM t1; } 1439 } -body { 1440 execsql { SELECT * FROM t1; } 1441 } -test { 1442 faultsim_test_result {0 one} 1443 } 1444 sqlite3_shutdown 1445 sqlite3_config_uri 0 1446 1447 do_faultsim_test pagerfault-33a -prep { 1448 sqlite3 db :memory: 1449 execsql { 1450 CREATE TABLE t1(a, b); 1451 INSERT INTO t1 VALUES(1, 2); 1452 } 1453 } -body { 1454 execsql { VACUUM } 1455 } -test { 1456 faultsim_test_result {0 {}} 1457 } 1458 do_faultsim_test pagerfault-33b -prep { 1459 sqlite3 db "" 1460 execsql { 1461 CREATE TABLE t1(a, b); 1462 INSERT INTO t1 VALUES(1, 2); 1463 } 1464 } -body { 1465 execsql { VACUUM } 1466 } -test { 1467 faultsim_test_result {0 {}} 1468 } 1469 1470 do_test pagerfault-34-pre { 1471 reset_db 1472 execsql { 1473 CREATE TABLE t1(x PRIMARY KEY); 1474 } 1475 } {} 1476 faultsim_save_and_close 1477 do_faultsim_test pagerfault-34 -prep { 1478 faultsim_restore_and_reopen 1479 execsql { 1480 BEGIN; 1481 INSERT INTO t1 VALUES( randomblob(4000) ); 1482 DELETE FROM t1; 1483 } 1484 } -body { 1485 execsql COMMIT 1486 } -test { 1487 faultsim_test_result {0 {}} 1488 } 1489 1490 do_test pagerfault-35-pre { 1491 faultsim_delete_and_reopen 1492 execsql { 1493 CREATE TABLE t1(x PRIMARY KEY, y); 1494 INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); 1495 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; 1496 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; 1497 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; 1498 } 1499 faultsim_save_and_close 1500 } {} 1501 testvfs tv -default 1 1502 tv sectorsize 8192; 1503 tv devchar [list] 1504 do_faultsim_test pagerfault-35 -prep { 1505 faultsim_restore_and_reopen 1506 } -body { 1507 execsql { UPDATE t1 SET x=randomblob(200) } 1508 } -test { 1509 faultsim_test_result {0 {}} 1510 } 1511 catch {db close} 1512 tv delete 1513 1514 sqlite3_shutdown 1515 sqlite3_config_uri 1 1516 do_test pagerfault-36-pre { 1517 faultsim_delete_and_reopen 1518 execsql { 1519 CREATE TABLE t1(x PRIMARY KEY, y); 1520 INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); 1521 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; 1522 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; 1523 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; 1524 } 1525 faultsim_save_and_close 1526 } {} 1527 do_faultsim_test pagerfault-36 -prep { 1528 faultsim_restore 1529 sqlite3 db file:test.db?cache=shared 1530 sqlite3 db2 file:test.db?cache=shared 1531 db2 eval { 1532 BEGIN; 1533 SELECT count(*) FROM sqlite_master; 1534 } 1535 db eval { 1536 PRAGMA cache_size = 1; 1537 BEGIN; 1538 UPDATE t1 SET x = randomblob(200); 1539 } 1540 } -body { 1541 execsql ROLLBACK db 1542 } -test { 1543 catch { db eval {UPDATE t1 SET x = randomblob(200)} } 1544 faultsim_test_result {0 {}} 1545 catch { db close } 1546 catch { db2 close } 1547 } 1548 1549 sqlite3_shutdown 1550 sqlite3_config_uri 0 1551 sqlite3_initialize 1552 1553 finish_test