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