gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/overlay/snapshot_fault.test (about) 1 # 2015 December 10 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. The focus 12 # of this file is the sqlite3_snapshot_xxx() APIs. 13 # 14 15 set testdir [file dirname $argv0] 16 source $testdir/tester.tcl 17 ifcapable !snapshot {finish_test; return} 18 set testprefix snapshot_fault 19 20 #------------------------------------------------------------------------- 21 # Check that an sqlite3_snapshot_open() client cannot be tricked into 22 # reading a corrupt snapshot even if a second client fails while 23 # checkpointing the db. 24 # 25 26 # This test relies on a forcedelete of an open file 27 # resulting in: error deleting "test.db": permission denied 28 # Not possible to remove the open file 29 if {$::tcl_platform(platform)!="windows"} { 30 31 do_faultsim_test 1.0 -prep { 32 faultsim_delete_and_reopen 33 sqlite3 db2 test.db 34 db2 eval { 35 CREATE TABLE t1(a, b UNIQUE, c UNIQUE); 36 INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500)); 37 INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500)); 38 PRAGMA journal_mode = wal; 39 INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500)); 40 BEGIN; 41 SELECT a FROM t1; 42 } 43 set ::snapshot [sqlite3_snapshot_get db2 main] 44 db2 eval COMMIT 45 db2 eval { 46 UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1; 47 INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500)); 48 INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500)); 49 INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); 50 } 51 } -body { 52 db eval { PRAGMA wal_checkpoint } 53 } -test { 54 db2 eval BEGIN 55 if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} { 56 if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} { 57 error "error is $msg" 58 } 59 } else { 60 set res [db2 eval { 61 SELECT a FROM t1; 62 PRAGMA integrity_check; 63 }] 64 if {$res != "1 2 3 ok"} { error "res is $res" } 65 } 66 67 sqlite3_snapshot_free $::snapshot 68 } 69 } 70 71 #------------------------------------------------------------------------- 72 # This test is similar to the previous one. Except, after the 73 # "PRAGMA wal_checkpoint" command fails the db is closed and reopened 74 # so as to require wal file recovery. It should not be possible to open 75 # a snapshot that is part of the body of a recovered wal file. 76 # 77 do_faultsim_test 2.0 -prep { 78 faultsim_delete_and_reopen 79 db eval { 80 CREATE TABLE t1(a, b UNIQUE, c UNIQUE); 81 INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500)); 82 INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500)); 83 PRAGMA journal_mode = wal; 84 INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500)); 85 BEGIN; 86 SELECT a FROM t1; 87 } 88 set ::snapshot [sqlite3_snapshot_get db main] 89 db eval COMMIT 90 91 db eval { 92 UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1; 93 INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500)); 94 INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500)); 95 INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); 96 } 97 } -body { 98 db eval { PRAGMA wal_checkpoint } 99 } -test { 100 101 db_save 102 db close 103 db_restore_and_reopen 104 db eval { SELECT * FROM t1 } 105 106 db eval BEGIN 107 if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} { 108 if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} { 109 error "error is $msg" 110 } 111 } else { 112 # This branch should actually never be taken. But it was useful in 113 # determining whether or not this test was actually working (by 114 # running a modified version of SQLite that allowed snapshots to be 115 # opened following a recovery). 116 error "TEST HAS FAILED" 117 118 set res [db eval { 119 SELECT a FROM t1; 120 PRAGMA integrity_check; 121 }] 122 if {$res != "1 2 3 ok"} { error "res is $res" } 123 } 124 125 sqlite3_snapshot_free $::snapshot 126 } 127 128 #------------------------------------------------------------------------- 129 # Test the handling of faults that occur within sqlite3_snapshot_open(). 130 # 131 do_faultsim_test 3.0 -prep { 132 faultsim_delete_and_reopen 133 db eval { 134 CREATE TABLE t1(a, b UNIQUE, c UNIQUE); 135 INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500)); 136 INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500)); 137 PRAGMA journal_mode = wal; 138 INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500)); 139 BEGIN; 140 SELECT a FROM t1; 141 } 142 set ::snapshot [sqlite3_snapshot_get db main] 143 db eval COMMIT 144 db eval { 145 UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1; 146 INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500)); 147 INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500)); 148 INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); 149 BEGIN; 150 } 151 } -body { 152 if { [catch { sqlite3_snapshot_open db main $::snapshot } msg] } { 153 error $msg 154 } 155 } -test { 156 faultsim_test_result {0 {}} {1 SQLITE_IOERR} {1 SQLITE_NOMEM} \ 157 {1 SQLITE_IOERR_NOMEM} {1 SQLITE_IOERR_READ} 158 if {$testrc==0} { 159 set res [db eval { 160 SELECT a FROM t1; 161 PRAGMA integrity_check; 162 }] 163 if {$res != "1 2 3 ok"} { error "res is $res" } 164 } 165 166 sqlite3_snapshot_free $::snapshot 167 } 168 169 #------------------------------------------------------------------------- 170 # Test the handling of faults that occur within sqlite3_snapshot_recover(). 171 # 172 reset_db 173 do_execsql_test 4.0 { 174 PRAGMA journal_mode = wal; 175 CREATE TABLE t1(zzz); 176 INSERT INTO t1 VALUES('abc'); 177 INSERT INTO t1 VALUES('def'); 178 } {wal} 179 faultsim_save_and_close 180 181 do_test 4.0.1 { 182 faultsim_restore_and_reopen 183 db eval { SELECT * FROM sqlite_master } 184 sqlite3_snapshot_recover db main 185 } {} 186 db close 187 188 do_faultsim_test 4.0 -faults oom* -prep { 189 faultsim_restore_and_reopen 190 db eval { SELECT * FROM sqlite_master } 191 } -body { 192 sqlite3_snapshot_recover db main 193 } -test { 194 faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM} 195 } 196 197 # The following test cases contrive to call sqlite3_snapshot_recover() 198 # before all pages of the *-shm file have been mapped. This tests an 199 # extra branch of error handling logic in snapshot_recover(). 200 # 201 reset_db 202 do_execsql_test 4.1.0 { 203 PRAGMA page_size = 512; 204 PRAGMA journal_mode = wal; 205 PRAGMA wal_autocheckpoint = 0; 206 CREATE TABLE t1(zzz); 207 INSERT INTO t1 VALUES(randomblob( 500 * 9500 )); 208 PRAGMA user_version = 211; 209 } {wal 0} 210 211 do_test 4.1.1 { 212 list [file size test.db-shm] [file size test.db] 213 } {98304 512} 214 215 faultsim_save_and_close 216 do_faultsim_test 4.1 -faults shm* -prep { 217 catch { db2 close } 218 catch { db close } 219 faultsim_restore_and_reopen 220 sqlite3 db2 test.db 221 db2 eval { SELECT * FROM sqlite_master } 222 db eval BEGIN 223 sqlite3_snapshot_get_blob db main 224 db eval COMMIT 225 } -body { 226 sqlite3_snapshot_recover db main 227 } -test { 228 faultsim_test_result {0 {}} {1 SQLITE_IOERR} 229 } 230 231 #------------------------------------------------------------------------- 232 # Test the handling of faults that occur within sqlite3_snapshot_get(). 233 # 234 reset_db 235 do_execsql_test 5.0 { 236 PRAGMA page_size = 512; 237 PRAGMA journal_mode = wal; 238 PRAGMA wal_autocheckpoint = 0; 239 CREATE TABLE t1(zzz); 240 INSERT INTO t1 VALUES(randomblob( 5000 )); 241 PRAGMA user_version = 211; 242 } {wal 0} 243 faultsim_save_and_close 244 245 do_faultsim_test 5 -prep { 246 faultsim_restore_and_reopen 247 execsql { SELECT count(*) FROM sqlite_master } 248 execsql BEGIN 249 } -body { 250 sqlite3_snapshot_get_blob db main 251 set {} {} 252 } -test { 253 execsql END 254 faultsim_test_result {0 {}} {1 SQLITE_IOERR} {1 SQLITE_NOMEM} 255 } 256 257 258 finish_test