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

     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" occurred 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" occurred 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