github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/pagerfault.test (about)

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