Annotation of embedaddon/sqlite3/test/ioerr5.test, revision 1.1
1.1 ! misho 1: # 2008 May 12
! 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: # This file tests that if sqlite3_release_memory() is called to reclaim
! 13: # memory from a pager that is in the error-state, SQLite does not
! 14: # incorrectly write dirty pages out to the database (not safe to do
! 15: # once the pager is in error state).
! 16: #
! 17: # $Id: ioerr5.test,v 1.5 2008/08/28 18:35:34 danielk1977 Exp $
! 18:
! 19: set testdir [file dirname $argv0]
! 20: source $testdir/tester.tcl
! 21:
! 22: ifcapable !memorymanage||!shared_cache {
! 23: finish_test
! 24: return
! 25: }
! 26:
! 27: db close
! 28:
! 29: set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
! 30: set ::soft_limit [sqlite3_soft_heap_limit 1048576]
! 31:
! 32: # This procedure prepares, steps and finalizes an SQL statement via the
! 33: # UTF-16 APIs. The text representation of an SQLite error code is returned
! 34: # ("SQLITE_OK", "SQLITE_IOERR" etc.). The actual results returned by the
! 35: # SQL statement, if it is a SELECT, are not available.
! 36: #
! 37: # This can be useful for testing because it forces SQLite to make an extra
! 38: # call to sqlite3_malloc() when translating from the supplied UTF-16 to
! 39: # the UTF-8 encoding used internally.
! 40: #
! 41: proc dosql16 {zSql {db db}} {
! 42: set sql [encoding convertto unicode $zSql]
! 43: append sql "\00\00"
! 44: set stmt [sqlite3_prepare16 $db $sql -1 {}]
! 45: sqlite3_step $stmt
! 46: set rc [sqlite3_finalize $stmt]
! 47: }
! 48:
! 49: proc compilesql16 {zSql {db db}} {
! 50: set sql [encoding convertto unicode $zSql]
! 51: append sql "\00\00"
! 52: set stmt [sqlite3_prepare16 $db $sql -1 {}]
! 53: set rc [sqlite3_finalize $stmt]
! 54: }
! 55:
! 56: # Open two database connections (handle db and db2) to database "test.db".
! 57: #
! 58: proc opendatabases {} {
! 59: catch {db close}
! 60: catch {db2 close}
! 61: sqlite3 db test.db
! 62: sqlite3 db2 test.db
! 63: db2 cache size 0
! 64: db cache size 0
! 65: execsql {
! 66: pragma page_size=512;
! 67: pragma auto_vacuum=2;
! 68: pragma cache_size=16;
! 69: }
! 70: }
! 71:
! 72: # Open two database connections and create a single table in the db.
! 73: #
! 74: do_test ioerr5-1.0 {
! 75: opendatabases
! 76: execsql { CREATE TABLE A(Id INTEGER, Name TEXT) }
! 77: } {}
! 78:
! 79: foreach locking_mode {normal exclusive} {
! 80: set nPage 2
! 81: for {set iFail 1} {$iFail<200} {incr iFail} {
! 82: sqlite3_soft_heap_limit 1048576
! 83: opendatabases
! 84: execsql { pragma locking_mode=exclusive }
! 85: set nRow [db one {SELECT count(*) FROM a}]
! 86:
! 87: # Dirty (at least) one of the pages in the cache.
! 88: do_test ioerr5-1.$locking_mode-$iFail.1 {
! 89: execsql {
! 90: BEGIN EXCLUSIVE;
! 91: INSERT INTO a VALUES(1, 'ABCDEFGHIJKLMNOP');
! 92: }
! 93: } {}
! 94:
! 95: # Open a read-only cursor on table "a". If the COMMIT below is
! 96: # interrupted by a persistent IO error, the pager will transition to
! 97: # PAGER_ERROR state. If there are no other read-only cursors open,
! 98: # from there the pager immediately discards all cached data and
! 99: # switches to PAGER_OPEN state. This read-only cursor stops that
! 100: # from happening, leaving the pager stuck in PAGER_ERROR state.
! 101: #
! 102: set channel [db incrblob -readonly a Name [db last_insert_rowid]]
! 103:
! 104: # Now try to commit the transaction. Cause an IO error to occur
! 105: # within this operation, which moves the pager into the error state.
! 106: #
! 107: set ::sqlite_io_error_persist 1
! 108: set ::sqlite_io_error_pending $iFail
! 109: do_test ioerr5-1.$locking_mode-$iFail.2 {
! 110: set rc [catchsql {COMMIT}]
! 111: list
! 112: } {}
! 113: set ::sqlite_io_error_hit 0
! 114: set ::sqlite_io_error_persist 0
! 115: set ::sqlite_io_error_pending 0
! 116:
! 117: # Read the contents of the database file into a Tcl variable.
! 118: #
! 119: set fd [open test.db]
! 120: fconfigure $fd -translation binary -encoding binary
! 121: set zDatabase [read $fd]
! 122: close $fd
! 123:
! 124: # Set a very low soft-limit and then try to compile an SQL statement
! 125: # from UTF-16 text. To do this, SQLite will need to reclaim memory
! 126: # from the pager that is in error state. Including that associated
! 127: # with the dirty page.
! 128: #
! 129: do_test ioerr5-1.$locking_mode-$iFail.3 {
! 130: sqlite3_soft_heap_limit 1024
! 131: compilesql16 "SELECT 10"
! 132: } {SQLITE_OK}
! 133:
! 134: close $channel
! 135:
! 136: # Ensure that nothing was written to the database while reclaiming
! 137: # memory from the pager in error state.
! 138: #
! 139: do_test ioerr5-1.$locking_mode-$iFail.4 {
! 140: set fd [open test.db]
! 141: fconfigure $fd -translation binary -encoding binary
! 142: set zDatabase2 [read $fd]
! 143: close $fd
! 144: expr {$zDatabase eq $zDatabase2}
! 145: } {1}
! 146:
! 147: if {$rc eq [list 0 {}]} {
! 148: do_test ioerr5.1-$locking_mode-$iFail.3 {
! 149: execsql { SELECT count(*) FROM a }
! 150: } [expr $nRow+1]
! 151: break
! 152: }
! 153: }
! 154: }
! 155:
! 156: # Make sure this test script doesn't leave any files open.
! 157: #
! 158: do_test ioerr5-1.X {
! 159: catch { db close }
! 160: catch { db2 close }
! 161: set sqlite_open_file_count
! 162: } 0
! 163:
! 164: do_test ioerr5-2.0 {
! 165: sqlite3 db test.db
! 166: execsql { CREATE INDEX i1 ON a(id, name); }
! 167: } {}
! 168:
! 169: foreach locking_mode {exclusive normal} {
! 170: for {set iFail 1} {$iFail<200} {incr iFail} {
! 171: sqlite3_soft_heap_limit 1048576
! 172: opendatabases
! 173: execsql { pragma locking_mode=exclusive }
! 174: set nRow [db one {SELECT count(*) FROM a}]
! 175:
! 176: do_test ioerr5-2.$locking_mode-$iFail.1 {
! 177: execsql {
! 178: BEGIN EXCLUSIVE;
! 179: INSERT INTO a VALUES(1, 'ABCDEFGHIJKLMNOP');
! 180: }
! 181: } {}
! 182:
! 183: set ::sqlite_io_error_persist 1
! 184: set ::sqlite_io_error_pending $iFail
! 185:
! 186: sqlite3_release_memory 10000
! 187:
! 188: set error_hit $::sqlite_io_error_hit
! 189: set ::sqlite_io_error_hit 0
! 190: set ::sqlite_io_error_persist 0
! 191: set ::sqlite_io_error_pending 0
! 192: if {$error_hit} {
! 193: do_test ioerr5-2.$locking_mode-$iFail.3a {
! 194: catchsql COMMIT
! 195: } {1 {disk I/O error}}
! 196: } else {
! 197: do_test ioerr5-2.$locking_mode-$iFail.3b {
! 198: execsql COMMIT
! 199: } {}
! 200: break
! 201: }
! 202: }
! 203: }
! 204:
! 205: # Make sure this test script doesn't leave any files open.
! 206: #
! 207: do_test ioerr5-2.X {
! 208: catch { db close }
! 209: catch { db2 close }
! 210: set sqlite_open_file_count
! 211: } 0
! 212:
! 213: sqlite3_enable_shared_cache $::enable_shared_cache
! 214: sqlite3_soft_heap_limit $::soft_limit
! 215:
! 216: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>