Annotation of embedaddon/sqlite3/test/journal2.test, revision 1.1
1.1 ! misho 1: # 2010 June 16
! 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. Specifically,
! 12: # it tests SQLite when using a VFS that claims the SAFE_DELETE property.
! 13: #
! 14:
! 15: set testdir [file dirname $argv0]
! 16: source $testdir/tester.tcl
! 17: source $testdir/lock_common.tcl
! 18: source $testdir/malloc_common.tcl
! 19: db close
! 20:
! 21: if {[permutation] == "inmemory_journal"} {
! 22: finish_test
! 23: return
! 24: }
! 25:
! 26: set a_string_counter 1
! 27: proc a_string {n} {
! 28: global a_string_counter
! 29: incr a_string_counter
! 30: string range [string repeat "${a_string_counter}." $n] 1 $n
! 31: }
! 32:
! 33: # Create a [testvfs] and install it as the default VFS. Set the device
! 34: # characteristics flags to "SAFE_DELETE".
! 35: #
! 36: testvfs tvfs -default 1
! 37: tvfs devchar {undeletable_when_open powersafe_overwrite}
! 38:
! 39: # Set up a hook so that each time a journal file is opened, closed or
! 40: # deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
! 41: # segment of the journal file-name (i.e. "test.db-journal") are appended to
! 42: # global list variable $::oplog.
! 43: #
! 44: tvfs filter {xOpen xClose xDelete}
! 45: tvfs script journal_op_catcher
! 46: proc journal_op_catcher {method filename args} {
! 47:
! 48: # If global variable ::tvfs_error_on_write is defined, then return an
! 49: # IO error to every attempt to modify the file-system. Otherwise, return
! 50: # SQLITE_OK.
! 51: #
! 52: if {[info exists ::tvfs_error_on_write]} {
! 53: if {[lsearch {xDelete xWrite xTruncate} $method]>=0} {
! 54: return SQLITE_IOERR
! 55: }
! 56: }
! 57:
! 58: # The rest of this command only deals with xOpen(), xClose() and xDelete()
! 59: # operations on journal files. If this invocation does not represent such
! 60: # an operation, return with no further ado.
! 61: #
! 62: set f [file tail $filename]
! 63: if {[string match *journal $f]==0} return
! 64: if {[lsearch {xOpen xDelete xClose} $method]<0} return
! 65:
! 66: # Append a record of this operation to global list variable $::oplog.
! 67: #
! 68: lappend ::oplog $method $f
! 69:
! 70: # If this is an attempt to delete a journal file for which there exists
! 71: # one ore more open handles, return an error. The code in test_vfs.c
! 72: # will not invoke the xDelete method of the "real" VFS in this case.
! 73: #
! 74: if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
! 75: switch -- $method {
! 76: xOpen { incr ::open_journals($f) +1 }
! 77: xClose { incr ::open_journals($f) -1 }
! 78: xDelete { if {$::open_journals($f)>0} { return SQLITE_IOERR } }
! 79: }
! 80:
! 81: return ""
! 82: }
! 83:
! 84:
! 85: do_test journal2-1.1 {
! 86: set ::oplog [list]
! 87: sqlite3 db test.db
! 88: execsql { CREATE TABLE t1(a, b) }
! 89: set ::oplog
! 90: } {xOpen test.db-journal xClose test.db-journal xDelete test.db-journal}
! 91: do_test journal2-1.2 {
! 92: set ::oplog [list]
! 93: execsql {
! 94: PRAGMA journal_mode = truncate;
! 95: INSERT INTO t1 VALUES(1, 2);
! 96: }
! 97: set ::oplog
! 98: } {xOpen test.db-journal}
! 99: do_test journal2-1.3 {
! 100: set ::oplog [list]
! 101: execsql { INSERT INTO t1 VALUES(3, 4) }
! 102: set ::oplog
! 103: } {}
! 104: do_test journal2-1.4 { execsql { SELECT * FROM t1 } } {1 2 3 4}
! 105:
! 106: # Add a second connection. This connection attempts to commit data in
! 107: # journal_mode=DELETE mode. When it tries to delete the journal file,
! 108: # the VFS layer returns an IO error.
! 109: #
! 110: do_test journal2-1.5 {
! 111: set ::oplog [list]
! 112: sqlite3 db2 test.db
! 113: execsql { PRAGMA journal_mode = delete } db2
! 114: catchsql { INSERT INTO t1 VALUES(5, 6) } db2
! 115: } {1 {disk I/O error}}
! 116: do_test journal2-1.6 { file exists test.db-journal } 1
! 117: do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
! 118: do_test journal2-1.8 {
! 119: execsql { PRAGMA journal_mode = truncate } db2
! 120: execsql { INSERT INTO t1 VALUES(5, 6) } db2
! 121: } {}
! 122: do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}
! 123:
! 124: # Grow the database until it is reasonably large.
! 125: #
! 126: do_test journal2-1.10 {
! 127: db2 close
! 128: db func a_string a_string
! 129: execsql {
! 130: CREATE TABLE t2(a UNIQUE, b UNIQUE);
! 131: INSERT INTO t2 VALUES(a_string(200), a_string(300));
! 132: INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 2
! 133: INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 4
! 134: INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 8
! 135: INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 16
! 136: INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 32
! 137: INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 64
! 138: }
! 139: file size test.db-journal
! 140: } {0}
! 141: do_test journal2-1.11 {
! 142: set sz [expr [file size test.db] / 1024]
! 143: expr {$sz>120 && $sz<200}
! 144: } 1
! 145:
! 146: # Using new connection [db2] (with journal_mode=DELETE), write a lot of
! 147: # data to the database. So that many pages within the database file are
! 148: # modified before the transaction is committed.
! 149: #
! 150: # Then, enable simulated IO errors in all calls to xDelete, xWrite
! 151: # and xTruncate before committing the transaction and closing the
! 152: # database file. From the point of view of other file-system users, it
! 153: # appears as if the process hosting [db2] unexpectedly exited.
! 154: #
! 155: do_test journal2-1.12 {
! 156: sqlite3 db2 test.db
! 157: execsql {
! 158: PRAGMA cache_size = 10;
! 159: BEGIN;
! 160: INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2; -- 128
! 161: } db2
! 162: } {}
! 163: do_test journal2-1.13 {
! 164: tvfs filter {xOpen xClose xDelete xWrite xTruncate}
! 165: set ::tvfs_error_on_write 1
! 166: catchsql { COMMIT } db2
! 167: } {1 {disk I/O error}}
! 168: db2 close
! 169: unset ::tvfs_error_on_write
! 170: forcecopy test.db testX.db
! 171:
! 172: do_test journal2-1.14 { file exists test.db-journal } 1
! 173: do_test journal2-1.15 {
! 174: execsql {
! 175: SELECT count(*) FROM t2;
! 176: PRAGMA integrity_check;
! 177: }
! 178: } {64 ok}
! 179:
! 180: # This block checks that in the test case above, connection [db2] really
! 181: # did begin writing to the database file before it hit IO errors. If
! 182: # this is true, then the copy of the database file made before [db]
! 183: # rolled back the hot journal should fail the integrity-check.
! 184: #
! 185: do_test journal2-1.16 {
! 186: set sz [expr [file size testX.db] / 1024]
! 187: expr {$sz>240 && $sz<400}
! 188: } 1
! 189: do_test journal2-1.17 {
! 190: expr {[catchsql { PRAGMA integrity_check } db] == "0 ok"}
! 191: } {1}
! 192: do_test journal2-1.20 {
! 193: sqlite3 db2 testX.db
! 194: expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
! 195: } {0}
! 196: do_test journal2-1.21 {
! 197: db2 close
! 198: } {}
! 199: db close
! 200:
! 201: #-------------------------------------------------------------------------
! 202: # Test that it is possible to switch from journal_mode=truncate to
! 203: # journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and
! 204: # delete the journal file when committing the transaction that switches
! 205: # the system to WAL mode.
! 206: #
! 207: ifcapable wal {
! 208: do_test journal2-2.1 {
! 209: faultsim_delete_and_reopen
! 210: set ::oplog [list]
! 211: execsql { PRAGMA journal_mode = persist }
! 212: set ::oplog
! 213: } {}
! 214: do_test journal2-2.2 {
! 215: execsql {
! 216: CREATE TABLE t1(x);
! 217: INSERT INTO t1 VALUES(3.14159);
! 218: }
! 219: set ::oplog
! 220: } {xOpen test.db-journal}
! 221: do_test journal2-2.3 {
! 222: expr {[file size test.db-journal] > 512}
! 223: } {1}
! 224: do_test journal2-2.4 {
! 225: set ::oplog [list]
! 226: execsql { PRAGMA journal_mode = WAL }
! 227: set ::oplog
! 228: } {xClose test.db-journal xDelete test.db-journal}
! 229: db close
! 230: }
! 231:
! 232: tvfs delete
! 233: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>