persistentstorage/sqlite3api/TEST/TclScript/tkt2409.test
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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