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>