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