AryaWu/sqlite
0
1# 2010 June 152#3# The author disclaims copyright to this source code. In place of4# 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.tcl15source $testdir/lock_common.tcl16source $testdir/malloc_common.tcl17 18if {[permutation] == "inmemory_journal"} {19 finish_test20 return21}22 23if {$::tcl_platform(os) eq "Windows NT"} {24 finish_test25 return26}27 28set a_string_counter 129proc a_string {n} {30 global a_string_counter31 incr a_string_counter32 string range [string repeat "${a_string_counter}." $n] 1 $n33}34db func a_string a_string35 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_close54} {}55do_faultsim_test pagerfault-1 -prep {56 faultsim_restore_and_reopen57} -body {58 execsql { SELECT count(*) FROM t1 }59} -test {60 faultsim_test_result {0 4} 61 faultsim_integrity_check62 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 the70# database file.71#72do_test pagerfault-2-pre1 {73 testvfs tv -default 174 tv filter xSync75 tv script xSyncCb76 proc xSyncCb {filename args} {77 if {[string match *journal filename]==0} faultsim_save78 }79 faultsim_delete_and_reopen80 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; -- 487 INSERT INTO abc SELECT * FROM abc; -- 888 INSERT INTO abc SELECT * FROM abc; -- 1689 INSERT INTO abc SELECT * FROM abc; -- 3290 INSERT INTO abc SELECT * FROM abc; -- 6491 INSERT INTO abc SELECT * FROM abc; -- 12892 INSERT INTO abc SELECT * FROM abc; -- 25693 COMMIT;94 PRAGMA page_size = 1024;95 VACUUM;96 }97 db close98 tv delete99} {}100do_faultsim_test pagerfault-2 -prep {101 faultsim_restore_and_reopen102} -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_check108 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 created114# as part of a multi-file transaction.115#116do_test pagerfault-3-pre1 {117 testvfs tstvfs -default 1118 tstvfs filter xDelete119 tstvfs script xDeleteCallback120 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_reopen127 db func a_string a_string128 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 close152 tstvfs delete153} {}154do_faultsim_test pagerfault-3 -prep {155 faultsim_restore_and_reopen156} -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_check165 catchsql { ATTACH 'test.db2' AS aux }166 if {[db one { SELECT count(*) FROM t1 }] != 4167 || [db one { SELECT count(*) FROM t2 }] != 4168 } {169 error "Database content appears incorrect"170 }171}172 173#-------------------------------------------------------------------------174# Test fault-injection as part of a vanilla, no-transaction, INSERT175# statement.176#177do_faultsim_test pagerfault-4 -prep {178 faultsim_delete_and_reopen179} -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_check188}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_reopen201 db func a_string a_string202 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_close209} {}210do_faultsim_test pagerfault-5.1 -prep {211 faultsim_restore_and_reopen212 db func a_string a_string213 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_check219}220do_faultsim_test pagerfault-5.2 -prep {221 faultsim_restore_and_reopen222 db func a_string a_string223 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_check232}233do_faultsim_test pagerfault-5.3 -faults oom-transient -prep {234 faultsim_restore_and_reopen235 db func a_string a_string236 forcedelete test2.db test2.db-journal test2.db-wal237 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_check257 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_reopen268 db func a_string a_string269 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_close274} {}275 276do_faultsim_test pagerfault-6.1 -prep {277 faultsim_restore_and_reopen278 db func a_string a_string279 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_check286}287 288# The unix vfs xAccess() method considers a file zero bytes in size to289# "not exist". This proc overrides that behaviour so that a zero length290# 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 xAccess298 shmfault script xAccess299 300 faultsim_restore_and_reopen301 db func a_string a_string302 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_check309}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_reopen315# 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_close331# } {}332# do_faultsim_test pagerfault-6 -prep {333# faultsim_restore_and_reopen334# } -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_check351# }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 a357# dirty page to the file-system in order to free up memory, the pager enters358# the "error state". An IO error causes SQLite to roll back the current359# transaction (exiting the error state). A FULL error, however, may only360# rollback the current statement.361#362# This block tests that nothing goes wrong if a FULL error occurs while363# writing a dirty page out to free memory from within a statement that has364# opened a statement transaction.365#366do_test pagerfault-7-pre1 {367 faultsim_delete_and_reopen368 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; -- 4374 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 8375 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 16376 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 32377 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 64378 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_close384} {}385do_faultsim_test pagerfault-7 -prep {386 faultsim_restore_and_reopen387 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 COMMIT395} -test {396 faultsim_test_result {0 {}}397 faultsim_integrity_check398}399 400do_test pagerfault-8-pre1 {401 faultsim_delete_and_reopen402 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; -- 4409 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 8410 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 16411 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 32412 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 64413 COMMIT;414 }415 faultsim_save_and_close416 set filesize [file size test.db]417 set {} {}418} {}419do_test pagerfault-8-pre2 {420 faultsim_restore_and_reopen421 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_reopen426 execsql { 427 BEGIN;428 DELETE FROM t1 WHERE a>32;429 }430} -body {431 execsql COMMIT432} -test {433 faultsim_test_result {0 {}}434 faultsim_integrity_check435}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 surrounding440# 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_reopen445 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_close456} {}457do_faultsim_test pagerfault-9.1 -prep {458 faultsim_restore_and_reopen459 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_count473 }474} -test {475 faultsim_test_result {0 2}476 faultsim_integrity_check477 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_check508 faultsim_integrity_check509 }510}511 512#-------------------------------------------------------------------------513# Test fault injection with transaction savepoints (savepoints created514# when a SAVEPOINT command is executed outside of any other savepoint515# or transaction context).516#517do_test pagerfault-9-pre1 {518 faultsim_delete_and_reopen519 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_close538} {}539do_faultsim_test pagerfault-11 -prep {540 faultsim_restore_and_reopen541 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_check557}558 559 560#-------------------------------------------------------------------------561# Test fault injection when writing to a database file that resides on562# a file-system with a sector-size larger than the database page-size.563#564do_test pagerfault-12-pre1 {565 testvfs ss_layer -default 1566 ss_layer sectorsize 4096567 faultsim_delete_and_reopen568 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_close585} {}586 587do_faultsim_test pagerfault-12a -prep {588 faultsim_restore_and_reopen589 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_check598}599 600do_test pagerfault-12-pre2 {601 faultsim_restore_and_reopen602 execsql {603 CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 10;604 }605 faultsim_save_and_close606} {}607do_faultsim_test pagerfault-12b -prep {608 faultsim_restore_and_reopen609 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_check620}621 622catch { db close }623ss_layer delete624 625 626#-------------------------------------------------------------------------627# Test fault injection when SQLite opens a database where the size of the628# database file is zero bytes but the accompanying journal file is larger629# 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 valid631# hot-journal file.632#633do_test pagerfault-13-pre1 {634 faultsim_delete_and_reopen635 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 close644 forcedelete test.db645 faultsim_save646} {}647do_faultsim_test pagerfault-13 -prep {648 faultsim_restore_and_reopen649} -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_reopen660 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_close672} {}673 674do_faultsim_test pagerfault-14a -prep {675 faultsim_restore_and_reopen676} -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 created683# as an in-memory database. This test will not work in that case, as it684# is not possible to change the page-size of an in-memory database. Even685# using the backup API.686#687# Update: It is no longer possible to change the page size of any temp688# database after it has been created.689#690do_faultsim_test pagerfault-14b -prep {691 catch { db2 close }692 faultsim_restore_and_reopen693 sqlite3 db2 ""694 db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) }695} -body {696 sqlite3_backup B db2 main db main697 B step 200698 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_reopen710 sqlite3 db2 test.db2711 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 main718 B step 200719 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_reopen729 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_close738} {}739do_faultsim_test pagerfault-15 -prep {740 faultsim_restore_and_reopen741 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_check752}753 754 755do_test pagerfault-16-pre1 {756 faultsim_delete_and_reopen757 execsql { CREATE TABLE t1(x, y UNIQUE) }758 faultsim_save_and_close759} {}760do_faultsim_test pagerfault-16 -prep {761 faultsim_restore_and_reopen762} -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_check778}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_reopen786 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_close793} {}794do_faultsim_test pagerfault-17a -prep {795 faultsim_restore_and_reopen796} -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_check804}805do_faultsim_test pagerfault-17b -prep {806 faultsim_restore_and_reopen807 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_check817}818do_faultsim_test pagerfault-17c -prep {819 faultsim_restore_and_reopen820 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_check829}830do_faultsim_test pagerfault-17d -prep {831 catch { db2 close }832 faultsim_restore_and_reopen833 sqlite3 db2 test.db834 execsql { PRAGMA journal_mode = delete }835 execsql { PRAGMA journal_mode = wal }836 execsql { INSERT INTO t1 VALUES(99, 'Bradman') } db2837} -body {838 execsql { PRAGMA journal_mode = delete }839} -test {840 faultsim_test_result {1 {database is locked}}841 faultsim_integrity_check842}843do_faultsim_test pagerfault-17e -prep {844 catch { db2 close }845 faultsim_restore_and_reopen846 sqlite3 db2 test.db847 execsql { PRAGMA journal_mode = delete }848 execsql { PRAGMA journal_mode = wal }849 set ::chan [launch_testfixture]850 testfixture $::chan {851 sqlite3 db test.db852 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_check861}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_reopen869 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_close878} {}879do_faultsim_test pagerfault-18 -prep {880 faultsim_restore_and_reopen881 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_check890}891 892do_faultsim_test pagerfault-19a -prep {893 sqlite3 db :memory:894 db func a_string a_string895 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_reopen914 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_close924} {}925do_faultsim_test pagerfault-19b -prep {926 faultsim_restore_and_reopen927} -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_reopen951 execsql {952 PRAGMA cache_size = 10;953 PRAGMA auto_vacuum = FULL;954 CREATE TABLE t0(a, b);955 }956 faultsim_save_and_close957} {}958do_faultsim_test pagerfault-20 -prep {959 faultsim_restore_and_reopen960} -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_reopen974 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_close980} {}981do_faultsim_test pagerfault-21 -prep {982 faultsim_restore_and_reopen983} -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_reopen999 execsql {1000 PRAGMA page_size = 1024;1001 PRAGMA journal_mode = WAL;1002 PRAGMA journal_mode = DELETE;1003 }1004 db close1005 hexio_write test.db 20 101006 hexio_write test.db 105 03F01007 sqlite3 db test.db1008 db func a_string a_string1009 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_close1017} {}1018 1019do_faultsim_test pagerfault-21 -prep {1020 faultsim_restore_and_reopen1021} -body {1022 execsql { INSERT INTO t0 SELECT a||'x', b||'x' FROM t0 }1023} -test {1024 faultsim_test_result {0 {}}1025 faultsim_integrity_check1026}1027ifcapable crashtest {1028 faultsim_delete_and_reopen1029 execsql {1030 PRAGMA page_size = 1024;1031 PRAGMA journal_mode = WAL;1032 PRAGMA journal_mode = DELETE;1033 }1034 db close1035 hexio_write test.db 20 101036 hexio_write test.db 105 03F01037 1038 sqlite3 db test.db1039 db func a_string a_string1040 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_close1046 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.db1058 execsql { PRAGMA integrity_check }1059 } {ok}1060 db close1061 }1062}1063 1064 1065#-------------------------------------------------------------------------1066# When a 3.7.0 client opens a write-transaction on a database file that1067# has been appended to or truncated by a pre-370 client, it updates1068# the db-size in the file header immediately. This test case provokes1069# errors during that operation.1070#1071do_test pagerfault-22-pre1 {1072 faultsim_delete_and_reopen1073 db func a_string a_string1074 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 close1084 sql36231 { INSERT INTO t1 VALUES(a_string(3000)) }1085 faultsim_save_and_close1086} {}1087do_faultsim_test pagerfault-22 -prep {1088 faultsim_restore_and_reopen1089} -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_check1095}1096 1097#-------------------------------------------------------------------------1098# Provoke an OOM error during a commit of multi-file transaction. One of1099# 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_OK1105# PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR1106# 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_check1127}1128 1129do_faultsim_test pagerfault-24 -prep {1130 faultsim_delete_and_reopen1131 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_reopen1152 db func a_string a_string1153 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_close1165} {}1166do_faultsim_test pagerfault-25 -prep {1167 faultsim_restore_and_reopen1168 db func a_string a_string1169 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 301178} -test {1179 catch { lockrows 30 }1180 catch { db eval COMMIT }1181 close $::channel1182 faultsim_test_result {0 {}} 1183}1184 1185do_faultsim_test pagerfault-26 -prep {1186 faultsim_delete_and_reopen1187 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 {