OLD | NEW |
(Empty) | |
| 1 # 2010 June 15 |
| 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 |
| 13 set testdir [file dirname $argv0] |
| 14 source $testdir/tester.tcl |
| 15 source $testdir/lock_common.tcl |
| 16 source $testdir/malloc_common.tcl |
| 17 |
| 18 if {[permutation] == "inmemory_journal"} { |
| 19 finish_test |
| 20 return |
| 21 } |
| 22 |
| 23 set a_string_counter 1 |
| 24 proc a_string {n} { |
| 25 global a_string_counter |
| 26 incr a_string_counter |
| 27 string range [string repeat "${a_string_counter}." $n] 1 $n |
| 28 } |
| 29 db func a_string a_string |
| 30 |
| 31 #------------------------------------------------------------------------- |
| 32 # Test fault-injection while rolling back a hot-journal file. |
| 33 # |
| 34 do_test pagerfault-1-pre1 { |
| 35 execsql { |
| 36 PRAGMA journal_mode = DELETE; |
| 37 PRAGMA cache_size = 10; |
| 38 CREATE TABLE t1(a UNIQUE, b UNIQUE); |
| 39 INSERT INTO t1 VALUES(a_string(200), a_string(300)); |
| 40 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 41 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 42 BEGIN; |
| 43 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; |
| 44 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; |
| 45 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; |
| 46 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; |
| 47 } |
| 48 faultsim_save_and_close |
| 49 } {} |
| 50 do_faultsim_test pagerfault-1 -prep { |
| 51 faultsim_restore_and_reopen |
| 52 } -body { |
| 53 execsql { SELECT count(*) FROM t1 } |
| 54 } -test { |
| 55 faultsim_test_result {0 4} |
| 56 faultsim_integrity_check |
| 57 if {[db one { SELECT count(*) FROM t1 }] != 4} { |
| 58 error "Database content appears incorrect" |
| 59 } |
| 60 } |
| 61 |
| 62 #------------------------------------------------------------------------- |
| 63 # Test fault-injection while rolling back a hot-journal file with a |
| 64 # page-size different from the current value stored on page 1 of the |
| 65 # database file. |
| 66 # |
| 67 do_test pagerfault-2-pre1 { |
| 68 testvfs tv -default 1 |
| 69 tv filter xSync |
| 70 tv script xSyncCb |
| 71 proc xSyncCb {filename args} { |
| 72 if {[string match *journal filename]==0} faultsim_save |
| 73 } |
| 74 faultsim_delete_and_reopen |
| 75 execsql { |
| 76 PRAGMA page_size = 4096; |
| 77 BEGIN; |
| 78 CREATE TABLE abc(a, b, c); |
| 79 INSERT INTO abc VALUES('o', 't', 't'); |
| 80 INSERT INTO abc VALUES('f', 'f', 's'); |
| 81 INSERT INTO abc SELECT * FROM abc; -- 4 |
| 82 INSERT INTO abc SELECT * FROM abc; -- 8 |
| 83 INSERT INTO abc SELECT * FROM abc; -- 16 |
| 84 INSERT INTO abc SELECT * FROM abc; -- 32 |
| 85 INSERT INTO abc SELECT * FROM abc; -- 64 |
| 86 INSERT INTO abc SELECT * FROM abc; -- 128 |
| 87 INSERT INTO abc SELECT * FROM abc; -- 256 |
| 88 COMMIT; |
| 89 PRAGMA page_size = 1024; |
| 90 VACUUM; |
| 91 } |
| 92 db close |
| 93 tv delete |
| 94 } {} |
| 95 do_faultsim_test pagerfault-2 -prep { |
| 96 faultsim_restore_and_reopen |
| 97 } -body { |
| 98 execsql { SELECT * FROM abc } |
| 99 } -test { |
| 100 set answer [split [string repeat "ottffs" 128] ""] |
| 101 faultsim_test_result [list 0 $answer] |
| 102 faultsim_integrity_check |
| 103 set res [db eval { SELECT * FROM abc }] |
| 104 if {$res != $answer} { error "Database content appears incorrect ($res)" } |
| 105 } |
| 106 |
| 107 #------------------------------------------------------------------------- |
| 108 # Test fault-injection while rolling back hot-journals that were created |
| 109 # as part of a multi-file transaction. |
| 110 # |
| 111 do_test pagerfault-3-pre1 { |
| 112 testvfs tstvfs -default 1 |
| 113 tstvfs filter xDelete |
| 114 tstvfs script xDeleteCallback |
| 115 |
| 116 proc xDeleteCallback {method file args} { |
| 117 set file [file tail $file] |
| 118 if { [string match *mj* $file] } { faultsim_save } |
| 119 } |
| 120 |
| 121 faultsim_delete_and_reopen |
| 122 db func a_string a_string |
| 123 |
| 124 execsql { |
| 125 ATTACH 'test.db2' AS aux; |
| 126 PRAGMA journal_mode = DELETE; |
| 127 PRAGMA main.cache_size = 10; |
| 128 PRAGMA aux.cache_size = 10; |
| 129 |
| 130 CREATE TABLE t1(a UNIQUE, b UNIQUE); |
| 131 CREATE TABLE aux.t2(a UNIQUE, b UNIQUE); |
| 132 INSERT INTO t1 VALUES(a_string(200), a_string(300)); |
| 133 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 134 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 135 INSERT INTO t2 SELECT * FROM t1; |
| 136 |
| 137 BEGIN; |
| 138 INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1; |
| 139 INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1; |
| 140 INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1; |
| 141 INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1; |
| 142 REPLACE INTO t2 SELECT * FROM t1; |
| 143 COMMIT; |
| 144 } |
| 145 |
| 146 db close |
| 147 tstvfs delete |
| 148 } {} |
| 149 do_faultsim_test pagerfault-3 -prep { |
| 150 faultsim_restore_and_reopen |
| 151 } -body { |
| 152 execsql { |
| 153 ATTACH 'test.db2' AS aux; |
| 154 SELECT count(*) FROM t2; |
| 155 SELECT count(*) FROM t1; |
| 156 } |
| 157 } -test { |
| 158 faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}} |
| 159 faultsim_integrity_check |
| 160 catchsql { ATTACH 'test.db2' AS aux } |
| 161 if {[db one { SELECT count(*) FROM t1 }] != 4 |
| 162 || [db one { SELECT count(*) FROM t2 }] != 4 |
| 163 } { |
| 164 error "Database content appears incorrect" |
| 165 } |
| 166 } |
| 167 |
| 168 #------------------------------------------------------------------------- |
| 169 # Test fault-injection as part of a vanilla, no-transaction, INSERT |
| 170 # statement. |
| 171 # |
| 172 do_faultsim_test pagerfault-4 -prep { |
| 173 faultsim_delete_and_reopen |
| 174 } -body { |
| 175 execsql { |
| 176 CREATE TABLE x(y); |
| 177 INSERT INTO x VALUES('z'); |
| 178 SELECT * FROM x; |
| 179 } |
| 180 } -test { |
| 181 faultsim_test_result {0 z} |
| 182 faultsim_integrity_check |
| 183 } |
| 184 |
| 185 #------------------------------------------------------------------------- |
| 186 # Test fault-injection as part of a commit when using journal_mode=PERSIST. |
| 187 # Three different cases: |
| 188 # |
| 189 # pagerfault-5.1: With no journal_size_limit configured. |
| 190 # pagerfault-5.2: With a journal_size_limit configured. |
| 191 # pagerfault-5.4: Multi-file transaction. One connection has a |
| 192 # journal_size_limit of 0, the other has no limit. |
| 193 # |
| 194 do_test pagerfault-5-pre1 { |
| 195 faultsim_delete_and_reopen |
| 196 db func a_string a_string |
| 197 execsql { |
| 198 CREATE TABLE t1(a UNIQUE, b UNIQUE); |
| 199 INSERT INTO t1 VALUES(a_string(200), a_string(300)); |
| 200 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 201 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 202 } |
| 203 faultsim_save_and_close |
| 204 } {} |
| 205 do_faultsim_test pagerfault-5.1 -prep { |
| 206 faultsim_restore_and_reopen |
| 207 db func a_string a_string |
| 208 execsql { PRAGMA journal_mode = PERSIST } |
| 209 } -body { |
| 210 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } |
| 211 } -test { |
| 212 faultsim_test_result {0 {}} |
| 213 faultsim_integrity_check |
| 214 } |
| 215 do_faultsim_test pagerfault-5.2 -prep { |
| 216 faultsim_restore_and_reopen |
| 217 db func a_string a_string |
| 218 execsql { |
| 219 PRAGMA journal_mode = PERSIST; |
| 220 PRAGMA journal_size_limit = 2048; |
| 221 } |
| 222 } -body { |
| 223 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } |
| 224 } -test { |
| 225 faultsim_test_result {0 {}} |
| 226 faultsim_integrity_check |
| 227 } |
| 228 do_faultsim_test pagerfault-5.3 -faults oom-transient -prep { |
| 229 faultsim_restore_and_reopen |
| 230 db func a_string a_string |
| 231 file delete -force test2.db test2.db-journal test2.db-wal |
| 232 execsql { |
| 233 PRAGMA journal_mode = PERSIST; |
| 234 ATTACH 'test2.db' AS aux; |
| 235 PRAGMA aux.journal_mode = PERSIST; |
| 236 PRAGMA aux.journal_size_limit = 0; |
| 237 } |
| 238 } -body { |
| 239 execsql { |
| 240 BEGIN; |
| 241 INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; |
| 242 CREATE TABLE aux.t2 AS SELECT * FROM t1; |
| 243 COMMIT; |
| 244 } |
| 245 } -test { |
| 246 faultsim_test_result {0 {}} |
| 247 |
| 248 catchsql { COMMIT } |
| 249 catchsql { ROLLBACK } |
| 250 |
| 251 faultsim_integrity_check |
| 252 set res "" |
| 253 set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }] |
| 254 if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"} |
| 255 } |
| 256 |
| 257 #------------------------------------------------------------------------- |
| 258 # Test fault-injection as part of a commit when using |
| 259 # journal_mode=TRUNCATE. |
| 260 # |
| 261 do_test pagerfault-6-pre1 { |
| 262 faultsim_delete_and_reopen |
| 263 db func a_string a_string |
| 264 execsql { |
| 265 CREATE TABLE t1(a UNIQUE, b UNIQUE); |
| 266 INSERT INTO t1 VALUES(a_string(200), a_string(300)); |
| 267 } |
| 268 faultsim_save_and_close |
| 269 } {} |
| 270 |
| 271 do_faultsim_test pagerfault-6.1 -prep { |
| 272 faultsim_restore_and_reopen |
| 273 db func a_string a_string |
| 274 execsql { PRAGMA journal_mode = TRUNCATE } |
| 275 } -body { |
| 276 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } |
| 277 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } |
| 278 } -test { |
| 279 faultsim_test_result {0 {}} |
| 280 faultsim_integrity_check |
| 281 } |
| 282 |
| 283 # The unix vfs xAccess() method considers a file zero bytes in size to |
| 284 # "not exist". This proc overrides that behaviour so that a zero length |
| 285 # file is considered to exist. |
| 286 # |
| 287 proc xAccess {method filename op args} { |
| 288 if {$op != "SQLITE_ACCESS_EXISTS"} { return "" } |
| 289 return [file exists $filename] |
| 290 } |
| 291 do_faultsim_test pagerfault-6.2 -faults cantopen-* -prep { |
| 292 shmfault filter xAccess |
| 293 shmfault script xAccess |
| 294 |
| 295 faultsim_restore_and_reopen |
| 296 db func a_string a_string |
| 297 execsql { PRAGMA journal_mode = TRUNCATE } |
| 298 } -body { |
| 299 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } |
| 300 execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } |
| 301 } -test { |
| 302 faultsim_test_result {0 {}} |
| 303 faultsim_integrity_check |
| 304 } |
| 305 |
| 306 # The following was an attempt to get a bitvec malloc to fail. Didn't work. |
| 307 # |
| 308 # do_test pagerfault-6-pre1 { |
| 309 # faultsim_delete_and_reopen |
| 310 # execsql { |
| 311 # CREATE TABLE t1(x, y, UNIQUE(x, y)); |
| 312 # INSERT INTO t1 VALUES(1, randomblob(1501)); |
| 313 # INSERT INTO t1 VALUES(2, randomblob(1502)); |
| 314 # INSERT INTO t1 VALUES(3, randomblob(1503)); |
| 315 # INSERT INTO t1 VALUES(4, randomblob(1504)); |
| 316 # INSERT INTO t1 |
| 317 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; |
| 318 # INSERT INTO t1 |
| 319 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; |
| 320 # INSERT INTO t1 |
| 321 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; |
| 322 # INSERT INTO t1 |
| 323 # SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; |
| 324 # } |
| 325 # faultsim_save_and_close |
| 326 # } {} |
| 327 # do_faultsim_test pagerfault-6 -prep { |
| 328 # faultsim_restore_and_reopen |
| 329 # } -body { |
| 330 # execsql { |
| 331 # BEGIN; |
| 332 # UPDATE t1 SET x=x+4 WHERE x=1; |
| 333 # SAVEPOINT one; |
| 334 # UPDATE t1 SET x=x+4 WHERE x=2; |
| 335 # SAVEPOINT three; |
| 336 # UPDATE t1 SET x=x+4 WHERE x=3; |
| 337 # SAVEPOINT four; |
| 338 # UPDATE t1 SET x=x+4 WHERE x=4; |
| 339 # RELEASE three; |
| 340 # COMMIT; |
| 341 # SELECT DISTINCT x FROM t1; |
| 342 # } |
| 343 # } -test { |
| 344 # faultsim_test_result {0 {5 6 7 8}} |
| 345 # faultsim_integrity_check |
| 346 # } |
| 347 # |
| 348 |
| 349 # This is designed to provoke a special case in the pager code: |
| 350 # |
| 351 # If an error (specifically, a FULL or IOERR error) occurs while writing a |
| 352 # dirty page to the file-system in order to free up memory, the pager enters |
| 353 # the "error state". An IO error causes SQLite to roll back the current |
| 354 # transaction (exiting the error state). A FULL error, however, may only |
| 355 # rollback the current statement. |
| 356 # |
| 357 # This block tests that nothing goes wrong if a FULL error occurs while |
| 358 # writing a dirty page out to free memory from within a statement that has |
| 359 # opened a statement transaction. |
| 360 # |
| 361 do_test pagerfault-7-pre1 { |
| 362 faultsim_delete_and_reopen |
| 363 execsql { |
| 364 CREATE TABLE t2(a INTEGER PRIMARY KEY, b); |
| 365 BEGIN; |
| 366 INSERT INTO t2 VALUES(NULL, randomblob(1500)); |
| 367 INSERT INTO t2 VALUES(NULL, randomblob(1500)); |
| 368 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 4 |
| 369 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 8 |
| 370 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 16 |
| 371 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 32 |
| 372 INSERT INTO t2 SELECT NULL, randomblob(1500) FROM t2; -- 64 |
| 373 COMMIT; |
| 374 CREATE TABLE t1(a PRIMARY KEY, b); |
| 375 INSERT INTO t1 SELECT * FROM t2; |
| 376 DROP TABLE t2; |
| 377 } |
| 378 faultsim_save_and_close |
| 379 } {} |
| 380 do_faultsim_test pagerfault-7 -prep { |
| 381 faultsim_restore_and_reopen |
| 382 execsql { |
| 383 PRAGMA cache_size = 10; |
| 384 BEGIN; |
| 385 UPDATE t1 SET b = randomblob(1500); |
| 386 } |
| 387 } -body { |
| 388 execsql { UPDATE t1 SET a = 65, b = randomblob(1500) WHERE (a+1)>200 } |
| 389 execsql COMMIT |
| 390 } -test { |
| 391 faultsim_test_result {0 {}} |
| 392 faultsim_integrity_check |
| 393 } |
| 394 |
| 395 do_test pagerfault-8-pre1 { |
| 396 faultsim_delete_and_reopen |
| 397 execsql { |
| 398 PRAGMA auto_vacuum = 1; |
| 399 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); |
| 400 BEGIN; |
| 401 INSERT INTO t1 VALUES(NULL, randomblob(1500)); |
| 402 INSERT INTO t1 VALUES(NULL, randomblob(1500)); |
| 403 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 4 |
| 404 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 8 |
| 405 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 16 |
| 406 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 32 |
| 407 INSERT INTO t1 SELECT NULL, randomblob(1500) FROM t1; -- 64 |
| 408 COMMIT; |
| 409 } |
| 410 faultsim_save_and_close |
| 411 set filesize [file size test.db] |
| 412 set {} {} |
| 413 } {} |
| 414 do_test pagerfault-8-pre2 { |
| 415 faultsim_restore_and_reopen |
| 416 execsql { DELETE FROM t1 WHERE a>32 } |
| 417 expr {[file size test.db] < $filesize} |
| 418 } {1} |
| 419 do_faultsim_test pagerfault-8 -prep { |
| 420 faultsim_restore_and_reopen |
| 421 execsql { |
| 422 BEGIN; |
| 423 DELETE FROM t1 WHERE a>32; |
| 424 } |
| 425 } -body { |
| 426 execsql COMMIT |
| 427 } -test { |
| 428 faultsim_test_result {0 {}} |
| 429 faultsim_integrity_check |
| 430 } |
| 431 |
| 432 #------------------------------------------------------------------------- |
| 433 # This test case is specially designed so that during a savepoint |
| 434 # rollback, a new cache entry must be allocated (see comments surrounding |
| 435 # the call to sqlite3PagerAcquire() from within pager_playback_one_page() |
| 436 # for details). Test the effects of injecting an OOM at this point. |
| 437 # |
| 438 do_test pagerfault-9-pre1 { |
| 439 faultsim_delete_and_reopen |
| 440 execsql { |
| 441 PRAGMA auto_vacuum = incremental; |
| 442 CREATE TABLE t1(x); |
| 443 CREATE TABLE t2(y); |
| 444 CREATE TABLE t3(z); |
| 445 |
| 446 INSERT INTO t1 VALUES(randomblob(900)); |
| 447 INSERT INTO t1 VALUES(randomblob(900)); |
| 448 DELETE FROM t1; |
| 449 } |
| 450 faultsim_save_and_close |
| 451 } {} |
| 452 do_faultsim_test pagerfault-9.1 -prep { |
| 453 faultsim_restore_and_reopen |
| 454 execsql { |
| 455 BEGIN; |
| 456 INSERT INTO t1 VALUES(randomblob(900)); |
| 457 INSERT INTO t1 VALUES(randomblob(900)); |
| 458 DROP TABLE t3; |
| 459 DROP TABLE t2; |
| 460 SAVEPOINT abc; |
| 461 PRAGMA incremental_vacuum; |
| 462 } |
| 463 } -body { |
| 464 execsql { |
| 465 ROLLBACK TO abc; |
| 466 COMMIT; |
| 467 PRAGMA freelist_count |
| 468 } |
| 469 } -test { |
| 470 faultsim_test_result {0 2} |
| 471 faultsim_integrity_check |
| 472 |
| 473 set sl [db one { SELECT COALESCE(sum(length(x)), 'null') FROM t1 }] |
| 474 if {$sl!="null" && $sl!=1800} { |
| 475 error "Content looks no good... ($sl)" |
| 476 } |
| 477 } |
| 478 |
| 479 #------------------------------------------------------------------------- |
| 480 # Test fault injection with a temporary database file. |
| 481 # |
| 482 foreach v {a b} { |
| 483 do_faultsim_test pagerfault-10$v -prep { |
| 484 sqlite3 db "" |
| 485 db func a_string a_string; |
| 486 execsql { |
| 487 PRAGMA cache_size = 10; |
| 488 BEGIN; |
| 489 CREATE TABLE xx(a, b, UNIQUE(a, b)); |
| 490 INSERT INTO xx VALUES(a_string(200), a_string(200)); |
| 491 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; |
| 492 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; |
| 493 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; |
| 494 INSERT INTO xx SELECT a_string(200), a_string(200) FROM xx; |
| 495 COMMIT; |
| 496 } |
| 497 } -body { |
| 498 execsql { UPDATE xx SET a = a_string(300) } |
| 499 } -test { |
| 500 faultsim_test_result {0 {}} |
| 501 if {$::v == "b"} { execsql { PRAGMA journal_mode = TRUNCATE } } |
| 502 faultsim_integrity_check |
| 503 faultsim_integrity_check |
| 504 } |
| 505 } |
| 506 |
| 507 #------------------------------------------------------------------------- |
| 508 # Test fault injection with transaction savepoints (savepoints created |
| 509 # when a SAVEPOINT command is executed outside of any other savepoint |
| 510 # or transaction context). |
| 511 # |
| 512 do_test pagerfault-9-pre1 { |
| 513 faultsim_delete_and_reopen |
| 514 db func a_string a_string; |
| 515 execsql { |
| 516 PRAGMA auto_vacuum = on; |
| 517 CREATE TABLE t1(x UNIQUE); |
| 518 CREATE TABLE t2(y UNIQUE); |
| 519 CREATE TABLE t3(z UNIQUE); |
| 520 BEGIN; |
| 521 INSERT INTO t1 VALUES(a_string(202)); |
| 522 INSERT INTO t2 VALUES(a_string(203)); |
| 523 INSERT INTO t3 VALUES(a_string(204)); |
| 524 INSERT INTO t1 SELECT a_string(202) FROM t1; |
| 525 INSERT INTO t1 SELECT a_string(203) FROM t1; |
| 526 INSERT INTO t1 SELECT a_string(204) FROM t1; |
| 527 INSERT INTO t1 SELECT a_string(205) FROM t1; |
| 528 INSERT INTO t2 SELECT a_string(length(x)) FROM t1; |
| 529 INSERT INTO t3 SELECT a_string(length(x)) FROM t1; |
| 530 COMMIT; |
| 531 } |
| 532 faultsim_save_and_close |
| 533 } {} |
| 534 do_faultsim_test pagerfault-11 -prep { |
| 535 faultsim_restore_and_reopen |
| 536 execsql { PRAGMA cache_size = 10 } |
| 537 } -body { |
| 538 execsql { |
| 539 SAVEPOINT trans; |
| 540 UPDATE t2 SET y = y||'2'; |
| 541 INSERT INTO t3 SELECT * FROM t2; |
| 542 DELETE FROM t1; |
| 543 ROLLBACK TO trans; |
| 544 UPDATE t1 SET x = x||'3'; |
| 545 INSERT INTO t2 SELECT * FROM t1; |
| 546 DELETE FROM t3; |
| 547 RELEASE trans; |
| 548 } |
| 549 } -test { |
| 550 faultsim_test_result {0 {}} |
| 551 faultsim_integrity_check |
| 552 } |
| 553 |
| 554 |
| 555 #------------------------------------------------------------------------- |
| 556 # Test fault injection when writing to a database file that resides on |
| 557 # a file-system with a sector-size larger than the database page-size. |
| 558 # |
| 559 do_test pagerfault-12-pre1 { |
| 560 testvfs ss_layer -default 1 |
| 561 ss_layer sectorsize 4096 |
| 562 faultsim_delete_and_reopen |
| 563 db func a_string a_string; |
| 564 |
| 565 execsql { |
| 566 PRAGMA page_size = 1024; |
| 567 PRAGMA journal_mode = PERSIST; |
| 568 PRAGMA cache_size = 10; |
| 569 BEGIN; |
| 570 CREATE TABLE t1(x, y UNIQUE); |
| 571 INSERT INTO t1 VALUES(a_string(333), a_string(444)); |
| 572 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; |
| 573 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; |
| 574 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; |
| 575 INSERT INTO t1 SELECT a_string(333+rowid), a_string(444+rowid) FROM t1; |
| 576 INSERT INTO t1 SELECT a_string(44), a_string(55) FROM t1 LIMIT 13; |
| 577 COMMIT; |
| 578 } |
| 579 faultsim_save_and_close |
| 580 } {} |
| 581 |
| 582 do_faultsim_test pagerfault-12a -prep { |
| 583 faultsim_restore_and_reopen |
| 584 execsql { PRAGMA cache_size = 10 } |
| 585 db func a_string a_string; |
| 586 } -body { |
| 587 execsql { |
| 588 UPDATE t1 SET x = a_string(length(x)), y = a_string(length(y)); |
| 589 } |
| 590 } -test { |
| 591 faultsim_test_result {0 {}} |
| 592 faultsim_integrity_check |
| 593 } |
| 594 |
| 595 do_test pagerfault-12-pre2 { |
| 596 faultsim_restore_and_reopen |
| 597 execsql { |
| 598 CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 10; |
| 599 } |
| 600 faultsim_save_and_close |
| 601 } {} |
| 602 do_faultsim_test pagerfault-12b -prep { |
| 603 faultsim_restore_and_reopen |
| 604 db func a_string a_string; |
| 605 execsql { SELECT * FROM t1 } |
| 606 } -body { |
| 607 set sql(1) { UPDATE t2 SET x = a_string(280) } |
| 608 set sql(2) { UPDATE t1 SET x = a_string(280) WHERE rowid = 5 } |
| 609 |
| 610 db eval { SELECT rowid FROM t1 LIMIT 2 } { db eval $sql($rowid) } |
| 611 |
| 612 } -test { |
| 613 faultsim_test_result {0 {}} |
| 614 faultsim_integrity_check |
| 615 } |
| 616 |
| 617 catch { db close } |
| 618 ss_layer delete |
| 619 |
| 620 |
| 621 #------------------------------------------------------------------------- |
| 622 # Test fault injection when SQLite opens a database where the size of the |
| 623 # database file is zero bytes but the accompanying journal file is larger |
| 624 # than that. In this scenario SQLite should delete the journal file |
| 625 # without rolling it back, even if it is in all other respects a valid |
| 626 # hot-journal file. |
| 627 # |
| 628 do_test pagerfault-13-pre1 { |
| 629 faultsim_delete_and_reopen |
| 630 db func a_string a_string; |
| 631 execsql { |
| 632 PRAGMA journal_mode = PERSIST; |
| 633 BEGIN; |
| 634 CREATE TABLE t1(x, y UNIQUE); |
| 635 INSERT INTO t1 VALUES(a_string(333), a_string(444)); |
| 636 COMMIT; |
| 637 } |
| 638 db close |
| 639 file delete -force test.db |
| 640 faultsim_save |
| 641 } {} |
| 642 do_faultsim_test pagerfault-13 -prep { |
| 643 faultsim_restore_and_reopen |
| 644 } -body { |
| 645 execsql { CREATE TABLE xx(a, b) } |
| 646 } -test { |
| 647 faultsim_test_result {0 {}} |
| 648 } |
| 649 |
| 650 #--------------------------------------------------------------------------- |
| 651 # Test fault injection into a small backup operation. |
| 652 # |
| 653 do_test pagerfault-14-pre1 { |
| 654 faultsim_delete_and_reopen |
| 655 db func a_string a_string; |
| 656 execsql { |
| 657 PRAGMA journal_mode = PERSIST; |
| 658 ATTACH 'test.db2' AS two; |
| 659 BEGIN; |
| 660 CREATE TABLE t1(x, y UNIQUE); |
| 661 CREATE TABLE two.t2(x, y UNIQUE); |
| 662 INSERT INTO t1 VALUES(a_string(333), a_string(444)); |
| 663 INSERT INTO t2 VALUES(a_string(333), a_string(444)); |
| 664 COMMIT; |
| 665 } |
| 666 faultsim_save_and_close |
| 667 } {} |
| 668 |
| 669 do_faultsim_test pagerfault-14a -prep { |
| 670 faultsim_restore_and_reopen |
| 671 } -body { |
| 672 if {[catch {db backup test.db2} msg]} { error [regsub {.*: } $msg {}] } |
| 673 } -test { |
| 674 faultsim_test_result {0 {}} {1 {}} {1 {SQL logic error or missing database}} |
| 675 } |
| 676 |
| 677 # If TEMP_STORE is 2 or greater, then the database [db2] will be created |
| 678 # as an in-memory database. This test will not work in that case, as it |
| 679 # is not possible to change the page-size of an in-memory database. Even |
| 680 # using the backup API. |
| 681 # |
| 682 if {$TEMP_STORE<2} { |
| 683 do_faultsim_test pagerfault-14b -prep { |
| 684 catch { db2 close } |
| 685 faultsim_restore_and_reopen |
| 686 sqlite3 db2 "" |
| 687 db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) } |
| 688 } -body { |
| 689 sqlite3_backup B db2 main db main |
| 690 B step 200 |
| 691 set rc [B finish] |
| 692 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} |
| 693 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } |
| 694 set {} {} |
| 695 } -test { |
| 696 faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}} |
| 697 } |
| 698 } |
| 699 |
| 700 do_faultsim_test pagerfault-14c -prep { |
| 701 catch { db2 close } |
| 702 faultsim_restore_and_reopen |
| 703 sqlite3 db2 test.db2 |
| 704 db2 eval { |
| 705 PRAGMA synchronous = off; |
| 706 PRAGMA page_size = 4096; |
| 707 CREATE TABLE xx(a); |
| 708 } |
| 709 } -body { |
| 710 sqlite3_backup B db2 main db main |
| 711 B step 200 |
| 712 set rc [B finish] |
| 713 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} |
| 714 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } |
| 715 set {} {} |
| 716 } -test { |
| 717 faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}} |
| 718 } |
| 719 |
| 720 do_test pagerfault-15-pre1 { |
| 721 faultsim_delete_and_reopen |
| 722 db func a_string a_string; |
| 723 execsql { |
| 724 BEGIN; |
| 725 CREATE TABLE t1(x, y UNIQUE); |
| 726 INSERT INTO t1 VALUES(a_string(11), a_string(22)); |
| 727 INSERT INTO t1 VALUES(a_string(11), a_string(22)); |
| 728 COMMIT; |
| 729 } |
| 730 faultsim_save_and_close |
| 731 } {} |
| 732 do_faultsim_test pagerfault-15 -prep { |
| 733 faultsim_restore_and_reopen |
| 734 db func a_string a_string; |
| 735 } -body { |
| 736 db eval { SELECT * FROM t1 LIMIT 1 } { |
| 737 execsql { |
| 738 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; |
| 739 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; |
| 740 } |
| 741 } |
| 742 } -test { |
| 743 faultsim_test_result {0 {}} |
| 744 faultsim_integrity_check |
| 745 } |
| 746 |
| 747 |
| 748 do_test pagerfault-16-pre1 { |
| 749 faultsim_delete_and_reopen |
| 750 execsql { CREATE TABLE t1(x, y UNIQUE) } |
| 751 faultsim_save_and_close |
| 752 } {} |
| 753 do_faultsim_test pagerfault-16 -prep { |
| 754 faultsim_restore_and_reopen |
| 755 } -body { |
| 756 execsql { |
| 757 PRAGMA locking_mode = exclusive; |
| 758 PRAGMA journal_mode = wal; |
| 759 INSERT INTO t1 VALUES(1, 2); |
| 760 INSERT INTO t1 VALUES(3, 4); |
| 761 PRAGMA journal_mode = delete; |
| 762 INSERT INTO t1 VALUES(4, 5); |
| 763 PRAGMA journal_mode = wal; |
| 764 INSERT INTO t1 VALUES(6, 7); |
| 765 PRAGMA journal_mode = persist; |
| 766 INSERT INTO t1 VALUES(8, 9); |
| 767 } |
| 768 } -test { |
| 769 faultsim_test_result {0 {exclusive wal delete wal persist}} |
| 770 faultsim_integrity_check |
| 771 } |
| 772 |
| 773 |
| 774 #------------------------------------------------------------------------- |
| 775 # Test fault injection while changing into and out of WAL mode. |
| 776 # |
| 777 do_test pagerfault-17-pre1 { |
| 778 faultsim_delete_and_reopen |
| 779 execsql { |
| 780 CREATE TABLE t1(a PRIMARY KEY, b); |
| 781 INSERT INTO t1 VALUES(1862, 'Botha'); |
| 782 INSERT INTO t1 VALUES(1870, 'Smuts'); |
| 783 INSERT INTO t1 VALUES(1866, 'Hertzog'); |
| 784 } |
| 785 faultsim_save_and_close |
| 786 } {} |
| 787 do_faultsim_test pagerfault-17a -prep { |
| 788 faultsim_restore_and_reopen |
| 789 } -body { |
| 790 execsql { |
| 791 PRAGMA journal_mode = wal; |
| 792 PRAGMA journal_mode = delete; |
| 793 } |
| 794 } -test { |
| 795 faultsim_test_result {0 {wal delete}} |
| 796 faultsim_integrity_check |
| 797 } |
| 798 do_faultsim_test pagerfault-17b -prep { |
| 799 faultsim_restore_and_reopen |
| 800 execsql { PRAGMA synchronous = OFF } |
| 801 } -body { |
| 802 execsql { |
| 803 PRAGMA journal_mode = wal; |
| 804 INSERT INTO t1 VALUES(22, 'Clarke'); |
| 805 PRAGMA journal_mode = delete; |
| 806 } |
| 807 } -test { |
| 808 faultsim_test_result {0 {wal delete}} |
| 809 faultsim_integrity_check |
| 810 } |
| 811 do_faultsim_test pagerfault-17c -prep { |
| 812 faultsim_restore_and_reopen |
| 813 execsql { |
| 814 PRAGMA locking_mode = exclusive; |
| 815 PRAGMA journal_mode = wal; |
| 816 } |
| 817 } -body { |
| 818 execsql { PRAGMA journal_mode = delete } |
| 819 } -test { |
| 820 faultsim_test_result {0 delete} |
| 821 faultsim_integrity_check |
| 822 } |
| 823 do_faultsim_test pagerfault-17d -prep { |
| 824 catch { db2 close } |
| 825 faultsim_restore_and_reopen |
| 826 sqlite3 db2 test.db |
| 827 execsql { PRAGMA journal_mode = delete } |
| 828 execsql { PRAGMA journal_mode = wal } |
| 829 execsql { INSERT INTO t1 VALUES(99, 'Bradman') } db2 |
| 830 } -body { |
| 831 execsql { PRAGMA journal_mode = delete } |
| 832 } -test { |
| 833 faultsim_test_result {1 {database is locked}} |
| 834 faultsim_integrity_check |
| 835 } |
| 836 do_faultsim_test pagerfault-17e -prep { |
| 837 catch { db2 close } |
| 838 faultsim_restore_and_reopen |
| 839 sqlite3 db2 test.db |
| 840 execsql { PRAGMA journal_mode = delete } |
| 841 execsql { PRAGMA journal_mode = wal } |
| 842 set ::chan [launch_testfixture] |
| 843 testfixture $::chan { |
| 844 sqlite3 db test.db |
| 845 db eval { INSERT INTO t1 VALUES(101, 'Latham') } |
| 846 } |
| 847 catch { testfixture $::chan sqlite_abort } |
| 848 catch { close $::chan } |
| 849 } -body { |
| 850 execsql { PRAGMA journal_mode = delete } |
| 851 } -test { |
| 852 faultsim_test_result {0 delete} |
| 853 faultsim_integrity_check |
| 854 } |
| 855 |
| 856 #------------------------------------------------------------------------- |
| 857 # Test fault-injection when changing from journal_mode=persist to |
| 858 # journal_mode=delete (this involves deleting the journal file). |
| 859 # |
| 860 do_test pagerfault-18-pre1 { |
| 861 faultsim_delete_and_reopen |
| 862 execsql { |
| 863 CREATE TABLE qq(x); |
| 864 INSERT INTO qq VALUES('Herbert'); |
| 865 INSERT INTO qq VALUES('Macalister'); |
| 866 INSERT INTO qq VALUES('Mackenzie'); |
| 867 INSERT INTO qq VALUES('Lilley'); |
| 868 INSERT INTO qq VALUES('Palmer'); |
| 869 } |
| 870 faultsim_save_and_close |
| 871 } {} |
| 872 do_faultsim_test pagerfault-18 -prep { |
| 873 faultsim_restore_and_reopen |
| 874 execsql { |
| 875 PRAGMA journal_mode = PERSIST; |
| 876 INSERT INTO qq VALUES('Beatty'); |
| 877 } |
| 878 } -body { |
| 879 execsql { PRAGMA journal_mode = delete } |
| 880 } -test { |
| 881 faultsim_test_result {0 delete} |
| 882 faultsim_integrity_check |
| 883 } |
| 884 |
| 885 do_faultsim_test pagerfault-19a -prep { |
| 886 sqlite3 db :memory: |
| 887 db func a_string a_string |
| 888 execsql { |
| 889 PRAGMA auto_vacuum = FULL; |
| 890 BEGIN; |
| 891 CREATE TABLE t1(a, b); |
| 892 INSERT INTO t1 VALUES(a_string(5000), a_string(6000)); |
| 893 COMMIT; |
| 894 } |
| 895 } -body { |
| 896 execsql { |
| 897 CREATE TABLE t2(a, b); |
| 898 INSERT INTO t2 SELECT * FROM t1; |
| 899 DELETE FROM t1; |
| 900 } |
| 901 } -test { |
| 902 faultsim_test_result {0 {}} |
| 903 } |
| 904 |
| 905 do_test pagerfault-19-pre1 { |
| 906 faultsim_delete_and_reopen |
| 907 execsql { |
| 908 PRAGMA auto_vacuum = FULL; |
| 909 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); |
| 910 CREATE TABLE t2(x); INSERT INTO t2 VALUES(2); |
| 911 CREATE TABLE t3(x); INSERT INTO t3 VALUES(3); |
| 912 CREATE TABLE t4(x); INSERT INTO t4 VALUES(4); |
| 913 CREATE TABLE t5(x); INSERT INTO t5 VALUES(5); |
| 914 CREATE TABLE t6(x); INSERT INTO t6 VALUES(6); |
| 915 } |
| 916 faultsim_save_and_close |
| 917 } {} |
| 918 do_faultsim_test pagerfault-19b -prep { |
| 919 faultsim_restore_and_reopen |
| 920 } -body { |
| 921 execsql { |
| 922 BEGIN; |
| 923 UPDATE t4 SET x = x+1; |
| 924 UPDATE t6 SET x = x+1; |
| 925 SAVEPOINT one; |
| 926 UPDATE t3 SET x = x+1; |
| 927 SAVEPOINT two; |
| 928 DROP TABLE t2; |
| 929 ROLLBACK TO one; |
| 930 COMMIT; |
| 931 SELECT * FROM t3; |
| 932 SELECT * FROM t4; |
| 933 SELECT * FROM t6; |
| 934 } |
| 935 } -test { |
| 936 faultsim_test_result {0 {3 5 7}} |
| 937 } |
| 938 |
| 939 #------------------------------------------------------------------------- |
| 940 # This tests fault-injection in a special case in the auto-vacuum code. |
| 941 # |
| 942 do_test pagerfault-20-pre1 { |
| 943 faultsim_delete_and_reopen |
| 944 execsql { |
| 945 PRAGMA cache_size = 10; |
| 946 PRAGMA auto_vacuum = FULL; |
| 947 CREATE TABLE t0(a, b); |
| 948 } |
| 949 faultsim_save_and_close |
| 950 } {} |
| 951 do_faultsim_test pagerfault-20 -prep { |
| 952 faultsim_restore_and_reopen |
| 953 } -body { |
| 954 execsql { |
| 955 BEGIN; |
| 956 CREATE TABLE t1(a, b); |
| 957 CREATE TABLE t2(a, b); |
| 958 DROP TABLE t1; |
| 959 COMMIT; |
| 960 } |
| 961 } -test { |
| 962 faultsim_test_result {0 {}} |
| 963 } |
| 964 |
| 965 do_test pagerfault-21-pre1 { |
| 966 faultsim_delete_and_reopen |
| 967 execsql { |
| 968 PRAGMA cache_size = 10; |
| 969 CREATE TABLE t0(a PRIMARY KEY, b); |
| 970 INSERT INTO t0 VALUES(1, 2); |
| 971 } |
| 972 faultsim_save_and_close |
| 973 } {} |
| 974 do_faultsim_test pagerfault-21 -prep { |
| 975 faultsim_restore_and_reopen |
| 976 } -body { |
| 977 db eval { SELECT * FROM t0 LIMIT 1 } { |
| 978 db eval { INSERT INTO t0 SELECT a+1, b FROM t0 } |
| 979 db eval { INSERT INTO t0 SELECT a+2, b FROM t0 } |
| 980 } |
| 981 } -test { |
| 982 faultsim_test_result {0 {}} |
| 983 } |
| 984 |
| 985 |
| 986 #------------------------------------------------------------------------- |
| 987 # Test fault-injection and rollback when the nReserve header value |
| 988 # is non-zero. |
| 989 # |
| 990 do_test pagerfault-21-pre1 { |
| 991 faultsim_delete_and_reopen |
| 992 execsql { |
| 993 PRAGMA page_size = 1024; |
| 994 PRAGMA journal_mode = WAL; |
| 995 PRAGMA journal_mode = DELETE; |
| 996 } |
| 997 db close |
| 998 hexio_write test.db 20 10 |
| 999 hexio_write test.db 105 03F0 |
| 1000 sqlite3 db test.db |
| 1001 db func a_string a_string |
| 1002 execsql { |
| 1003 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); |
| 1004 INSERT INTO t0 VALUES(a_string(222), a_string(333)); |
| 1005 INSERT INTO t0 VALUES(a_string(223), a_string(334)); |
| 1006 INSERT INTO t0 VALUES(a_string(224), a_string(335)); |
| 1007 INSERT INTO t0 VALUES(a_string(225), a_string(336)); |
| 1008 } |
| 1009 faultsim_save_and_close |
| 1010 } {} |
| 1011 |
| 1012 do_faultsim_test pagerfault-21 -prep { |
| 1013 faultsim_restore_and_reopen |
| 1014 } -body { |
| 1015 execsql { INSERT INTO t0 SELECT a||'x', b||'x' FROM t0 } |
| 1016 } -test { |
| 1017 faultsim_test_result {0 {}} |
| 1018 faultsim_integrity_check |
| 1019 } |
| 1020 ifcapable crashtest { |
| 1021 faultsim_delete_and_reopen |
| 1022 execsql { |
| 1023 PRAGMA page_size = 1024; |
| 1024 PRAGMA journal_mode = WAL; |
| 1025 PRAGMA journal_mode = DELETE; |
| 1026 } |
| 1027 db close |
| 1028 hexio_write test.db 20 10 |
| 1029 hexio_write test.db 105 03F0 |
| 1030 |
| 1031 sqlite3 db test.db |
| 1032 db func a_string a_string |
| 1033 execsql { |
| 1034 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); |
| 1035 INSERT INTO t0 VALUES(a_string(222), a_string(333)); |
| 1036 INSERT INTO t0 VALUES(a_string(223), a_string(334)); |
| 1037 } |
| 1038 faultsim_save_and_close |
| 1039 |
| 1040 for {set iTest 1} {$iTest<50} {incr iTest} { |
| 1041 do_test pagerfault-21.crash.$iTest.1 { |
| 1042 crashsql -delay 1 -file test.db -seed $iTest { |
| 1043 BEGIN; |
| 1044 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); |
| 1045 INSERT INTO t1 SELECT a, b FROM t0; |
| 1046 COMMIT; |
| 1047 } |
| 1048 } {1 {child process exited abnormally}} |
| 1049 do_test pagerfault-22.$iTest.2 { |
| 1050 sqlite3 db test.db |
| 1051 execsql { PRAGMA integrity_check } |
| 1052 } {ok} |
| 1053 db close |
| 1054 } |
| 1055 } |
| 1056 |
| 1057 |
| 1058 #------------------------------------------------------------------------- |
| 1059 # When a 3.7.0 client opens a write-transaction on a database file that |
| 1060 # has been appended to or truncated by a pre-370 client, it updates |
| 1061 # the db-size in the file header immediately. This test case provokes |
| 1062 # errors during that operation. |
| 1063 # |
| 1064 do_test pagerfault-22-pre1 { |
| 1065 faultsim_delete_and_reopen |
| 1066 db func a_string a_string |
| 1067 execsql { |
| 1068 PRAGMA page_size = 1024; |
| 1069 PRAGMA auto_vacuum = 0; |
| 1070 CREATE TABLE t1(a); |
| 1071 CREATE INDEX i1 ON t1(a); |
| 1072 INSERT INTO t1 VALUES(a_string(3000)); |
| 1073 CREATE TABLE t2(a); |
| 1074 INSERT INTO t2 VALUES(1); |
| 1075 } |
| 1076 db close |
| 1077 sql36231 { INSERT INTO t1 VALUES(a_string(3000)) } |
| 1078 faultsim_save_and_close |
| 1079 } {} |
| 1080 do_faultsim_test pagerfault-22 -prep { |
| 1081 faultsim_restore_and_reopen |
| 1082 } -body { |
| 1083 execsql { INSERT INTO t2 VALUES(2) } |
| 1084 execsql { SELECT * FROM t2 } |
| 1085 } -test { |
| 1086 faultsim_test_result {0 {1 2}} |
| 1087 faultsim_integrity_check |
| 1088 } |
| 1089 |
| 1090 #------------------------------------------------------------------------- |
| 1091 # Provoke an OOM error during a commit of multi-file transaction. One of |
| 1092 # the databases written during the transaction is an in-memory database. |
| 1093 # This test causes rollback of the in-memory database after CommitPhaseOne() |
| 1094 # has successfully returned. i.e. the series of calls for the aborted commit |
| 1095 # is: |
| 1096 # |
| 1097 # PagerCommitPhaseOne(<in-memory-db>) -> SQLITE_OK |
| 1098 # PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR |
| 1099 # PagerRollback(<in-memory-db>) |
| 1100 # PagerRollback(<file-db>) |
| 1101 # |
| 1102 do_faultsim_test pagerfault-23 -prep { |
| 1103 sqlite3 db :memory: |
| 1104 foreach f [glob -nocomplain test.db*] { file delete -force $f } |
| 1105 db eval { |
| 1106 ATTACH 'test.db2' AS aux; |
| 1107 CREATE TABLE t1(a, b); |
| 1108 CREATE TABLE aux.t2(a, b); |
| 1109 } |
| 1110 } -body { |
| 1111 execsql { |
| 1112 BEGIN; |
| 1113 INSERT INTO t1 VALUES(1,2); |
| 1114 INSERT INTO t2 VALUES(3,4); |
| 1115 COMMIT; |
| 1116 } |
| 1117 } -test { |
| 1118 faultsim_test_result {0 {}} |
| 1119 faultsim_integrity_check |
| 1120 } |
| 1121 |
| 1122 do_faultsim_test pagerfault-24 -prep { |
| 1123 faultsim_delete_and_reopen |
| 1124 db eval { PRAGMA temp_store = file } |
| 1125 execsql { CREATE TABLE x(a, b) } |
| 1126 } -body { |
| 1127 execsql { CREATE TEMP TABLE t1(a, b) } |
| 1128 } -test { |
| 1129 faultsim_test_result {0 {}} \ |
| 1130 {1 {unable to open a temporary database file for storing temporary tables}} |
| 1131 set ic [db eval { PRAGMA temp.integrity_check }] |
| 1132 if {$ic != "ok"} { error "Integrity check: $ic" } |
| 1133 } |
| 1134 |
| 1135 proc lockrows {n} { |
| 1136 if {$n==0} { return "" } |
| 1137 db eval { SELECT * FROM t1 WHERE oid = $n } { |
| 1138 return [lockrows [expr {$n-1}]] |
| 1139 } |
| 1140 } |
| 1141 |
| 1142 |
| 1143 do_test pagerfault-25-pre1 { |
| 1144 faultsim_delete_and_reopen |
| 1145 db func a_string a_string |
| 1146 execsql { |
| 1147 PRAGMA page_size = 1024; |
| 1148 PRAGMA auto_vacuum = 0; |
| 1149 CREATE TABLE t1(a); |
| 1150 INSERT INTO t1 VALUES(a_string(500)); |
| 1151 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1152 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1153 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1154 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1155 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1156 } |
| 1157 faultsim_save_and_close |
| 1158 } {} |
| 1159 do_faultsim_test pagerfault-25 -prep { |
| 1160 faultsim_restore_and_reopen |
| 1161 db func a_string a_string |
| 1162 set ::channel [db incrblob -readonly t1 a 1] |
| 1163 execsql { |
| 1164 PRAGMA cache_size = 10; |
| 1165 BEGIN; |
| 1166 INSERT INTO t1 VALUES(a_string(3000)); |
| 1167 INSERT INTO t1 VALUES(a_string(3000)); |
| 1168 } |
| 1169 } -body { |
| 1170 lockrows 30 |
| 1171 } -test { |
| 1172 catch { lockrows 30 } |
| 1173 catch { db eval COMMIT } |
| 1174 close $::channel |
| 1175 faultsim_test_result {0 {}} |
| 1176 } |
| 1177 |
| 1178 do_faultsim_test pagerfault-26 -prep { |
| 1179 faultsim_delete_and_reopen |
| 1180 execsql { |
| 1181 PRAGMA page_size = 1024; |
| 1182 PRAGMA journal_mode = truncate; |
| 1183 PRAGMA auto_vacuum = full; |
| 1184 PRAGMA locking_mode=exclusive; |
| 1185 CREATE TABLE t1(a, b); |
| 1186 INSERT INTO t1 VALUES(1, 2); |
| 1187 PRAGMA page_size = 4096; |
| 1188 } |
| 1189 } -body { |
| 1190 execsql { |
| 1191 VACUUM; |
| 1192 } |
| 1193 } -test { |
| 1194 faultsim_test_result {0 {}} |
| 1195 |
| 1196 set contents [db eval {SELECT * FROM t1}] |
| 1197 if {$contents != "1 2"} { error "Bad database contents ($contents)" } |
| 1198 |
| 1199 set sz [file size test.db] |
| 1200 if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { |
| 1201 error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes" |
| 1202 } |
| 1203 if {$testrc==0 && $sz!=4096*3} { |
| 1204 error "Expected file size to be 12288 bytes - actual size $sz bytes" |
| 1205 } |
| 1206 } |
| 1207 |
| 1208 do_test pagerfault-27-pre { |
| 1209 faultsim_delete_and_reopen |
| 1210 db func a_string a_string |
| 1211 execsql { |
| 1212 PRAGMA page_size = 1024; |
| 1213 CREATE TABLE t1(a, b); |
| 1214 CREATE TABLE t2(a UNIQUE, b UNIQUE); |
| 1215 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); |
| 1216 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1217 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1218 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1219 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1220 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1221 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1222 INSERT INTO t1 VALUES (a_string(20000), a_string(20000)); |
| 1223 } |
| 1224 faultsim_save_and_close |
| 1225 } {} |
| 1226 do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep { |
| 1227 faultsim_restore_and_reopen |
| 1228 db func a_string a_string |
| 1229 execsql { |
| 1230 PRAGMA cache_size = 10; |
| 1231 BEGIN EXCLUSIVE; |
| 1232 } |
| 1233 set ::channel [db incrblob t1 a 1] |
| 1234 } -body { |
| 1235 puts $::channel [string repeat abc 6000] |
| 1236 flush $::channel |
| 1237 } -test { |
| 1238 catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) } |
| 1239 catch { close $::channel } |
| 1240 catchsql { ROLLBACK } |
| 1241 faultsim_integrity_check |
| 1242 } |
| 1243 |
| 1244 finish_test |
| 1245 |
OLD | NEW |