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 # Update: It is no longer possible to change the page size of any temp |
| 688 # database after it has been created. |
| 689 # |
| 690 do_faultsim_test pagerfault-14b -prep { |
| 691 catch { db2 close } |
| 692 faultsim_restore_and_reopen |
| 693 sqlite3 db2 "" |
| 694 db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) } |
| 695 } -body { |
| 696 sqlite3_backup B db2 main db main |
| 697 B step 200 |
| 698 set rc [B finish] |
| 699 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} |
| 700 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } |
| 701 set {} {} |
| 702 } -test { |
| 703 faultsim_test_result {1 {attempt to write a readonly database}} \ |
| 704 {1 {sqlite3_backup_init() failed}} |
| 705 } |
| 706 |
| 707 do_faultsim_test pagerfault-14c -prep { |
| 708 catch { db2 close } |
| 709 faultsim_restore_and_reopen |
| 710 sqlite3 db2 test.db2 |
| 711 db2 eval { |
| 712 PRAGMA synchronous = off; |
| 713 PRAGMA page_size = 4096; |
| 714 CREATE TABLE xx(a); |
| 715 } |
| 716 } -body { |
| 717 sqlite3_backup B db2 main db main |
| 718 B step 200 |
| 719 set rc [B finish] |
| 720 if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} |
| 721 if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } |
| 722 set {} {} |
| 723 } -test { |
| 724 faultsim_test_result {0 {}} {1 {sqlite3_backup_init() failed}} |
| 725 } |
| 726 |
| 727 do_test pagerfault-15-pre1 { |
| 728 faultsim_delete_and_reopen |
| 729 db func a_string a_string; |
| 730 execsql { |
| 731 BEGIN; |
| 732 CREATE TABLE t1(x, y UNIQUE); |
| 733 INSERT INTO t1 VALUES(a_string(11), a_string(22)); |
| 734 INSERT INTO t1 VALUES(a_string(11), a_string(22)); |
| 735 COMMIT; |
| 736 } |
| 737 faultsim_save_and_close |
| 738 } {} |
| 739 do_faultsim_test pagerfault-15 -prep { |
| 740 faultsim_restore_and_reopen |
| 741 db func a_string a_string; |
| 742 } -body { |
| 743 db eval { SELECT * FROM t1 LIMIT 1 } { |
| 744 execsql { |
| 745 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; |
| 746 BEGIN; INSERT INTO t1 VALUES(a_string(333), a_string(555)); COMMIT; |
| 747 } |
| 748 } |
| 749 } -test { |
| 750 faultsim_test_result {0 {}} |
| 751 faultsim_integrity_check |
| 752 } |
| 753 |
| 754 |
| 755 do_test pagerfault-16-pre1 { |
| 756 faultsim_delete_and_reopen |
| 757 execsql { CREATE TABLE t1(x, y UNIQUE) } |
| 758 faultsim_save_and_close |
| 759 } {} |
| 760 do_faultsim_test pagerfault-16 -prep { |
| 761 faultsim_restore_and_reopen |
| 762 } -body { |
| 763 execsql { |
| 764 PRAGMA locking_mode = exclusive; |
| 765 PRAGMA journal_mode = wal; |
| 766 INSERT INTO t1 VALUES(1, 2); |
| 767 INSERT INTO t1 VALUES(3, 4); |
| 768 PRAGMA journal_mode = delete; |
| 769 INSERT INTO t1 VALUES(4, 5); |
| 770 PRAGMA journal_mode = wal; |
| 771 INSERT INTO t1 VALUES(6, 7); |
| 772 PRAGMA journal_mode = persist; |
| 773 INSERT INTO t1 VALUES(8, 9); |
| 774 } |
| 775 } -test { |
| 776 faultsim_test_result {0 {exclusive wal delete wal persist}} |
| 777 faultsim_integrity_check |
| 778 } |
| 779 |
| 780 |
| 781 #------------------------------------------------------------------------- |
| 782 # Test fault injection while changing into and out of WAL mode. |
| 783 # |
| 784 do_test pagerfault-17-pre1 { |
| 785 faultsim_delete_and_reopen |
| 786 execsql { |
| 787 CREATE TABLE t1(a PRIMARY KEY, b); |
| 788 INSERT INTO t1 VALUES(1862, 'Botha'); |
| 789 INSERT INTO t1 VALUES(1870, 'Smuts'); |
| 790 INSERT INTO t1 VALUES(1866, 'Hertzog'); |
| 791 } |
| 792 faultsim_save_and_close |
| 793 } {} |
| 794 do_faultsim_test pagerfault-17a -prep { |
| 795 faultsim_restore_and_reopen |
| 796 } -body { |
| 797 execsql { |
| 798 PRAGMA journal_mode = wal; |
| 799 PRAGMA journal_mode = delete; |
| 800 } |
| 801 } -test { |
| 802 faultsim_test_result {0 {wal delete}} |
| 803 faultsim_integrity_check |
| 804 } |
| 805 do_faultsim_test pagerfault-17b -prep { |
| 806 faultsim_restore_and_reopen |
| 807 execsql { PRAGMA synchronous = OFF } |
| 808 } -body { |
| 809 execsql { |
| 810 PRAGMA journal_mode = wal; |
| 811 INSERT INTO t1 VALUES(22, 'Clarke'); |
| 812 PRAGMA journal_mode = delete; |
| 813 } |
| 814 } -test { |
| 815 faultsim_test_result {0 {wal delete}} |
| 816 faultsim_integrity_check |
| 817 } |
| 818 do_faultsim_test pagerfault-17c -prep { |
| 819 faultsim_restore_and_reopen |
| 820 execsql { |
| 821 PRAGMA locking_mode = exclusive; |
| 822 PRAGMA journal_mode = wal; |
| 823 } |
| 824 } -body { |
| 825 execsql { PRAGMA journal_mode = delete } |
| 826 } -test { |
| 827 faultsim_test_result {0 delete} |
| 828 faultsim_integrity_check |
| 829 } |
| 830 do_faultsim_test pagerfault-17d -prep { |
| 831 catch { db2 close } |
| 832 faultsim_restore_and_reopen |
| 833 sqlite3 db2 test.db |
| 834 execsql { PRAGMA journal_mode = delete } |
| 835 execsql { PRAGMA journal_mode = wal } |
| 836 execsql { INSERT INTO t1 VALUES(99, 'Bradman') } db2 |
| 837 } -body { |
| 838 execsql { PRAGMA journal_mode = delete } |
| 839 } -test { |
| 840 faultsim_test_result {1 {database is locked}} |
| 841 faultsim_integrity_check |
| 842 } |
| 843 do_faultsim_test pagerfault-17e -prep { |
| 844 catch { db2 close } |
| 845 faultsim_restore_and_reopen |
| 846 sqlite3 db2 test.db |
| 847 execsql { PRAGMA journal_mode = delete } |
| 848 execsql { PRAGMA journal_mode = wal } |
| 849 set ::chan [launch_testfixture] |
| 850 testfixture $::chan { |
| 851 sqlite3 db test.db |
| 852 db eval { INSERT INTO t1 VALUES(101, 'Latham') } |
| 853 } |
| 854 catch { testfixture $::chan sqlite_abort } |
| 855 catch { close $::chan } |
| 856 } -body { |
| 857 execsql { PRAGMA journal_mode = delete } |
| 858 } -test { |
| 859 faultsim_test_result {0 delete} |
| 860 faultsim_integrity_check |
| 861 } |
| 862 |
| 863 #------------------------------------------------------------------------- |
| 864 # Test fault-injection when changing from journal_mode=persist to |
| 865 # journal_mode=delete (this involves deleting the journal file). |
| 866 # |
| 867 do_test pagerfault-18-pre1 { |
| 868 faultsim_delete_and_reopen |
| 869 execsql { |
| 870 CREATE TABLE qq(x); |
| 871 INSERT INTO qq VALUES('Herbert'); |
| 872 INSERT INTO qq VALUES('Macalister'); |
| 873 INSERT INTO qq VALUES('Mackenzie'); |
| 874 INSERT INTO qq VALUES('Lilley'); |
| 875 INSERT INTO qq VALUES('Palmer'); |
| 876 } |
| 877 faultsim_save_and_close |
| 878 } {} |
| 879 do_faultsim_test pagerfault-18 -prep { |
| 880 faultsim_restore_and_reopen |
| 881 execsql { |
| 882 PRAGMA journal_mode = PERSIST; |
| 883 INSERT INTO qq VALUES('Beatty'); |
| 884 } |
| 885 } -body { |
| 886 execsql { PRAGMA journal_mode = delete } |
| 887 } -test { |
| 888 faultsim_test_result {0 delete} |
| 889 faultsim_integrity_check |
| 890 } |
| 891 |
| 892 do_faultsim_test pagerfault-19a -prep { |
| 893 sqlite3 db :memory: |
| 894 db func a_string a_string |
| 895 execsql { |
| 896 PRAGMA auto_vacuum = FULL; |
| 897 BEGIN; |
| 898 CREATE TABLE t1(a, b); |
| 899 INSERT INTO t1 VALUES(a_string(5000), a_string(6000)); |
| 900 COMMIT; |
| 901 } |
| 902 } -body { |
| 903 execsql { |
| 904 CREATE TABLE t2(a, b); |
| 905 INSERT INTO t2 SELECT * FROM t1; |
| 906 DELETE FROM t1; |
| 907 } |
| 908 } -test { |
| 909 faultsim_test_result {0 {}} |
| 910 } |
| 911 |
| 912 do_test pagerfault-19-pre1 { |
| 913 faultsim_delete_and_reopen |
| 914 execsql { |
| 915 PRAGMA auto_vacuum = FULL; |
| 916 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); |
| 917 CREATE TABLE t2(x); INSERT INTO t2 VALUES(2); |
| 918 CREATE TABLE t3(x); INSERT INTO t3 VALUES(3); |
| 919 CREATE TABLE t4(x); INSERT INTO t4 VALUES(4); |
| 920 CREATE TABLE t5(x); INSERT INTO t5 VALUES(5); |
| 921 CREATE TABLE t6(x); INSERT INTO t6 VALUES(6); |
| 922 } |
| 923 faultsim_save_and_close |
| 924 } {} |
| 925 do_faultsim_test pagerfault-19b -prep { |
| 926 faultsim_restore_and_reopen |
| 927 } -body { |
| 928 execsql { |
| 929 BEGIN; |
| 930 UPDATE t4 SET x = x+1; |
| 931 UPDATE t6 SET x = x+1; |
| 932 SAVEPOINT one; |
| 933 UPDATE t3 SET x = x+1; |
| 934 SAVEPOINT two; |
| 935 DROP TABLE t2; |
| 936 ROLLBACK TO one; |
| 937 COMMIT; |
| 938 SELECT * FROM t3; |
| 939 SELECT * FROM t4; |
| 940 SELECT * FROM t6; |
| 941 } |
| 942 } -test { |
| 943 faultsim_test_result {0 {3 5 7}} |
| 944 } |
| 945 |
| 946 #------------------------------------------------------------------------- |
| 947 # This tests fault-injection in a special case in the auto-vacuum code. |
| 948 # |
| 949 do_test pagerfault-20-pre1 { |
| 950 faultsim_delete_and_reopen |
| 951 execsql { |
| 952 PRAGMA cache_size = 10; |
| 953 PRAGMA auto_vacuum = FULL; |
| 954 CREATE TABLE t0(a, b); |
| 955 } |
| 956 faultsim_save_and_close |
| 957 } {} |
| 958 do_faultsim_test pagerfault-20 -prep { |
| 959 faultsim_restore_and_reopen |
| 960 } -body { |
| 961 execsql { |
| 962 BEGIN; |
| 963 CREATE TABLE t1(a, b); |
| 964 CREATE TABLE t2(a, b); |
| 965 DROP TABLE t1; |
| 966 COMMIT; |
| 967 } |
| 968 } -test { |
| 969 faultsim_test_result {0 {}} |
| 970 } |
| 971 |
| 972 do_test pagerfault-21-pre1 { |
| 973 faultsim_delete_and_reopen |
| 974 execsql { |
| 975 PRAGMA cache_size = 10; |
| 976 CREATE TABLE t0(a PRIMARY KEY, b); |
| 977 INSERT INTO t0 VALUES(1, 2); |
| 978 } |
| 979 faultsim_save_and_close |
| 980 } {} |
| 981 do_faultsim_test pagerfault-21 -prep { |
| 982 faultsim_restore_and_reopen |
| 983 } -body { |
| 984 db eval { SELECT * FROM t0 LIMIT 1 } { |
| 985 db eval { INSERT INTO t0 SELECT a+1, b FROM t0 } |
| 986 db eval { INSERT INTO t0 SELECT a+2, b FROM t0 } |
| 987 } |
| 988 } -test { |
| 989 faultsim_test_result {0 {}} |
| 990 } |
| 991 |
| 992 |
| 993 #------------------------------------------------------------------------- |
| 994 # Test fault-injection and rollback when the nReserve header value |
| 995 # is non-zero. |
| 996 # |
| 997 do_test pagerfault-21-pre1 { |
| 998 faultsim_delete_and_reopen |
| 999 execsql { |
| 1000 PRAGMA page_size = 1024; |
| 1001 PRAGMA journal_mode = WAL; |
| 1002 PRAGMA journal_mode = DELETE; |
| 1003 } |
| 1004 db close |
| 1005 hexio_write test.db 20 10 |
| 1006 hexio_write test.db 105 03F0 |
| 1007 sqlite3 db test.db |
| 1008 db func a_string a_string |
| 1009 execsql { |
| 1010 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); |
| 1011 INSERT INTO t0 VALUES(a_string(222), a_string(333)); |
| 1012 INSERT INTO t0 VALUES(a_string(223), a_string(334)); |
| 1013 INSERT INTO t0 VALUES(a_string(224), a_string(335)); |
| 1014 INSERT INTO t0 VALUES(a_string(225), a_string(336)); |
| 1015 } |
| 1016 faultsim_save_and_close |
| 1017 } {} |
| 1018 |
| 1019 do_faultsim_test pagerfault-21 -prep { |
| 1020 faultsim_restore_and_reopen |
| 1021 } -body { |
| 1022 execsql { INSERT INTO t0 SELECT a||'x', b||'x' FROM t0 } |
| 1023 } -test { |
| 1024 faultsim_test_result {0 {}} |
| 1025 faultsim_integrity_check |
| 1026 } |
| 1027 ifcapable crashtest { |
| 1028 faultsim_delete_and_reopen |
| 1029 execsql { |
| 1030 PRAGMA page_size = 1024; |
| 1031 PRAGMA journal_mode = WAL; |
| 1032 PRAGMA journal_mode = DELETE; |
| 1033 } |
| 1034 db close |
| 1035 hexio_write test.db 20 10 |
| 1036 hexio_write test.db 105 03F0 |
| 1037 |
| 1038 sqlite3 db test.db |
| 1039 db func a_string a_string |
| 1040 execsql { |
| 1041 CREATE TABLE t0(a PRIMARY KEY, b UNIQUE); |
| 1042 INSERT INTO t0 VALUES(a_string(222), a_string(333)); |
| 1043 INSERT INTO t0 VALUES(a_string(223), a_string(334)); |
| 1044 } |
| 1045 faultsim_save_and_close |
| 1046 |
| 1047 for {set iTest 1} {$iTest<50} {incr iTest} { |
| 1048 do_test pagerfault-21.crash.$iTest.1 { |
| 1049 crashsql -delay 1 -file test.db -seed $iTest { |
| 1050 BEGIN; |
| 1051 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); |
| 1052 INSERT INTO t1 SELECT a, b FROM t0; |
| 1053 COMMIT; |
| 1054 } |
| 1055 } {1 {child process exited abnormally}} |
| 1056 do_test pagerfault-22.$iTest.2 { |
| 1057 sqlite3 db test.db |
| 1058 execsql { PRAGMA integrity_check } |
| 1059 } {ok} |
| 1060 db close |
| 1061 } |
| 1062 } |
| 1063 |
| 1064 |
| 1065 #------------------------------------------------------------------------- |
| 1066 # When a 3.7.0 client opens a write-transaction on a database file that |
| 1067 # has been appended to or truncated by a pre-370 client, it updates |
| 1068 # the db-size in the file header immediately. This test case provokes |
| 1069 # errors during that operation. |
| 1070 # |
| 1071 do_test pagerfault-22-pre1 { |
| 1072 faultsim_delete_and_reopen |
| 1073 db func a_string a_string |
| 1074 execsql { |
| 1075 PRAGMA page_size = 1024; |
| 1076 PRAGMA auto_vacuum = 0; |
| 1077 CREATE TABLE t1(a); |
| 1078 CREATE INDEX i1 ON t1(a); |
| 1079 INSERT INTO t1 VALUES(a_string(3000)); |
| 1080 CREATE TABLE t2(a); |
| 1081 INSERT INTO t2 VALUES(1); |
| 1082 } |
| 1083 db close |
| 1084 sql36231 { INSERT INTO t1 VALUES(a_string(3000)) } |
| 1085 faultsim_save_and_close |
| 1086 } {} |
| 1087 do_faultsim_test pagerfault-22 -prep { |
| 1088 faultsim_restore_and_reopen |
| 1089 } -body { |
| 1090 execsql { INSERT INTO t2 VALUES(2) } |
| 1091 execsql { SELECT * FROM t2 } |
| 1092 } -test { |
| 1093 faultsim_test_result {0 {1 2}} |
| 1094 faultsim_integrity_check |
| 1095 } |
| 1096 |
| 1097 #------------------------------------------------------------------------- |
| 1098 # Provoke an OOM error during a commit of multi-file transaction. One of |
| 1099 # the databases written during the transaction is an in-memory database. |
| 1100 # This test causes rollback of the in-memory database after CommitPhaseOne() |
| 1101 # has successfully returned. i.e. the series of calls for the aborted commit |
| 1102 # is: |
| 1103 # |
| 1104 # PagerCommitPhaseOne(<in-memory-db>) -> SQLITE_OK |
| 1105 # PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR |
| 1106 # PagerRollback(<in-memory-db>) |
| 1107 # PagerRollback(<file-db>) |
| 1108 # |
| 1109 do_faultsim_test pagerfault-23 -prep { |
| 1110 sqlite3 db :memory: |
| 1111 foreach f [glob -nocomplain test.db*] { forcedelete $f } |
| 1112 db eval { |
| 1113 ATTACH 'test.db2' AS aux; |
| 1114 CREATE TABLE t1(a, b); |
| 1115 CREATE TABLE aux.t2(a, b); |
| 1116 } |
| 1117 } -body { |
| 1118 execsql { |
| 1119 BEGIN; |
| 1120 INSERT INTO t1 VALUES(1,2); |
| 1121 INSERT INTO t2 VALUES(3,4); |
| 1122 COMMIT; |
| 1123 } |
| 1124 } -test { |
| 1125 faultsim_test_result {0 {}} |
| 1126 faultsim_integrity_check |
| 1127 } |
| 1128 |
| 1129 do_faultsim_test pagerfault-24 -prep { |
| 1130 faultsim_delete_and_reopen |
| 1131 db eval { PRAGMA temp_store = file } |
| 1132 execsql { CREATE TABLE x(a, b) } |
| 1133 } -body { |
| 1134 execsql { CREATE TEMP TABLE t1(a, b) } |
| 1135 } -test { |
| 1136 faultsim_test_result {0 {}} \ |
| 1137 {1 {unable to open a temporary database file for storing temporary tables}} |
| 1138 set ic [db eval { PRAGMA temp.integrity_check }] |
| 1139 if {$ic != "ok"} { error "Integrity check: $ic" } |
| 1140 } |
| 1141 |
| 1142 proc lockrows {n} { |
| 1143 if {$n==0} { return "" } |
| 1144 db eval { SELECT * FROM t1 WHERE oid = $n } { |
| 1145 return [lockrows [expr {$n-1}]] |
| 1146 } |
| 1147 } |
| 1148 |
| 1149 |
| 1150 do_test pagerfault-25-pre1 { |
| 1151 faultsim_delete_and_reopen |
| 1152 db func a_string a_string |
| 1153 execsql { |
| 1154 PRAGMA page_size = 1024; |
| 1155 PRAGMA auto_vacuum = 0; |
| 1156 CREATE TABLE t1(a); |
| 1157 INSERT INTO t1 VALUES(a_string(500)); |
| 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 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1162 INSERT INTO t1 SELECT a_string(500) FROM t1; |
| 1163 } |
| 1164 faultsim_save_and_close |
| 1165 } {} |
| 1166 do_faultsim_test pagerfault-25 -prep { |
| 1167 faultsim_restore_and_reopen |
| 1168 db func a_string a_string |
| 1169 set ::channel [db incrblob -readonly t1 a 1] |
| 1170 execsql { |
| 1171 PRAGMA cache_size = 10; |
| 1172 BEGIN; |
| 1173 INSERT INTO t1 VALUES(a_string(3000)); |
| 1174 INSERT INTO t1 VALUES(a_string(3000)); |
| 1175 } |
| 1176 } -body { |
| 1177 lockrows 30 |
| 1178 } -test { |
| 1179 catch { lockrows 30 } |
| 1180 catch { db eval COMMIT } |
| 1181 close $::channel |
| 1182 faultsim_test_result {0 {}} |
| 1183 } |
| 1184 |
| 1185 do_faultsim_test pagerfault-26 -prep { |
| 1186 faultsim_delete_and_reopen |
| 1187 execsql { |
| 1188 PRAGMA page_size = 1024; |
| 1189 PRAGMA journal_mode = truncate; |
| 1190 PRAGMA auto_vacuum = full; |
| 1191 PRAGMA locking_mode=exclusive; |
| 1192 CREATE TABLE t1(a, b); |
| 1193 INSERT INTO t1 VALUES(1, 2); |
| 1194 PRAGMA page_size = 4096; |
| 1195 } |
| 1196 } -body { |
| 1197 execsql { |
| 1198 VACUUM; |
| 1199 } |
| 1200 } -test { |
| 1201 faultsim_test_result {0 {}} |
| 1202 |
| 1203 set contents [db eval {SELECT * FROM t1}] |
| 1204 if {$contents != "1 2"} { error "Bad database contents ($contents)" } |
| 1205 |
| 1206 set sz [file size test.db] |
| 1207 if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { |
| 1208 error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes" |
| 1209 } |
| 1210 if {$testrc==0 && $sz!=4096*3} { |
| 1211 error "Expected file size to be 12288 bytes - actual size $sz bytes" |
| 1212 } |
| 1213 } |
| 1214 |
| 1215 do_test pagerfault-27-pre { |
| 1216 faultsim_delete_and_reopen |
| 1217 db func a_string a_string |
| 1218 execsql { |
| 1219 PRAGMA page_size = 1024; |
| 1220 CREATE TABLE t1(a, b); |
| 1221 CREATE TABLE t2(a UNIQUE, b UNIQUE); |
| 1222 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); |
| 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 t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1228 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1229 INSERT INTO t1 VALUES (a_string(20000), a_string(20000)); |
| 1230 } |
| 1231 faultsim_save_and_close |
| 1232 } {} |
| 1233 do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep { |
| 1234 faultsim_restore_and_reopen |
| 1235 db func a_string a_string |
| 1236 execsql { |
| 1237 PRAGMA cache_size = 10; |
| 1238 BEGIN EXCLUSIVE; |
| 1239 } |
| 1240 set ::channel [db incrblob t1 a 1] |
| 1241 } -body { |
| 1242 puts $::channel [string repeat abc 6000] |
| 1243 flush $::channel |
| 1244 } -test { |
| 1245 catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) } |
| 1246 catch { close $::channel } |
| 1247 catchsql { ROLLBACK } |
| 1248 faultsim_integrity_check |
| 1249 } |
| 1250 |
| 1251 |
| 1252 #------------------------------------------------------------------------- |
| 1253 # |
| 1254 do_test pagerfault-28-pre { |
| 1255 faultsim_delete_and_reopen |
| 1256 db func a_string a_string |
| 1257 execsql { |
| 1258 PRAGMA page_size = 512; |
| 1259 |
| 1260 PRAGMA journal_mode = wal; |
| 1261 PRAGMA wal_autocheckpoint = 0; |
| 1262 PRAGMA cache_size = 100000; |
| 1263 |
| 1264 BEGIN; |
| 1265 CREATE TABLE t2(a UNIQUE, b UNIQUE); |
| 1266 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); |
| 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 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1277 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1278 COMMIT; |
| 1279 CREATE TABLE t1(a PRIMARY KEY, b); |
| 1280 } |
| 1281 expr {[file size test.db-shm] >= 96*1024} |
| 1282 } {1} |
| 1283 faultsim_save_and_close |
| 1284 |
| 1285 do_faultsim_test pagerfault-28a -faults oom* -prep { |
| 1286 faultsim_restore_and_reopen |
| 1287 execsql { PRAGMA mmap_size=0 } |
| 1288 |
| 1289 sqlite3 db2 test.db |
| 1290 db2 eval { SELECT count(*) FROM t2 } |
| 1291 |
| 1292 db func a_string a_string |
| 1293 execsql { |
| 1294 BEGIN; |
| 1295 INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); |
| 1296 INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); |
| 1297 } |
| 1298 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY] |
| 1299 sqlite3_step $::STMT |
| 1300 } -body { |
| 1301 execsql { ROLLBACK } |
| 1302 } -test { |
| 1303 db2 close |
| 1304 sqlite3_finalize $::STMT |
| 1305 catchsql { ROLLBACK } |
| 1306 faultsim_integrity_check |
| 1307 } |
| 1308 |
| 1309 faultsim_restore_and_reopen |
| 1310 sqlite3 db2 test.db |
| 1311 db2 eval {SELECT count(*) FROM t2} |
| 1312 db close |
| 1313 |
| 1314 do_faultsim_test pagerfault-28b -faults oom* -prep { |
| 1315 sqlite3 db test.db |
| 1316 } -body { |
| 1317 execsql { SELECT count(*) FROM t2 } |
| 1318 } -test { |
| 1319 faultsim_test_result {0 2048} |
| 1320 db close |
| 1321 } |
| 1322 |
| 1323 db2 close |
| 1324 |
| 1325 #------------------------------------------------------------------------- |
| 1326 # Try this: |
| 1327 # |
| 1328 # 1) Put the pager in ERROR state (error during rollback) |
| 1329 # |
| 1330 # 2) Next time the connection is used inject errors into all xWrite() and |
| 1331 # xUnlock() calls. This causes the hot-journal rollback to fail and |
| 1332 # the pager to declare its locking state UNKNOWN. |
| 1333 # |
| 1334 # 3) Same again. |
| 1335 # |
| 1336 # 4a) Stop injecting errors. Allow the rollback to succeed. Check that |
| 1337 # the database is Ok. Or, |
| 1338 # |
| 1339 # 4b) Close and reopen the db. Check that the db is Ok. |
| 1340 # |
| 1341 proc custom_injectinstall {} { |
| 1342 testvfs custom -default true |
| 1343 custom filter {xWrite xUnlock} |
| 1344 } |
| 1345 proc custom_injectuninstall {} { |
| 1346 catch {db close} |
| 1347 catch {db2 close} |
| 1348 custom delete |
| 1349 } |
| 1350 proc custom_injectstart {iFail} { |
| 1351 custom ioerr $iFail 1 |
| 1352 } |
| 1353 proc custom_injectstop {} { |
| 1354 custom ioerr |
| 1355 } |
| 1356 set ::FAULTSIM(custom) [list \ |
| 1357 -injectinstall custom_injectinstall \ |
| 1358 -injectstart custom_injectstart \ |
| 1359 -injectstop custom_injectstop \ |
| 1360 -injecterrlist {{1 {disk I/O error}}} \ |
| 1361 -injectuninstall custom_injectuninstall \ |
| 1362 ] |
| 1363 |
| 1364 do_test pagerfault-29-pre { |
| 1365 faultsim_delete_and_reopen |
| 1366 db func a_string a_string |
| 1367 execsql { |
| 1368 PRAGMA page_size = 1024; |
| 1369 PRAGMA cache_size = 5; |
| 1370 |
| 1371 BEGIN; |
| 1372 CREATE TABLE t2(a UNIQUE, b UNIQUE); |
| 1373 INSERT INTO t2 VALUES( a_string(800), a_string(800) ); |
| 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 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1377 INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; |
| 1378 COMMIT; |
| 1379 } |
| 1380 expr {[file size test.db] >= 50*1024} |
| 1381 } {1} |
| 1382 faultsim_save_and_close |
| 1383 foreach {tn tt} { |
| 1384 29 { catchsql ROLLBACK } |
| 1385 30 { db close ; sqlite3 db test.db } |
| 1386 } { |
| 1387 do_faultsim_test pagerfault-$tn -faults custom -prep { |
| 1388 faultsim_restore_and_reopen |
| 1389 db func a_string a_string |
| 1390 execsql { |
| 1391 PRAGMA cache_size = 5; |
| 1392 BEGIN; |
| 1393 UPDATE t2 SET a = a_string(799); |
| 1394 } |
| 1395 } -body { |
| 1396 catchsql ROLLBACK |
| 1397 catchsql ROLLBACK |
| 1398 catchsql ROLLBACK |
| 1399 } -test { |
| 1400 eval $::tt |
| 1401 if {"ok" != [db one {PRAGMA integrity_check}]} { |
| 1402 error "integrity check failed" |
| 1403 } |
| 1404 } |
| 1405 } |
| 1406 |
| 1407 do_test pagerfault-31-pre { |
| 1408 sqlite3_shutdown |
| 1409 sqlite3_config_uri 1 |
| 1410 } {SQLITE_OK} |
| 1411 do_faultsim_test pagerfault-31 -faults oom* -body { |
| 1412 sqlite3 db {file:one?mode=memory&cache=shared} |
| 1413 db eval { |
| 1414 CREATE TABLE t1(x); |
| 1415 INSERT INTO t1 VALUES(1); |
| 1416 SELECT * FROM t1; |
| 1417 } |
| 1418 } -test { |
| 1419 faultsim_test_result {0 1} {1 {}} |
| 1420 catch { db close } |
| 1421 } |
| 1422 sqlite3_shutdown |
| 1423 sqlite3_config_uri 0 |
| 1424 |
| 1425 do_test pagerfault-32-pre { |
| 1426 reset_db |
| 1427 execsql { |
| 1428 CREATE TABLE t1(x); |
| 1429 INSERT INTO t1 VALUES('one'); |
| 1430 } |
| 1431 } {} |
| 1432 faultsim_save_and_close |
| 1433 |
| 1434 do_faultsim_test pagerfault-32 -prep { |
| 1435 faultsim_restore_and_reopen |
| 1436 db eval { SELECT * FROM t1; } |
| 1437 } -body { |
| 1438 execsql { SELECT * FROM t1; } |
| 1439 } -test { |
| 1440 faultsim_test_result {0 one} |
| 1441 } |
| 1442 sqlite3_shutdown |
| 1443 sqlite3_config_uri 0 |
| 1444 |
| 1445 do_faultsim_test pagerfault-33a -prep { |
| 1446 sqlite3 db :memory: |
| 1447 execsql { |
| 1448 CREATE TABLE t1(a, b); |
| 1449 INSERT INTO t1 VALUES(1, 2); |
| 1450 } |
| 1451 } -body { |
| 1452 execsql { VACUUM } |
| 1453 } -test { |
| 1454 faultsim_test_result {0 {}} |
| 1455 } |
| 1456 do_faultsim_test pagerfault-33b -prep { |
| 1457 sqlite3 db "" |
| 1458 execsql { |
| 1459 CREATE TABLE t1(a, b); |
| 1460 INSERT INTO t1 VALUES(1, 2); |
| 1461 } |
| 1462 } -body { |
| 1463 execsql { VACUUM } |
| 1464 } -test { |
| 1465 faultsim_test_result {0 {}} |
| 1466 } |
| 1467 |
| 1468 do_test pagerfault-34-pre { |
| 1469 reset_db |
| 1470 execsql { |
| 1471 CREATE TABLE t1(x PRIMARY KEY); |
| 1472 } |
| 1473 } {} |
| 1474 faultsim_save_and_close |
| 1475 do_faultsim_test pagerfault-34 -prep { |
| 1476 faultsim_restore_and_reopen |
| 1477 execsql { |
| 1478 BEGIN; |
| 1479 INSERT INTO t1 VALUES( randomblob(4000) ); |
| 1480 DELETE FROM t1; |
| 1481 } |
| 1482 } -body { |
| 1483 execsql COMMIT |
| 1484 } -test { |
| 1485 faultsim_test_result {0 {}} |
| 1486 } |
| 1487 |
| 1488 do_test pagerfault-35-pre { |
| 1489 faultsim_delete_and_reopen |
| 1490 execsql { |
| 1491 CREATE TABLE t1(x PRIMARY KEY, y); |
| 1492 INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); |
| 1493 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; |
| 1494 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; |
| 1495 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; |
| 1496 } |
| 1497 faultsim_save_and_close |
| 1498 } {} |
| 1499 testvfs tv -default 1 |
| 1500 tv sectorsize 8192; |
| 1501 tv devchar [list] |
| 1502 do_faultsim_test pagerfault-35 -prep { |
| 1503 faultsim_restore_and_reopen |
| 1504 } -body { |
| 1505 execsql { UPDATE t1 SET x=randomblob(200) } |
| 1506 } -test { |
| 1507 faultsim_test_result {0 {}} |
| 1508 } |
| 1509 catch {db close} |
| 1510 tv delete |
| 1511 |
| 1512 sqlite3_shutdown |
| 1513 sqlite3_config_uri 1 |
| 1514 do_test pagerfault-36-pre { |
| 1515 faultsim_delete_and_reopen |
| 1516 execsql { |
| 1517 CREATE TABLE t1(x PRIMARY KEY, y); |
| 1518 INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); |
| 1519 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; |
| 1520 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; |
| 1521 INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; |
| 1522 } |
| 1523 faultsim_save_and_close |
| 1524 } {} |
| 1525 do_faultsim_test pagerfault-36 -prep { |
| 1526 faultsim_restore |
| 1527 sqlite3 db file:test.db?cache=shared |
| 1528 sqlite3 db2 file:test.db?cache=shared |
| 1529 db2 eval { |
| 1530 BEGIN; |
| 1531 SELECT count(*) FROM sqlite_master; |
| 1532 } |
| 1533 db eval { |
| 1534 PRAGMA cache_size = 1; |
| 1535 BEGIN; |
| 1536 UPDATE t1 SET x = randomblob(200); |
| 1537 } |
| 1538 } -body { |
| 1539 execsql ROLLBACK db |
| 1540 } -test { |
| 1541 catch { db eval {UPDATE t1 SET x = randomblob(200)} } |
| 1542 faultsim_test_result {0 {}} |
| 1543 catch { db close } |
| 1544 catch { db2 close } |
| 1545 } |
| 1546 |
| 1547 sqlite3_shutdown |
| 1548 sqlite3_config_uri 0 |
| 1549 sqlite3_initialize |
| 1550 |
| 1551 finish_test |
OLD | NEW |