1# 2014 October 22 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 13if {![info exists testdir]} { 14 set testdir [file join [file dirname [info script]] .. .. test] 15} 16source $testdir/tester.tcl 17source $testdir/malloc_common.tcl 18set ::testprefix rbufault 19 20proc copy_if_exists {src target} { 21 if {[file exists $src]} { 22 forcecopy $src $target 23 } else { 24 forcedelete $target 25 } 26} 27 28foreach {tn2 setup sql expect} { 29 1 { 30 CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); 31 CREATE INDEX t1cb ON t1(c, b); 32 INSERT INTO t1 VALUES(1, 1, 1); 33 INSERT INTO t1 VALUES(2, 2, 2); 34 INSERT INTO t1 VALUES(3, 3, 3); 35 36 CREATE TABLE rbu.data_t1(a, b, c, rbu_control); 37 INSERT INTO data_t1 VALUES(2, NULL, NULL, 1); 38 INSERT INTO data_t1 VALUES(3, 'three', NULL, '.x.'); 39 INSERT INTO data_t1 VALUES(4, 4, 4, 0); 40 } { 41 SELECT * FROM t1 42 } {1 1 1 3 three 3 4 4 4} 43 44 2 { 45 CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID; 46 CREATE INDEX t2cb ON t2(c, b); 47 INSERT INTO t2 VALUES('a', 'a', 'a'); 48 INSERT INTO t2 VALUES('b', 'b', 'b'); 49 INSERT INTO t2 VALUES('c', 'c', 'c'); 50 51 CREATE TABLE rbu.data_t2(a, b, c, rbu_control); 52 INSERT INTO data_t2 VALUES('b', NULL, NULL, 1); 53 INSERT INTO data_t2 VALUES('c', 'see', NULL, '.x.'); 54 INSERT INTO data_t2 VALUES('d', 'd', 'd', 0); 55 } { 56 SELECT * FROM t2 57 } {a a a c see c d d d} 58 59 3 { 60 CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); 61 CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID; 62 CREATE INDEX t1cb ON t1(c, b); 63 CREATE INDEX t2cb ON t2(c, b); 64 65 CREATE TABLE rbu.data_t1(a, b, c, rbu_control); 66 CREATE TABLE rbu.data_t2(a, b, c, rbu_control); 67 INSERT INTO data_t1 VALUES(1, 2, 3, 0); 68 INSERT INTO data_t2 VALUES(4, 5, 6, 0); 69 } { 70 SELECT * FROM t1 UNION ALL SELECT * FROM t2 71 } {1 2 3 4 5 6} 72 73 4 { 74 CREATE TABLE t1(a PRIMARY KEY, b, c); 75 CREATE INDEX t1c ON t1(c); 76 INSERT INTO t1 VALUES('A', 'B', 'C'); 77 INSERT INTO t1 VALUES('D', 'E', 'F'); 78 79 CREATE TABLE rbu.data_t1(a, b, c, rbu_control); 80 INSERT INTO data_t1 VALUES('D', NULL, NULL, 1); 81 INSERT INTO data_t1 VALUES('A', 'Z', NULL, '.x.'); 82 INSERT INTO data_t1 VALUES('G', 'H', 'I', 0); 83 } { 84 SELECT * FROM t1 ORDER BY a; 85 } {A Z C G H I} 86 87 5 { 88 CREATE TABLE t1(a, b, c); 89 CREATE INDEX t1c ON t1(c, b); 90 91 CREATE TABLE rbu.data_t1(a, b, c, rbu_rowid, rbu_control); 92 INSERT INTO data_t1 VALUES('a', 'b', 'c', 1, 0); 93 INSERT INTO data_t1 VALUES('d', 'e', 'f', '2', 0); 94 } { 95 SELECT * FROM t1 ORDER BY a; 96 } {a b c d e f} 97 98} { 99 catch {db close} 100 forcedelete rbu.db test.db 101 sqlite3 db test.db 102 execsql { 103 PRAGMA encoding = utf16; 104 ATTACH 'rbu.db' AS rbu; 105 } 106 execsql $setup 107 db close 108 109 forcecopy test.db test.db.bak 110 forcecopy rbu.db rbu.db.bak 111 112 foreach {tn f reslist} { 113 1 oom-tra* { 114 {0 SQLITE_DONE} 115 {1 {SQLITE_NOMEM - out of memory}} 116 {1 SQLITE_NOMEM} 117 {1 SQLITE_IOERR_NOMEM} 118 {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}} 119 } 120 121 2 ioerr-* { 122 {0 SQLITE_DONE} 123 {1 {SQLITE_IOERR - disk I/O error}} 124 {1 SQLITE_IOERR} 125 {1 SQLITE_IOERR_WRITE} 126 {1 SQLITE_IOERR_READ} 127 {1 SQLITE_IOERR_FSYNC} 128 {1 {SQLITE_ERROR - SQL logic error}} 129 {1 {SQLITE_ERROR - unable to open database: rbu.db}} 130 {1 {SQLITE_IOERR - unable to open database: rbu.db}} 131 } 132 133 3 shmerr-* { 134 {0 SQLITE_DONE} 135 {1 {SQLITE_IOERR - disk I/O error}} 136 {1 SQLITE_IOERR} 137 } 138 } { 139 140 catch {db close} 141 sqlite3_shutdown 142 set lookaside_config [sqlite3_config_lookaside 0 0] 143 sqlite3_initialize 144 autoinstall_test_functions 145 146 do_faultsim_test 2.$tn2 -faults $::f -prep { 147 catch { db close } 148 forcedelete test.db-journal test.db-wal rbu.db-journal rbu.db-wal 149 forcecopy test.db.bak test.db 150 forcecopy rbu.db.bak rbu.db 151 } -body { 152 sqlite3rbu rbu test.db rbu.db 153 while {[rbu step]=="SQLITE_OK"} {} 154 rbu close 155 } -test { 156 faultsim_test_result {*}$::reslist 157 if {$testrc==0} { 158 sqlite3 db test.db 159 faultsim_integrity_check 160 set res [db eval $::sql] 161 if {$res != [list {*}$::expect]} { 162 puts "" 163 puts "res: $res" 164 puts "exp: $expect" 165 error "data not as expected!" 166 } 167 } 168 } 169 170 catch {db close} 171 sqlite3_shutdown 172 sqlite3_config_lookaside {*}$lookaside_config 173 sqlite3_initialize 174 autoinstall_test_functions 175 176 177 for {set iStep 0} {$iStep<=21} {incr iStep} { 178 179 forcedelete test.db-journal test.db-wal rbu.db-journal rbu.db-wal 180 181 copy_if_exists test.db.bak test.db 182 copy_if_exists rbu.db.bak rbu.db 183 184 sqlite3rbu rbu test.db rbu.db 185 for {set x 0} {$x < $::iStep} {incr x} { rbu step } 186 rbu close 187 188# sqlite3 x rbu.db ; puts "XYZ [x eval { SELECT * FROM rbu_state } ]" ; x close 189 190 copy_if_exists test.db test.db.bak.2 191 copy_if_exists test.db-wal test.db.bak.2-wal 192 copy_if_exists test.db-oal test.db.bak.2-oal 193 copy_if_exists rbu.db rbu.db.bak.2 194 195 do_faultsim_test 3.$tn.$iStep -faults $::f -prep { 196 catch { db close } 197 forcedelete test.db-journal test.db-wal rbu.db-journal rbu.db-wal 198 copy_if_exists test.db.bak.2 test.db 199 copy_if_exists test.db.bak.2-wal test.db-wal 200 copy_if_exists test.db.bak.2-oal test.db-oal 201 copy_if_exists rbu.db.bak.2 rbu.db 202 } -body { 203 sqlite3rbu rbu test.db rbu.db 204 rbu step 205 rbu close 206 } -test { 207 208 if {$testresult=="SQLITE_OK"} {set testresult "SQLITE_DONE"} 209 faultsim_test_result {*}$::reslist 210 211 if {$testrc==0} { 212 # No error occurred. If the RBU has not already been fully applied, 213 # apply the rest of it now. Then ensure that the final state of the 214 # target db is as expected. And that "PRAGMA integrity_check" 215 # passes. 216 sqlite3rbu rbu test.db rbu.db 217 while {[rbu step] == "SQLITE_OK"} {} 218 rbu close 219 220 sqlite3 db test.db 221 faultsim_integrity_check 222 223 set res [db eval $::sql] 224 if {$res != [list {*}$::expect]} { 225 puts "" 226 puts "res: $res" 227 puts "exp: $::expect" 228 error "data not as expected!" 229 } 230 } 231 } 232 } 233 } 234} 235 236finish_test 237