1# 2005 December 30 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# The focus of the tests in this file are IO errors that occur in a shared 13# cache context. What happens to connection B if one connection A encounters 14# an IO-error whilst reading or writing the file-system? 15# 16# $Id: shared_err.test,v 1.4 2006/01/23 05:50:58 danielk1977 Exp $ 17 18proc skip {args} {} 19 20 21set testdir [file dirname $argv0] 22source $testdir/tester.tcl 23db close 24 25ifcapable !shared_cache||!subquery { 26 finish_test 27 return 28} 29set ::enable_shared_cache [sqlite3_enable_shared_cache 1] 30 31 32# Todo: This is a copy of the [do_malloc_test] proc in malloc.test 33# It would be better if these were consolidated. 34 35# Usage: do_malloc_test <test number> <options...> 36# 37# The first argument, <test number>, is an integer used to name the 38# tests executed by this proc. Options are as follows: 39# 40# -tclprep TCL script to run to prepare test. 41# -sqlprep SQL script to run to prepare test. 42# -tclbody TCL script to run with malloc failure simulation. 43# -sqlbody TCL script to run with malloc failure simulation. 44# -cleanup TCL script to run after the test. 45# 46# This command runs a series of tests to verify SQLite's ability 47# to handle an out-of-memory condition gracefully. It is assumed 48# that if this condition occurs a malloc() call will return a 49# NULL pointer. Linux, for example, doesn't do that by default. See 50# the "BUGS" section of malloc(3). 51# 52# Each iteration of a loop, the TCL commands in any argument passed 53# to the -tclbody switch, followed by the SQL commands in any argument 54# passed to the -sqlbody switch are executed. Each iteration the 55# Nth call to sqliteMalloc() is made to fail, where N is increased 56# each time the loop runs starting from 1. When all commands execute 57# successfully, the loop ends. 58# 59proc do_malloc_test {tn args} { 60 array unset ::mallocopts 61 array set ::mallocopts $args 62 63 set ::go 1 64 for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { 65 do_test shared_malloc-$tn.$::n { 66 67 # Remove all traces of database files test.db and test2.db from the files 68 # system. Then open (empty database) "test.db" with the handle [db]. 69 # 70 sqlite_malloc_fail 0 71 catch {db close} 72 catch {file delete -force test.db} 73 catch {file delete -force test.db-journal} 74 catch {file delete -force test2.db} 75 catch {file delete -force test2.db-journal} 76 catch {sqlite3 db test.db} 77 set ::DB [sqlite3_connection_pointer db] 78 79 # Execute any -tclprep and -sqlprep scripts. 80 # 81 if {[info exists ::mallocopts(-tclprep)]} { 82 eval $::mallocopts(-tclprep) 83 } 84 if {[info exists ::mallocopts(-sqlprep)]} { 85 execsql $::mallocopts(-sqlprep) 86 } 87 88 # Now set the ${::n}th malloc() to fail and execute the -tclbody and 89 # -sqlbody scripts. 90 # 91 sqlite_malloc_fail $::n 92 set ::mallocbody {} 93 if {[info exists ::mallocopts(-tclbody)]} { 94 append ::mallocbody "$::mallocopts(-tclbody)\n" 95 } 96 if {[info exists ::mallocopts(-sqlbody)]} { 97 append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" 98 } 99 set v [catch $::mallocbody msg] 100 101 set leftover [lindex [sqlite_malloc_stat] 2] 102 if {$leftover>0} { 103 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} 104 set ::go 0 105 if {$v} { 106 puts "\nError message returned: $msg" 107 } else { 108 set v {1 1} 109 } 110 } else { 111 set v2 [expr {$msg=="" || $msg=="out of memory"}] 112 if {!$v2} {puts "\nError message returned: $msg"} 113 lappend v $v2 114 } 115 } {1 1} 116 117 sqlite_malloc_fail 0 118 if {[info exists ::mallocopts(-cleanup)]} { 119 catch [list uplevel #0 $::mallocopts(-cleanup)] msg 120 } 121 } 122 unset ::mallocopts 123} 124 125 126do_ioerr_test shared_ioerr-1 -tclprep { 127 sqlite3 db2 test.db 128 execsql { 129 PRAGMA read_uncommitted = 1; 130 CREATE TABLE t1(a,b,c); 131 BEGIN; 132 SELECT * FROM sqlite_master; 133 } db2 134} -sqlbody { 135 SELECT * FROM sqlite_master; 136 INSERT INTO t1 VALUES(1,2,3); 137 BEGIN TRANSACTION; 138 INSERT INTO t1 VALUES(1,2,3); 139 INSERT INTO t1 VALUES(4,5,6); 140 ROLLBACK; 141 SELECT * FROM t1; 142 BEGIN TRANSACTION; 143 INSERT INTO t1 VALUES(1,2,3); 144 INSERT INTO t1 VALUES(4,5,6); 145 COMMIT; 146 SELECT * FROM t1; 147 DELETE FROM t1 WHERE a<100; 148} -cleanup { 149 do_test shared_ioerr-1.$n.cleanup.1 { 150 set res [catchsql { 151 SELECT * FROM t1; 152 } db2] 153 set possible_results [list \ 154 "1 {disk I/O error}" \ 155 "0 {1 2 3}" \ 156 "0 {1 2 3 1 2 3 4 5 6}" \ 157 "0 {1 2 3 1 2 3 4 5 6 1 2 3 4 5 6}" \ 158 "0 {}" \ 159 ] 160 set rc [expr [lsearch -exact $possible_results $res] >= 0] 161 if {$rc != 1} { 162 puts "" 163 puts "Result: $res" 164 } 165 set rc 166 } {1} 167 db2 close 168} 169 170do_ioerr_test shared_ioerr-2 -tclprep { 171 sqlite3 db2 test.db 172 execsql { 173 PRAGMA read_uncommitted = 1; 174 BEGIN; 175 CREATE TABLE t1(a, b); 176 INSERT INTO t1(oid) VALUES(NULL); 177 INSERT INTO t1(oid) SELECT NULL FROM t1; 178 INSERT INTO t1(oid) SELECT NULL FROM t1; 179 INSERT INTO t1(oid) SELECT NULL FROM t1; 180 INSERT INTO t1(oid) SELECT NULL FROM t1; 181 INSERT INTO t1(oid) SELECT NULL FROM t1; 182 INSERT INTO t1(oid) SELECT NULL FROM t1; 183 INSERT INTO t1(oid) SELECT NULL FROM t1; 184 INSERT INTO t1(oid) SELECT NULL FROM t1; 185 INSERT INTO t1(oid) SELECT NULL FROM t1; 186 INSERT INTO t1(oid) SELECT NULL FROM t1; 187 UPDATE t1 set a = oid, b = 'abcdefghijklmnopqrstuvwxyz0123456789'; 188 CREATE INDEX i1 ON t1(a); 189 COMMIT; 190 BEGIN; 191 SELECT * FROM sqlite_master; 192 } db2 193} -tclbody { 194 set ::residx 0 195 execsql {DELETE FROM t1 WHERE 0 = (a % 2);} 196 incr ::residx 197 198 # When this transaction begins the table contains 512 entries. The 199 # two statements together add 512+146 more if it succeeds. 200 # (1024/7==146) 201 execsql {BEGIN;} 202 execsql {INSERT INTO t1 SELECT a+1, b FROM t1;} 203 execsql {INSERT INTO t1 SELECT 'string' || a, b FROM t1 WHERE 0 = (a%7);} 204 execsql {COMMIT;} 205 206 incr ::residx 207} -cleanup { 208 do_test shared_ioerr-2.$n.cleanup.1 { 209 set res [catchsql { 210 SELECT max(a), min(a), count(*) FROM (SELECT a FROM t1 order by a); 211 } db2] 212 set possible_results [list \ 213 {0 {1024 1 1024}} \ 214 {0 {1023 1 512}} \ 215 {0 {string994 1 1170}} \ 216 ] 217 set idx [lsearch -exact $possible_results $res] 218 set success [expr {$idx==$::residx || $res=="1 {disk I/O error}"}] 219 if {!$success} { 220 puts "" 221 puts "Result: \"$res\" ($::residx)" 222 } 223 set success 224 } {1} 225 db2 close 226} 227 228# This test is designed to provoke an IO error when a cursor position is 229# "saved" (because another cursor is going to modify the underlying table). 230# 231do_ioerr_test shared_ioerr-3 -tclprep { 232 sqlite3 db2 test.db 233 execsql { 234 PRAGMA read_uncommitted = 1; 235 PRAGMA cache_size = 10; 236 BEGIN; 237 CREATE TABLE t1(a, b, UNIQUE(a, b)); 238 } db2 239 for {set i 0} {$i < 200} {incr i} { 240 set a [string range [string repeat "[format %03d $i]." 5] 0 end-1] 241 242 set b [string repeat $i 2000] 243 execsql {INSERT INTO t1 VALUES($a, $b)} db2 244 } 245 execsql {COMMIT} db2 246 set ::DB2 [sqlite3_connection_pointer db2] 247 set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] 248 sqlite3_step $::STMT ;# Cursor points at 000.000.000.000 249 sqlite3_step $::STMT ;# Cursor points at 001.001.001.001 250 251} -tclbody { 252 execsql { 253 INSERT INTO t1 VALUES('201.201.201.201.201', NULL); 254 } 255} -cleanup { 256 do_test shared_ioerr-3.$n.cleanup.1 { 257 sqlite3_step $::STMT 258 } {SQLITE_ROW} 259 do_test shared_ioerr-3.$n.cleanup.2 { 260 sqlite3_column_text $::STMT 0 261 } {002.002.002.002.002} 262 do_test shared_ioerr-3.$n.cleanup.3 { 263 sqlite3_finalize $::STMT 264 } {SQLITE_OK} 265# db2 eval {select * from sqlite_master} 266 db2 close 267} 268 269# Provoke a malloc() failure when a cursor position is being saved. This 270# only happens with index cursors (because they malloc() space to save the 271# current key value). It does not happen with tables, because an integer 272# key does not require a malloc() to store. 273# 274# The library should return an SQLITE_NOMEM to the caller. The query that 275# owns the cursor (the one for which the position is not saved) should 276# continue unaffected. 277# 278do_malloc_test 4 -tclprep { 279 sqlite3 db2 test.db 280 execsql { 281 PRAGMA read_uncommitted = 1; 282 BEGIN; 283 CREATE TABLE t1(a, b, UNIQUE(a, b)); 284 } db2 285 for {set i 0} {$i < 5} {incr i} { 286 set a [string repeat $i 10] 287 set b [string repeat $i 2000] 288 execsql {INSERT INTO t1 VALUES($a, $b)} db2 289 } 290 execsql {COMMIT} db2 291 set ::DB2 [sqlite3_connection_pointer db2] 292 set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] 293 sqlite3_step $::STMT ;# Cursor points at 0000000000 294 sqlite3_step $::STMT ;# Cursor points at 1111111111 295} -tclbody { 296 execsql { 297 INSERT INTO t1 VALUES(6, NULL); 298 } 299} -cleanup { 300 do_test shared_malloc-4.$::n.cleanup.1 { 301 sqlite3_step $::STMT 302 } {SQLITE_ROW} 303 do_test shared_malloc-4.$::n.cleanup.2 { 304 sqlite3_column_text $::STMT 0 305 } {2222222222} 306 do_test shared_malloc-4.$::n.cleanup.3 { 307 sqlite3_finalize $::STMT 308 } {SQLITE_OK} 309# db2 eval {select * from sqlite_master} 310 db2 close 311} 312 313do_malloc_test 5 -tclbody { 314 sqlite3 dbX test.db 315 sqlite3 dbY test.db 316 dbX close 317 dbY close 318} -cleanup { 319 catch {dbX close} 320 catch {dbY close} 321} 322 323catch {db close} 324sqlite3_enable_shared_cache $::enable_shared_cache 325finish_test 326 327