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 13set testdir [file dirname $argv0] 14source $testdir/tester.tcl 15source $testdir/lock_common.tcl 16source $testdir/malloc_common.tcl 17 18if {[permutation] == "inmemory_journal"} { 19 finish_test 20 return 21} 22 23if {$::tcl_platform(platform)=="windows"} { 24 finish_test 25 return 26} 27 28set a_string_counter 1 29proc 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} 34db func a_string a_string 35 36#------------------------------------------------------------------------- 37# Test fault-injection while rolling back a hot-journal file. 38# 39do_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} {} 55do_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# 72do_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} {} 100do_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# 116do_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} {} 154do_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# 177do_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# 199do_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} {} 210do_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} 220do_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} 233do_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# 266do_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 276do_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# 292proc xAccess {method filename op args} { 293 if {$op != "SQLITE_ACCESS_EXISTS"} { return "" } 294 return [file exists $filename] 295} 296do_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# 366do_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} {} 385do_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 400do_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} {} 419do_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} 424do_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# 443do_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} {} 457do_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# 487foreach 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# 517do_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} {} 539do_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# 564do_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 587do_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 600do_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} {} 607do_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 622catch { db close } 623ss_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# 633do_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} {} 647do_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# 658do_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 674do_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# 690do_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 707do_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 727do_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} {} 739do_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 755do_test pagerfault-16-pre1 { 756 faultsim_delete_and_reopen 757 execsql { CREATE TABLE t1(x, y UNIQUE) } 758 faultsim_save_and_close 759} {} 760do_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# 784do_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} {} 794do_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} 805do_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} 818do_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} 830do_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} 843do_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# 867do_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} {} 879do_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 892do_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 912do_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} {} 925do_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# 949do_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} {} 958do_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 972do_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} {} 981do_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# 997do_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 1019do_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} 1027ifcapable 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# 1071do_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} {} 1087do_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# 1109do_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 1129do_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 1142proc 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 1150do_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} {} 1166do_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 1185do_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 1217do_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} {} 1235do_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# 1256do_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} 1285faultsim_save_and_close 1286 1287do_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 1311faultsim_restore_and_reopen 1312sqlite3 db2 test.db 1313db2 eval {SELECT count(*) FROM t2} 1314db close 1315 1316do_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 1325db2 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# 1343proc custom_injectinstall {} { 1344 testvfs custom -default true 1345 custom filter {xWrite xUnlock} 1346} 1347proc custom_injectuninstall {} { 1348 catch {db close} 1349 catch {db2 close} 1350 custom delete 1351} 1352proc custom_injectstart {iFail} { 1353 custom ioerr $iFail 1 1354} 1355proc custom_injectstop {} { 1356 custom ioerr 1357} 1358set ::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 1366do_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} 1384faultsim_save_and_close 1385foreach {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 1409do_test pagerfault-31-pre { 1410 sqlite3_shutdown 1411 sqlite3_config_uri 1 1412} {SQLITE_OK} 1413do_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} 1424sqlite3_shutdown 1425sqlite3_config_uri 0 1426 1427do_test pagerfault-32-pre { 1428 reset_db 1429 execsql { 1430 CREATE TABLE t1(x); 1431 INSERT INTO t1 VALUES('one'); 1432 } 1433} {} 1434faultsim_save_and_close 1435 1436do_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} 1444sqlite3_shutdown 1445sqlite3_config_uri 0 1446 1447do_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} 1458do_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 1470do_test pagerfault-34-pre { 1471 reset_db 1472 execsql { 1473 CREATE TABLE t1(x PRIMARY KEY); 1474 } 1475} {} 1476faultsim_save_and_close 1477do_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 1490do_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} {} 1501testvfs tv -default 1 1502tv sectorsize 8192; 1503tv devchar [list] 1504do_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} 1511catch {db close} 1512tv delete 1513 1514sqlite3_shutdown 1515sqlite3_config_uri 1 1516do_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} {} 1527do_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 1549sqlite3_shutdown 1550sqlite3_config_uri 0 1551sqlite3_initialize 1552 1553finish_test 1554