gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/ioerr2.test (about)

     1  # 2007 April 2
     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  # This file implements regression tests for SQLite library.  The
    12  # focus of this file is testing for correct handling of I/O errors
    13  # such as writes failing because the disk is full.
    14  # 
    15  # The tests in this file use special facilities that are only
    16  # available in the SQLite test fixture.
    17  #
    18  # $Id: ioerr2.test,v 1.12 2009/06/05 17:09:12 drh Exp $
    19  
    20  set testdir [file dirname $argv0]
    21  source $testdir/tester.tcl
    22  
    23  ifcapable !integrityck {
    24    finish_test
    25    return
    26  }
    27  
    28  do_test ioerr2-1.1 {
    29    execsql {
    30      PRAGMA cache_size = 10;
    31      PRAGMA default_cache_size = 10;
    32      CREATE TABLE t1(a, b, PRIMARY KEY(a, b));
    33      INSERT INTO t1 VALUES(randstr(400,400),randstr(400,400));
    34      INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 2
    35      INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 4
    36      INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 8
    37      INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 16
    38      INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) FROM t1; -- 32
    39    }
    40  } {}
    41  
    42  set ::cksum [execsql {SELECT md5sum(a, b) FROM t1}]
    43  proc check_db {testname} {
    44  
    45    # Make sure no I/O errors are simulated in this proc.
    46    set ::sqlite_io_error_hit 0
    47    set ::sqlite_io_error_persist 0
    48    set ::sqlite_io_error_pending 0
    49  
    50    # Run an integrity-check. If "disk I/O error" is returned, the
    51    # pager must be in error state. In this case open a new database
    52    # connection. Otherwise, try a ROLLBACK, in case a transaction 
    53    # is still active.
    54    set rc [catch {execsql {PRAGMA integrity_check}} msg]
    55    if {$rc && ($msg eq "disk I/O error" || $msg eq "database is locked")} {
    56      db close
    57      sqlite3 db test.db
    58      set refcnt 0
    59    } else {
    60      if {$rc || $msg ne "ok"} {
    61        error $msg
    62      }
    63      catch {execsql ROLLBACK}
    64    }
    65  
    66    # Check that the database checksum is still $::cksum, and that
    67    # the integrity-check passes.
    68    set ck [execsql {SELECT md5sum(a, b) FROM t1}]
    69    do_test ${testname}.cksum [list set ck $ck] $::cksum
    70    integrity_check ${testname}.integrity
    71    do_test ${testname}.refcnt {
    72      lindex [sqlite3_pager_refcounts db] 0
    73    } 0
    74  }
    75  
    76  check_db ioerr2-2
    77  
    78  set sql {
    79    PRAGMA cache_size = 10;
    80    PRAGMA default_cache_size = 10;
    81    BEGIN;
    82    DELETE FROM t1 WHERE (oid%7)==0;
    83    INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) 
    84      WHERE (random()%7)==0;
    85    UPDATE t1 SET a = randstr(400,400), b = randstr(400,400) 
    86      WHERE (random()%7)==0;
    87    ROLLBACK;
    88  }
    89  
    90  foreach bPersist [list 0 1] {
    91    set ::go 1
    92    for {set ::N 1} {$::go} {incr ::N} {
    93      db close
    94      sqlite3 db test.db
    95      set ::sqlite_io_error_hit 0
    96      set ::sqlite_io_error_persist $bPersist
    97      set ::sqlite_io_error_pending $::N
    98  
    99      foreach {::go res} [catchsql $sql] {}
   100      check_db ioerr2-3.$bPersist.$::N
   101    }
   102  }
   103  foreach bPersist [list 0 1] {
   104    set ::go 1
   105    for {set ::N 1} {$::go} {incr ::N} {
   106      set ::sqlite_io_error_hit 0
   107      set ::sqlite_io_error_persist $bPersist
   108      set ::sqlite_io_error_pending $::N
   109  
   110      foreach {::go res} [catchsql $sql] {}
   111      check_db ioerr2-4.[expr {$bPersist+2}].$::N
   112    }
   113  }
   114  
   115  # When this test was written, an IO error within the UPDATE statement caused
   116  # a rollback, which tripped all read-cursors, causing the outer SELECT to
   117  # fail with "abort due to ROLLBACK". Now, the loop continues until the UPDATE
   118  # is run successfully. At this point the next IO error occurs within the 
   119  # SELECT - throwing the "disk I/O error" that the test case now expects.
   120  #
   121  do_test ioerr2-5 {
   122    execsql {
   123      CREATE TABLE t2 AS SELECT * FROM t1;
   124      PRAGMA temp_store = memory;
   125    }
   126    set ::sqlite_io_error_persist 0
   127    set ::go 1
   128    set rc [catch {
   129      for {set ::N 2} {$::N<200} {incr ::N} {
   130        db eval {SELECT * FROM t1 WHERE rowid IN (1, 5, 10, 15, 20)} {
   131          set ::sqlite_io_error_hit 0
   132          set ::sqlite_io_error_pending $::N
   133          set sql {UPDATE t2 SET b = randstr(400,400)}
   134          foreach {::go res} [catchsql $sql] {}
   135        }
   136      }
   137    } msg]
   138    list $rc $msg
   139  } {1 {disk I/O error}} ;# used to be "{1 {abort due to ROLLBACK}}"
   140  
   141  if {$::tcl_platform(platform) == "unix"} {
   142    # Cause the call to xAccess used by [pragma temp_store_directory] to
   143    # determine if the specified directory is writable to fail. This causes
   144    # SQLite to report "not a writable directory", which is probably the
   145    # right answer.
   146    #
   147    do_test ioerr2-6 {
   148      set ::sqlite_io_error_hit 0
   149      set ::sqlite_io_error_pending 1
   150      catchsql {PRAGMA temp_store_directory = '/tmp/'}
   151    } {1 {not a writable directory}}
   152  }
   153  
   154  do_ioerr_test ioerr2-7 -persist 0 -sqlprep {
   155    PRAGMA cache_size = 10;
   156    PRAGMA auto_vacuum = 1;
   157    CREATE TABLE ab(a, b);
   158    CREATE TABLE de(d, e);
   159    INSERT INTO ab VALUES(1, randstr(200,200));
   160    INSERT INTO ab SELECT a+1, randstr(200,200) FROM ab;
   161    INSERT INTO ab SELECT a+2, randstr(200,200) FROM ab;
   162    INSERT INTO ab SELECT a+4, randstr(200,200) FROM ab;
   163    INSERT INTO ab SELECT a+8, randstr(200,200) FROM ab;
   164    INSERT INTO ab SELECT a+16, randstr(200,200) FROM ab;
   165    INSERT INTO ab SELECT a+32, randstr(200,200) FROM ab;
   166    INSERT INTO ab SELECT a+64, randstr(200,200) FROM ab;
   167    INSERT INTO de SELECT * FROM ab;
   168  } -sqlbody {
   169    BEGIN;
   170    UPDATE ab SET b = randstr(200,200);
   171    UPDATE de SET e = randstr(200,200) WHERE d = (SELECT max(d) FROM de);
   172    DELETE FROM ab;
   173    COMMIT;
   174  }
   175  
   176  finish_test