Home | History | Annotate | Download | only in test
      1 # 2007 June 13
      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.
     12 #
     13 # This file implements tests to verify that ticket #2409 has been
     14 # fixed. More specifically, they verify that if SQLite cannot
     15 # obtain an EXCLUSIVE lock while trying to spill the cache during
     16 # any statement other than a COMMIT, an I/O error is returned instead
     17 # of SQLITE_BUSY.
     18 #
     19 # $Id: tkt2409.test,v 1.6 2008/08/28 17:46:19 drh Exp $
     20 
     21 # Test Outline:
     22 #
     23 #   tkt-2409-1.*: Cause a cache-spill during an INSERT that is within
     24 #       a db transaction but does not start a statement transaction.
     25 #       Verify that the transaction is automatically rolled back
     26 #       and SQLITE_IOERR_BLOCKED is returned
     27 #
     28 #       UPDATE: As of the pcache modifications, failing to upgrade to
     29 #       an exclusive lock when attempting a cache-spill is no longer an
     30 #       error. The pcache module allocates more space and keeps working
     31 #       in memory if this occurs.
     32 #
     33 #   tkt-2409-2.*: Cause a cache-spill while updating the change-counter
     34 #       during a database COMMIT. Verify that the transaction is not
     35 #       rolled back and SQLITE_BUSY is returned.
     36 #
     37 #   tkt-2409-3.*: Similar to 2409-1.*, but using many INSERT statements
     38 #       within a transaction instead of just one.
     39 #
     40 #       UPDATE: Again, pcache now just keeps working in main memory.
     41 #
     42 #   tkt-2409-4.*: Similar to 2409-1.*, but rig it so that the
     43 #       INSERT statement starts a statement transaction. Verify that
     44 #       SQLITE_BUSY is returned and the transaction is not rolled back.
     45 #
     46 #       UPDATE: This time, SQLITE_BUSY is not returned. pcache just uses
     47 #       more malloc()'d memory.
     48 #
     49 
     50 set testdir [file dirname $argv0]
     51 source $testdir/tester.tcl
     52 
     53 ifcapable !pager_pragmas {
     54   finish_test
     55   return
     56 }
     57 
     58 sqlite3_extended_result_codes $::DB 1
     59 
     60 # Aquire a read-lock on the database using handle [db2].
     61 #
     62 proc read_lock_db {} {
     63   if {$::STMT eq ""} {
     64     set ::STMT [sqlite3_prepare db2 {SELECT rowid FROM sqlite_master} -1 TAIL]
     65     set rc [sqlite3_step $::STMT]
     66     if {$rc eq "SQLITE_ERROR"} {
     67       unread_lock_db
     68       read_lock_db
     69     }
     70   }
     71 }
     72 
     73 # Release any read-lock obtained using [read_lock_db]
     74 #
     75 proc unread_lock_db {} {
     76   if {$::STMT ne ""} {
     77     sqlite3_finalize $::STMT
     78     set ::STMT ""
     79   }
     80 }
     81 
     82 # Open the db handle used by [read_lock_db].
     83 #
     84 sqlite3 db2 test.db
     85 set ::STMT ""
     86 
     87 do_test tkt2409-1.1 {
     88   execsql {
     89     PRAGMA cache_size=10;
     90     CREATE TABLE t1(x TEXT UNIQUE NOT NULL, y BLOB);
     91   }
     92   read_lock_db
     93   set ::zShort [string repeat 0123456789 1]
     94   set ::zLong  [string repeat 0123456789 1500]
     95   catchsql {
     96     BEGIN;
     97     INSERT INTO t1 VALUES($::zShort, $::zLong);
     98   }
     99 } {0 {}}
    100 
    101 do_test tkt2409-1.2 {
    102   sqlite3_errcode $::DB
    103 } {SQLITE_OK}
    104 
    105 # Check the integrity of the cache.
    106 #
    107 integrity_check tkt2409-1.3
    108 
    109 # Check that the transaction was rolled back. Because the INSERT
    110 # statement in which the "I/O error" occured did not open a statement
    111 # transaction, SQLite had no choice but to roll back the transaction.
    112 #
    113 do_test tkt2409-1.4 {
    114   unread_lock_db
    115   catchsql { ROLLBACK }
    116 } {0 {}}
    117 
    118 set ::zShort [string repeat 0123456789 1]
    119 set ::zLong  [string repeat 0123456789 1500]
    120 set ::rc 1
    121 for {set iCache 10} {$::rc} {incr iCache} {
    122   execsql "PRAGMA cache_size = $iCache"
    123   do_test tkt2409-2.1.$iCache {
    124     read_lock_db
    125     set ::rc [catch {
    126       execsql {
    127         BEGIN;
    128         INSERT INTO t1 VALUES($::zShort, $::zLong);
    129       }
    130     } msg]
    131     expr {($::rc == 1 && $msg eq "disk I/O error") || $::rc == 0}
    132   } {1}
    133 }
    134 
    135 do_test tkt2409-2.2 {
    136   catchsql {
    137     ROLLBACK;
    138     BEGIN;
    139     INSERT INTO t1 VALUES($::zShort, $::zLong);
    140     COMMIT;
    141   }
    142 } {1 {database is locked}}
    143 
    144 do_test tkt2409-2.3 {
    145   unread_lock_db
    146   catchsql {
    147     COMMIT;
    148   }
    149 } {0 {}}
    150 
    151 
    152 do_test tkt2409-3.1 {
    153   db close
    154   set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db]
    155   sqlite3_extended_result_codes $::DB 1
    156   execsql {
    157     PRAGMA cache_size=10;
    158     DELETE FROM t1;
    159   }
    160   read_lock_db
    161   set ::zShort [string repeat 0123456789 1]
    162   set ::zLong  [string repeat 0123456789 1500]
    163   catchsql {
    164     BEGIN;
    165     INSERT INTO t1 SELECT $::zShort, $::zLong;
    166   }
    167 } {0 {}}
    168 
    169 do_test tkt2409-3.2 {
    170   sqlite3_errcode $::DB
    171 } {SQLITE_OK}
    172 
    173 # Check the integrity of the cache.
    174 #
    175 integrity_check tkt2409-3.3
    176 
    177 # Check that the transaction was rolled back. Because the INSERT
    178 # statement in which the "I/O error" occured did not open a statement
    179 # transaction, SQLite had no choice but to roll back the transaction.
    180 #
    181 do_test tkt2409-3.4 {
    182   unread_lock_db
    183   catchsql { ROLLBACK }
    184 } {0 {}}
    185 integrity_check tkt2409-3.5
    186 
    187 expr {srand(1)}
    188 do_test tkt2409-4.1 {
    189   execsql {
    190     PRAGMA cache_size=20;
    191     DROP TABLE t1;
    192     CREATE TABLE t1 (x TEXT UNIQUE NOT NULL);
    193   }
    194 
    195   unset -nocomplain t1
    196   array unset t1
    197   set t1(0) 1
    198   set sql ""
    199   for {set i 0} {$i<5000} {incr i} {
    200     set r 0
    201     while {[info exists t1($r)]} {
    202       set r [expr {int(rand()*1000000000)}]
    203     }
    204     set t1($r) 1
    205     append sql "INSERT INTO t1 VALUES('some-text-$r');"
    206   }
    207 
    208   read_lock_db
    209   execsql BEGIN
    210   catchsql $sql
    211 } {0 {}}
    212 
    213 do_test tkt2409-4.2 {
    214   sqlite3_errcode $::DB
    215 } {SQLITE_OK}
    216 
    217 # Check the integrity of the cache.
    218 #
    219 integrity_check tkt2409-4.3
    220 
    221 do_test tkt2409-4.4 {
    222   catchsql { ROLLBACK }
    223 } {0 {}}
    224 integrity_check tkt2409-4.5
    225 
    226 unread_lock_db
    227 db2 close
    228 unset -nocomplain t1
    229 finish_test
    230