gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/wal2.test (about) 1 # 2010 May 5 2 # 3 # The author disclaims copyright to this source code. In place of 4 # a legal notice, here is a blessing: 5 # 6 # May you do good and not evil. 7 # May you find forgiveness for yourself and forgive others. 8 # May you share freely, never taking more than you give. 9 # 10 #*********************************************************************** 11 # This file implements regression tests for SQLite library. The 12 # focus of this file is testing the operation of the library in 13 # "PRAGMA journal_mode=WAL" mode. 14 # 15 16 set testdir [file dirname $argv0] 17 source $testdir/tester.tcl 18 source $testdir/lock_common.tcl 19 source $testdir/malloc_common.tcl 20 source $testdir/wal_common.tcl 21 22 set testprefix wal2 23 24 ifcapable !wal {finish_test ; return } 25 26 set sqlite_sync_count 0 27 proc cond_incr_sync_count {adj} { 28 global sqlite_sync_count 29 if {$::tcl_platform(platform) == "windows"} { 30 incr sqlite_sync_count $adj 31 } { 32 ifcapable !dirsync { 33 incr sqlite_sync_count $adj 34 } 35 } 36 } 37 38 proc set_tvfs_hdr {file args} { 39 40 # Set $nHdr to the number of bytes in the wal-index header: 41 set nHdr 48 42 set nInt [expr {$nHdr/4}] 43 44 if {[llength $args]>2} { 45 error {wrong # args: should be "set_tvfs_hdr fileName ?val1? ?val2?"} 46 } 47 48 set blob [tvfs shm $file] 49 if {$::tcl_platform(byteOrder)=="bigEndian"} {set fmt I} {set fmt i} 50 51 if {[llength $args]} { 52 set ia [lindex $args 0] 53 set ib $ia 54 if {[llength $args]==2} { 55 set ib [lindex $args 1] 56 } 57 binary scan $blob a[expr $nHdr*2]a* dummy tail 58 set blob [binary format ${fmt}${nInt}${fmt}${nInt}a* $ia $ib $tail] 59 tvfs shm $file $blob 60 } 61 62 binary scan $blob ${fmt}${nInt} ints 63 return $ints 64 } 65 66 proc incr_tvfs_hdr {file idx incrval} { 67 set ints [set_tvfs_hdr $file] 68 set v [lindex $ints $idx] 69 incr v $incrval 70 lset ints $idx $v 71 set_tvfs_hdr $file $ints 72 } 73 74 75 #------------------------------------------------------------------------- 76 # Test case wal2-1.*: 77 # 78 # Set up a small database containing a single table. The database is not 79 # checkpointed during the test - all content resides in the log file. 80 # 81 # Two connections are established to the database file - a writer ([db]) 82 # and a reader ([db2]). For each of the 8 integer fields in the wal-index 83 # header (6 fields and 2 checksum values), do the following: 84 # 85 # 1. Modify the database using the writer. 86 # 87 # 2. Attempt to read the database using the reader. Before the reader 88 # has a chance to snapshot the wal-index header, increment one 89 # of the integer fields (so that the reader ends up with a corrupted 90 # header). 91 # 92 # 3. Check that the reader recovers the wal-index and reads the correct 93 # database content. 94 # 95 do_test wal2-1.0 { 96 proc tvfs_cb {method filename args} { 97 set ::filename $filename 98 return SQLITE_OK 99 } 100 101 testvfs tvfs 102 tvfs script tvfs_cb 103 tvfs filter xShmOpen 104 105 sqlite3 db test.db -vfs tvfs 106 sqlite3 db2 test.db -vfs tvfs 107 108 execsql { 109 PRAGMA journal_mode = WAL; 110 CREATE TABLE t1(a); 111 } db2 112 execsql { 113 INSERT INTO t1 VALUES(1); 114 INSERT INTO t1 VALUES(2); 115 INSERT INTO t1 VALUES(3); 116 INSERT INTO t1 VALUES(4); 117 SELECT count(a), sum(a) FROM t1; 118 } 119 } {4 10} 120 do_test wal2-1.1 { 121 execsql { SELECT count(a), sum(a) FROM t1 } db2 122 } {4 10} 123 124 set RECOVER [list \ 125 {0 1 lock exclusive} {1 2 lock exclusive} \ 126 {4 1 lock exclusive} {4 1 unlock exclusive} \ 127 {5 1 lock exclusive} {5 1 unlock exclusive} \ 128 {6 1 lock exclusive} {6 1 unlock exclusive} \ 129 {7 1 lock exclusive} {7 1 unlock exclusive} \ 130 {1 2 unlock exclusive} {0 1 unlock exclusive} \ 131 ] 132 set READ [list \ 133 {4 1 lock shared} {4 1 unlock shared} \ 134 ] 135 set INITSLOT [list \ 136 {4 1 lock exclusive} {4 1 unlock exclusive} \ 137 ] 138 139 foreach {tn iInsert res wal_index_hdr_mod wal_locks} " 140 2 5 {5 15} 0 {$RECOVER $READ} 141 3 6 {6 21} 1 {$RECOVER $READ} 142 4 7 {7 28} 2 {$RECOVER $READ} 143 5 8 {8 36} 3 {$RECOVER $READ} 144 6 9 {9 45} 4 {$RECOVER $READ} 145 7 10 {10 55} 5 {$RECOVER $READ} 146 8 11 {11 66} 6 {$RECOVER $READ} 147 9 12 {12 78} 7 {$RECOVER $READ} 148 10 13 {13 91} 8 {$RECOVER $READ} 149 11 14 {14 105} 9 {$RECOVER $READ} 150 12 15 {15 120} -1 {$INITSLOT $READ} 151 " { 152 153 do_test wal2-1.$tn.1 { 154 execsql { INSERT INTO t1 VALUES($iInsert) } 155 set ::locks [list] 156 proc tvfs_cb {method args} { 157 lappend ::locks [lindex $args 2] 158 return SQLITE_OK 159 } 160 tvfs filter xShmLock 161 if {$::wal_index_hdr_mod >= 0} { 162 incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1 163 } 164 execsql { SELECT count(a), sum(a) FROM t1 } db2 165 } $res 166 167 do_test wal2-1.$tn.2 { 168 set ::locks 169 } $wal_locks 170 } 171 db close 172 db2 close 173 tvfs delete 174 forcedelete test.db test.db-wal test.db-journal 175 176 #------------------------------------------------------------------------- 177 # This test case is very similar to the previous one, except, after 178 # the reader reads the corrupt wal-index header, but before it has 179 # a chance to re-read it under the cover of the RECOVER lock, the 180 # wal-index header is replaced with a valid, but out-of-date, header. 181 # 182 # Because the header checksum looks Ok, the reader does not run recovery, 183 # it simply drops back to a READ lock and proceeds. But because the 184 # header is out-of-date, the reader reads the out-of-date snapshot. 185 # 186 # After this, the header is corrupted again and the reader is allowed 187 # to run recovery. This time, it sees an up-to-date snapshot of the 188 # database file. 189 # 190 set WRITER [list 0 1 lock exclusive] 191 set LOCKS [list \ 192 {0 1 lock exclusive} {0 1 unlock exclusive} \ 193 {4 1 lock exclusive} {4 1 unlock exclusive} \ 194 {4 1 lock shared} {4 1 unlock shared} \ 195 ] 196 do_test wal2-2.0 { 197 198 testvfs tvfs 199 tvfs script tvfs_cb 200 tvfs filter xShmOpen 201 proc tvfs_cb {method args} { 202 set ::filename [lindex $args 0] 203 return SQLITE_OK 204 } 205 206 sqlite3 db test.db -vfs tvfs 207 sqlite3 db2 test.db -vfs tvfs 208 209 execsql { 210 PRAGMA journal_mode = WAL; 211 CREATE TABLE t1(a); 212 } db2 213 execsql { 214 INSERT INTO t1 VALUES(1); 215 INSERT INTO t1 VALUES(2); 216 INSERT INTO t1 VALUES(3); 217 INSERT INTO t1 VALUES(4); 218 SELECT count(a), sum(a) FROM t1; 219 } 220 } {4 10} 221 do_test wal2-2.1 { 222 execsql { SELECT count(a), sum(a) FROM t1 } db2 223 } {4 10} 224 225 foreach {tn iInsert res0 res1 wal_index_hdr_mod} { 226 2 5 {4 10} {5 15} 0 227 3 6 {5 15} {6 21} 1 228 4 7 {6 21} {7 28} 2 229 5 8 {7 28} {8 36} 3 230 6 9 {8 36} {9 45} 4 231 7 10 {9 45} {10 55} 5 232 8 11 {10 55} {11 66} 6 233 9 12 {11 66} {12 78} 7 234 } { 235 tvfs filter xShmLock 236 237 do_test wal2-2.$tn.1 { 238 set oldhdr [set_tvfs_hdr $::filename] 239 execsql { INSERT INTO t1 VALUES($iInsert) } 240 execsql { SELECT count(a), sum(a) FROM t1 } 241 } $res1 242 243 do_test wal2-2.$tn.2 { 244 set ::locks [list] 245 proc tvfs_cb {method args} { 246 set lock [lindex $args 2] 247 lappend ::locks $lock 248 if {$lock == $::WRITER} { 249 set_tvfs_hdr $::filename $::oldhdr 250 } 251 return SQLITE_OK 252 } 253 254 if {$::wal_index_hdr_mod >= 0} { 255 incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1 256 } 257 execsql { SELECT count(a), sum(a) FROM t1 } db2 258 } $res0 259 260 do_test wal2-2.$tn.3 { 261 set ::locks 262 } $LOCKS 263 264 do_test wal2-2.$tn.4 { 265 set ::locks [list] 266 proc tvfs_cb {method args} { 267 set lock [lindex $args 2] 268 lappend ::locks $lock 269 return SQLITE_OK 270 } 271 272 if {$::wal_index_hdr_mod >= 0} { 273 incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1 274 } 275 execsql { SELECT count(a), sum(a) FROM t1 } db2 276 } $res1 277 } 278 db close 279 db2 close 280 tvfs delete 281 forcedelete test.db test.db-wal test.db-journal 282 283 284 if 0 { 285 #------------------------------------------------------------------------- 286 # This test case - wal2-3.* - tests the response of the library to an 287 # SQLITE_BUSY when attempting to obtain a READ or RECOVER lock. 288 # 289 # wal2-3.0 - 2: SQLITE_BUSY when obtaining a READ lock 290 # wal2-3.3 - 6: SQLITE_BUSY when obtaining a RECOVER lock 291 # 292 do_test wal2-3.0 { 293 proc tvfs_cb {method args} { 294 if {$method == "xShmLock"} { 295 if {[info exists ::locked]} { return SQLITE_BUSY } 296 } 297 return SQLITE_OK 298 } 299 300 proc busyhandler x { 301 if {$x>3} { unset -nocomplain ::locked } 302 return 0 303 } 304 305 testvfs tvfs 306 tvfs script tvfs_cb 307 sqlite3 db test.db -vfs tvfs 308 db busy busyhandler 309 310 execsql { 311 PRAGMA journal_mode = WAL; 312 CREATE TABLE t1(a); 313 INSERT INTO t1 VALUES(1); 314 INSERT INTO t1 VALUES(2); 315 INSERT INTO t1 VALUES(3); 316 INSERT INTO t1 VALUES(4); 317 } 318 319 set ::locked 1 320 info exists ::locked 321 } {1} 322 do_test wal2-3.1 { 323 execsql { SELECT count(a), sum(a) FROM t1 } 324 } {4 10} 325 do_test wal2-3.2 { 326 info exists ::locked 327 } {0} 328 329 do_test wal2-3.3 { 330 proc tvfs_cb {method args} { 331 if {$method == "xShmLock"} { 332 if {[info exists ::sabotage]} { 333 unset -nocomplain ::sabotage 334 incr_tvfs_hdr [lindex $args 0] 1 1 335 } 336 if {[info exists ::locked] && [lindex $args 2] == "RECOVER"} { 337 return SQLITE_BUSY 338 } 339 } 340 return SQLITE_OK 341 } 342 set ::sabotage 1 343 set ::locked 1 344 list [info exists ::sabotage] [info exists ::locked] 345 } {1 1} 346 do_test wal2-3.4 { 347 execsql { SELECT count(a), sum(a) FROM t1 } 348 } {4 10} 349 do_test wal2-3.5 { 350 list [info exists ::sabotage] [info exists ::locked] 351 } {0 0} 352 db close 353 tvfs delete 354 forcedelete test.db test.db-wal test.db-journal 355 356 } 357 358 #------------------------------------------------------------------------- 359 # Test that a database connection using a VFS that does not support the 360 # xShmXXX interfaces cannot open a WAL database. 361 # 362 do_test wal2-4.1 { 363 sqlite3 db test.db 364 execsql { 365 PRAGMA auto_vacuum = 0; 366 PRAGMA journal_mode = WAL; 367 CREATE TABLE data(x); 368 INSERT INTO data VALUES('need xShmOpen to see this'); 369 PRAGMA wal_checkpoint; 370 } 371 # Three pages in the WAL file at this point: One copy of page 1 and two 372 # of the root page for table "data". 373 } {wal 0 3 3} 374 do_test wal2-4.2 { 375 db close 376 testvfs tvfs -noshm 1 377 sqlite3 db test.db -vfs tvfs 378 catchsql { SELECT * FROM data } 379 } {1 {unable to open database file}} 380 do_test wal2-4.3 { 381 db close 382 testvfs tvfs 383 sqlite3 db test.db -vfs tvfs 384 catchsql { SELECT * FROM data } 385 } {0 {{need xShmOpen to see this}}} 386 db close 387 tvfs delete 388 389 #------------------------------------------------------------------------- 390 # Test that if a database connection is forced to run recovery before it 391 # can perform a checkpoint, it does not transition into RECOVER state. 392 # 393 # UPDATE: This has now changed. When running a checkpoint, if recovery is 394 # required the client grabs all exclusive locks (just as it would for a 395 # recovery performed as a pre-cursor to a normal database transaction). 396 # 397 set expected_locks [list] 398 lappend expected_locks {1 1 lock exclusive} ;# Lock checkpoint 399 lappend expected_locks {0 1 lock exclusive} ;# Lock writer 400 lappend expected_locks {2 1 lock exclusive} ;# Lock recovery 401 # lappend expected_locks {4 4 lock exclusive} ;# Lock all aReadMark[] 402 lappend expected_locks {4 1 lock exclusive} ;# Lock aReadMark[1] 403 lappend expected_locks {4 1 unlock exclusive} ;# Unlock aReadMark[1] 404 lappend expected_locks {5 1 lock exclusive} 405 lappend expected_locks {5 1 unlock exclusive} 406 lappend expected_locks {6 1 lock exclusive} 407 lappend expected_locks {6 1 unlock exclusive} 408 lappend expected_locks {7 1 lock exclusive} 409 lappend expected_locks {7 1 unlock exclusive} 410 lappend expected_locks {2 1 unlock exclusive} ;# Unlock recovery 411 # lappend expected_locks {4 4 unlock exclusive} ;# Unlock all aReadMark[] 412 lappend expected_locks {0 1 unlock exclusive} ;# Unlock writer 413 lappend expected_locks {3 1 lock exclusive} ;# Lock aReadMark[0] 414 lappend expected_locks {3 1 unlock exclusive} ;# Unlock aReadMark[0] 415 lappend expected_locks {1 1 unlock exclusive} ;# Unlock checkpoint 416 do_test wal2-5.1 { 417 proc tvfs_cb {method args} { 418 set ::shm_file [lindex $args 0] 419 if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] } 420 return $::tvfs_cb_return 421 } 422 set tvfs_cb_return SQLITE_OK 423 424 testvfs tvfs 425 tvfs script tvfs_cb 426 427 sqlite3 db test.db -vfs tvfs 428 execsql { 429 PRAGMA journal_mode = WAL; 430 CREATE TABLE x(y); 431 INSERT INTO x VALUES(1); 432 } 433 434 incr_tvfs_hdr $::shm_file 1 1 435 set ::locks [list] 436 execsql { PRAGMA wal_checkpoint } 437 set ::locks 438 } $expected_locks 439 db close 440 tvfs delete 441 442 #------------------------------------------------------------------------- 443 # This block, test cases wal2-6.*, tests the operation of WAL with 444 # "PRAGMA locking_mode=EXCLUSIVE" set. 445 # 446 # wal2-6.1.*: Changing to WAL mode before setting locking_mode=exclusive. 447 # 448 # wal2-6.2.*: Changing to WAL mode after setting locking_mode=exclusive. 449 # 450 # wal2-6.3.*: Changing back to rollback mode from WAL mode after setting 451 # locking_mode=exclusive. 452 # 453 # wal2-6.4.*: Check that xShmLock calls are omitted in exclusive locking 454 # mode. 455 # 456 # wal2-6.5.*: 457 # 458 # wal2-6.6.*: Check that if the xShmLock() to reaquire a WAL read-lock when 459 # exiting exclusive mode fails (i.e. SQLITE_IOERR), then the 460 # connection silently remains in exclusive mode. 461 # 462 do_test wal2-6.1.1 { 463 forcedelete test.db test.db-wal test.db-journal 464 sqlite3 db test.db 465 execsql { 466 Pragma Journal_Mode = Wal; 467 } 468 } {wal} 469 do_test wal2-6.1.2 { 470 execsql { PRAGMA lock_status } 471 } {main unlocked temp closed} 472 do_test wal2-6.1.3 { 473 execsql { 474 SELECT * FROM sqlite_master; 475 Pragma Locking_Mode = Exclusive; 476 } 477 execsql { 478 BEGIN; 479 CREATE TABLE t1(a, b); 480 INSERT INTO t1 VALUES(1, 2); 481 COMMIT; 482 PRAGMA lock_status; 483 } 484 } {main exclusive temp closed} 485 do_test wal2-6.1.4 { 486 execsql { 487 PRAGMA locking_mode = normal; 488 PRAGMA lock_status; 489 } 490 } {normal main exclusive temp closed} 491 do_test wal2-6.1.5 { 492 execsql { 493 SELECT * FROM t1; 494 PRAGMA lock_status; 495 } 496 } {1 2 main shared temp closed} 497 do_test wal2-6.1.6 { 498 execsql { 499 INSERT INTO t1 VALUES(3, 4); 500 PRAGMA lock_status; 501 } 502 } {main shared temp closed} 503 db close 504 505 do_test wal2-6.2.1 { 506 forcedelete test.db test.db-wal test.db-journal 507 sqlite3 db test.db 508 execsql { 509 Pragma Locking_Mode = Exclusive; 510 Pragma Journal_Mode = Wal; 511 Pragma Lock_Status; 512 } 513 } {exclusive wal main exclusive temp closed} 514 do_test wal2-6.2.2 { 515 execsql { 516 BEGIN; 517 CREATE TABLE t1(a, b); 518 INSERT INTO t1 VALUES(1, 2); 519 COMMIT; 520 Pragma loCK_STATus; 521 } 522 } {main exclusive temp closed} 523 do_test wal2-6.2.3 { 524 db close 525 sqlite3 db test.db 526 execsql { SELECT * FROM sqlite_master } 527 execsql { PRAGMA LOCKING_MODE = EXCLUSIVE } 528 } {exclusive} 529 do_test wal2-6.2.4 { 530 execsql { 531 SELECT * FROM t1; 532 pragma lock_status; 533 } 534 } {1 2 main shared temp closed} 535 do_test wal2-6.2.5 { 536 execsql { 537 INSERT INTO t1 VALUES(3, 4); 538 pragma lock_status; 539 } 540 } {main exclusive temp closed} 541 do_test wal2-6.2.6 { 542 execsql { 543 PRAGMA locking_mode = NORMAL; 544 pragma lock_status; 545 } 546 } {normal main exclusive temp closed} 547 do_test wal2-6.2.7 { 548 execsql { 549 BEGIN IMMEDIATE; COMMIT; 550 pragma lock_status; 551 } 552 } {main shared temp closed} 553 do_test wal2-6.2.8 { 554 execsql { 555 PRAGMA locking_mode = EXCLUSIVE; 556 BEGIN IMMEDIATE; COMMIT; 557 PRAGMA locking_mode = NORMAL; 558 } 559 execsql { 560 SELECT * FROM t1; 561 pragma lock_status; 562 } 563 } {1 2 3 4 main shared temp closed} 564 do_test wal2-6.2.9 { 565 execsql { 566 INSERT INTO t1 VALUES(5, 6); 567 SELECT * FROM t1; 568 pragma lock_status; 569 } 570 } {1 2 3 4 5 6 main shared temp closed} 571 db close 572 573 do_test wal2-6.3.1 { 574 forcedelete test.db test.db-wal test.db-journal 575 sqlite3 db test.db 576 execsql { 577 PRAGMA journal_mode = WAL; 578 PRAGMA locking_mode = exclusive; 579 BEGIN; 580 CREATE TABLE t1(x); 581 INSERT INTO t1 VALUES('Chico'); 582 INSERT INTO t1 VALUES('Harpo'); 583 COMMIT; 584 } 585 list [file exists test.db-wal] [file exists test.db-journal] 586 } {1 0} 587 do_test wal2-6.3.2 { 588 execsql { PRAGMA journal_mode = DELETE } 589 file exists test.db-wal 590 } {0} 591 do_test wal2-6.3.3 { 592 execsql { PRAGMA lock_status } 593 } {main exclusive temp closed} 594 do_test wal2-6.3.4 { 595 execsql { 596 BEGIN; 597 INSERT INTO t1 VALUES('Groucho'); 598 } 599 } {} 600 if {[atomic_batch_write test.db]==0} { 601 do_test wal2-6.3.4.1 { 602 list [file exists test.db-wal] [file exists test.db-journal] 603 } {0 1} 604 } 605 do_test wal2-6.3.5 { 606 execsql { PRAGMA lock_status } 607 } {main exclusive temp closed} 608 do_test wal2-6.3.6 { 609 execsql { COMMIT } 610 } {} 611 if {[atomic_batch_write test.db]==0} { 612 do_test wal2-6.3.6.1 { 613 list [file exists test.db-wal] [file exists test.db-journal] 614 } {0 1} 615 } 616 do_test wal2-6.3.7 { 617 execsql { PRAGMA lock_status } 618 } {main exclusive temp closed} 619 db close 620 621 622 # This test - wal2-6.4.* - uses a single database connection and the 623 # [testvfs] instrumentation to test that xShmLock() is being called 624 # as expected when a WAL database is used with locking_mode=exclusive. 625 # 626 do_test wal2-6.4.1 { 627 forcedelete test.db test.db-wal test.db-journal 628 proc tvfs_cb {method args} { 629 set ::shm_file [lindex $args 0] 630 if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] } 631 return "SQLITE_OK" 632 } 633 testvfs tvfs 634 tvfs script tvfs_cb 635 sqlite3 db test.db -vfs tvfs 636 set {} {} 637 } {} 638 639 set RECOVERY { 640 {0 1 lock exclusive} {1 2 lock exclusive} 641 {4 1 lock exclusive} {4 1 unlock exclusive} 642 {5 1 lock exclusive} {5 1 unlock exclusive} 643 {6 1 lock exclusive} {6 1 unlock exclusive} 644 {7 1 lock exclusive} {7 1 unlock exclusive} 645 {1 2 unlock exclusive} {0 1 unlock exclusive} 646 } 647 set READMARK0_READ { 648 {3 1 lock shared} {3 1 unlock shared} 649 } 650 set READMARK0_WRITE { 651 {3 1 lock shared} 652 {0 1 lock exclusive} {3 1 unlock shared} 653 {4 1 lock exclusive} {4 1 unlock exclusive} {4 1 lock shared} 654 {0 1 unlock exclusive} {4 1 unlock shared} 655 } 656 set READMARK1_SET { 657 {4 1 lock exclusive} {4 1 unlock exclusive} 658 } 659 set READMARK1_READ { 660 {4 1 lock shared} {4 1 unlock shared} 661 } 662 set READMARK1_WRITE { 663 {4 1 lock shared} 664 {0 1 lock exclusive} {0 1 unlock exclusive} 665 {4 1 unlock shared} 666 } 667 668 foreach {tn sql res expected_locks} { 669 2 { 670 PRAGMA auto_vacuum = 0; 671 PRAGMA journal_mode = WAL; 672 BEGIN; 673 CREATE TABLE t1(x); 674 INSERT INTO t1 VALUES('Leonard'); 675 INSERT INTO t1 VALUES('Arthur'); 676 COMMIT; 677 } {wal} { 678 $RECOVERY 679 $READMARK0_WRITE 680 } 681 682 3 { 683 # This test should do the READMARK1_SET locking to populate the 684 # aReadMark[1] slot with the current mxFrame value. Followed by 685 # READMARK1_READ to read the database. 686 # 687 SELECT * FROM t1 688 } {Leonard Arthur} { 689 $READMARK1_SET 690 $READMARK1_READ 691 } 692 693 4 { 694 # aReadMark[1] is already set to mxFrame. So just READMARK1_READ 695 # this time, not READMARK1_SET. 696 # 697 SELECT * FROM t1 ORDER BY x 698 } {Arthur Leonard} { 699 $READMARK1_READ 700 } 701 702 5 { 703 PRAGMA locking_mode = exclusive 704 } {exclusive} { } 705 706 6 { 707 INSERT INTO t1 VALUES('Julius Henry'); 708 SELECT * FROM t1; 709 } {Leonard Arthur {Julius Henry}} { 710 $READMARK1_READ 711 } 712 713 7 { 714 INSERT INTO t1 VALUES('Karl'); 715 SELECT * FROM t1; 716 } {Leonard Arthur {Julius Henry} Karl} { } 717 718 8 { 719 PRAGMA locking_mode = normal 720 } {normal} { } 721 722 9 { 723 SELECT * FROM t1 ORDER BY x 724 } {Arthur {Julius Henry} Karl Leonard} $READMARK1_READ 725 726 10 { DELETE FROM t1 } {} $READMARK1_WRITE 727 728 11 { 729 SELECT * FROM t1 730 } {} { 731 $READMARK1_SET 732 $READMARK1_READ 733 } 734 } { 735 736 set L [list] 737 foreach el [subst $expected_locks] { lappend L $el } 738 739 set S "" 740 foreach sq [split $sql "\n"] { 741 set sq [string trim $sq] 742 if {[string match {#*} $sq]==0} {append S "$sq\n"} 743 } 744 745 set ::locks [list] 746 do_test wal2-6.4.$tn.1 { execsql $S } $res 747 do_test wal2-6.4.$tn.2 { set ::locks } $L 748 } 749 750 db close 751 tvfs delete 752 753 do_test wal2-6.5.1 { 754 sqlite3 db test.db 755 execsql { 756 PRAGMA auto_vacuum = 0; 757 PRAGMA journal_mode = wal; 758 PRAGMA locking_mode = exclusive; 759 CREATE TABLE t2(a, b); 760 PRAGMA wal_checkpoint; 761 INSERT INTO t2 VALUES('I', 'II'); 762 PRAGMA journal_mode; 763 } 764 } {wal exclusive 0 2 2 wal} 765 do_test wal2-6.5.2 { 766 execsql { 767 PRAGMA locking_mode = normal; 768 INSERT INTO t2 VALUES('III', 'IV'); 769 PRAGMA locking_mode = exclusive; 770 SELECT * FROM t2; 771 } 772 } {normal exclusive I II III IV} 773 do_test wal2-6.5.3 { 774 execsql { PRAGMA wal_checkpoint } 775 } {0 2 2} 776 db close 777 778 proc lock_control {method filename handle spec} { 779 foreach {start n op type} $spec break 780 if {$op == "lock"} { return SQLITE_IOERR } 781 return SQLITE_OK 782 } 783 do_test wal2-6.6.1 { 784 testvfs T 785 T script lock_control 786 T filter {} 787 sqlite3 db test.db -vfs T 788 execsql { SELECT * FROM sqlite_master } 789 execsql { PRAGMA locking_mode = exclusive } 790 execsql { INSERT INTO t2 VALUES('V', 'VI') } 791 } {} 792 do_test wal2-6.6.2 { 793 execsql { PRAGMA locking_mode = normal } 794 T filter xShmLock 795 execsql { INSERT INTO t2 VALUES('VII', 'VIII') } 796 } {} 797 do_test wal2-6.6.3 { 798 # At this point the connection should still be in exclusive-mode, even 799 # though it tried to exit exclusive-mode when committing the INSERT 800 # statement above. To exit exclusive mode, SQLite has to take a read-lock 801 # on the WAL file using xShmLock(). Since that call failed, it remains 802 # in exclusive mode. 803 # 804 sqlite3 db2 test.db -vfs T 805 catchsql { SELECT * FROM t2 } db2 806 } {1 {database is locked}} 807 do_test wal2-6.6.2 { 808 db2 close 809 T filter {} 810 execsql { INSERT INTO t2 VALUES('IX', 'X') } 811 } {} 812 do_test wal2-6.6.4 { 813 # This time, we have successfully exited exclusive mode. So the second 814 # connection can read the database. 815 sqlite3 db2 test.db -vfs T 816 catchsql { SELECT * FROM t2 } db2 817 } {0 {I II III IV V VI VII VIII IX X}} 818 819 db close 820 db2 close 821 T delete 822 823 #------------------------------------------------------------------------- 824 # Test a theory about the checksum algorithm. Theory was false and this 825 # test did not provoke a bug. 826 # 827 forcedelete test.db test.db-wal test.db-journal 828 do_test wal2-7.1.1 { 829 sqlite3 db test.db 830 execsql { 831 PRAGMA page_size = 4096; 832 PRAGMA journal_mode = WAL; 833 CREATE TABLE t1(a, b); 834 } 835 file size test.db 836 } {4096} 837 do_test wal2-7.1.2 { 838 forcecopy test.db test2.db 839 forcecopy test.db-wal test2.db-wal 840 # The first 32 bytes of the WAL file contain the WAL header. Offset 48 841 # is the first byte of the checksum for the first frame in the WAL. 842 # The following three lines replaces the contents of that byte with 843 # a different value. 844 set newval FF 845 if {$newval == [hexio_read test2.db-wal 48 1]} { set newval 00 } 846 hexio_write test2.db-wal 48 $newval 847 } {1} 848 do_test wal2-7.1.3 { 849 sqlite3 db2 test2.db 850 execsql { PRAGMA wal_checkpoint } db2 851 execsql { SELECT * FROM sqlite_master } db2 852 } {} 853 db close 854 db2 close 855 forcedelete test.db test.db-wal test.db-journal 856 do_test wal2-8.1.2 { 857 sqlite3 db test.db 858 execsql { 859 PRAGMA auto_vacuum=OFF; 860 PRAGMA page_size = 1024; 861 PRAGMA journal_mode = WAL; 862 CREATE TABLE t1(x); 863 INSERT INTO t1 VALUES(zeroblob(8188*1020)); 864 CREATE TABLE t2(y); 865 PRAGMA wal_checkpoint; 866 } 867 execsql { 868 SELECT rootpage>=8192 FROM sqlite_master WHERE tbl_name = 't2'; 869 } 870 } {1} 871 do_test wal2-8.1.3 { 872 execsql { 873 PRAGMA cache_size = 10; 874 CREATE TABLE t3(z); 875 BEGIN; 876 INSERT INTO t3 VALUES(randomblob(900)); 877 INSERT INTO t3 SELECT randomblob(900) FROM t3; 878 INSERT INTO t2 VALUES('hello'); 879 INSERT INTO t3 SELECT randomblob(900) FROM t3; 880 INSERT INTO t3 SELECT randomblob(900) FROM t3; 881 INSERT INTO t3 SELECT randomblob(900) FROM t3; 882 INSERT INTO t3 SELECT randomblob(900) FROM t3; 883 INSERT INTO t3 SELECT randomblob(900) FROM t3; 884 INSERT INTO t3 SELECT randomblob(900) FROM t3; 885 ROLLBACK; 886 } 887 execsql { 888 INSERT INTO t2 VALUES('goodbye'); 889 INSERT INTO t3 SELECT randomblob(900) FROM t3; 890 INSERT INTO t3 SELECT randomblob(900) FROM t3; 891 } 892 } {} 893 do_test wal2-8.1.4 { 894 sqlite3 db2 test.db 895 execsql { SELECT * FROM t2 } 896 } {goodbye} 897 db2 close 898 db close 899 900 #------------------------------------------------------------------------- 901 # Test that even if the checksums for both are valid, if the two copies 902 # of the wal-index header in the wal-index do not match, the client 903 # runs (or at least tries to run) database recovery. 904 # 905 # 906 proc get_name {method args} { set ::filename [lindex $args 0] ; tvfs filter {} } 907 testvfs tvfs 908 tvfs script get_name 909 tvfs filter xShmOpen 910 911 forcedelete test.db test.db-wal test.db-journal 912 do_test wal2-9.1 { 913 sqlite3 db test.db -vfs tvfs 914 execsql { 915 PRAGMA journal_mode = WAL; 916 CREATE TABLE x(y); 917 INSERT INTO x VALUES('Barton'); 918 INSERT INTO x VALUES('Deakin'); 919 } 920 921 # Set $wih(1) to the contents of the wal-index header after 922 # the frames associated with the first two rows in table 'x' have 923 # been inserted. Then insert one more row and set $wih(2) 924 # to the new value of the wal-index header. 925 # 926 # If the $wih(1) is written into the wal-index before running 927 # a read operation, the client will see only the first two rows. If 928 # $wih(2) is written into the wal-index, the client will see 929 # three rows. If an invalid header is written into the wal-index, then 930 # the client will run recovery and see three rows. 931 # 932 set wih(1) [set_tvfs_hdr $::filename] 933 execsql { INSERT INTO x VALUES('Watson') } 934 set wih(2) [set_tvfs_hdr $::filename] 935 936 sqlite3 db2 test.db -vfs tvfs 937 execsql { SELECT * FROM x } db2 938 } {Barton Deakin Watson} 939 940 foreach {tn hdr1 hdr2 res} [list \ 941 3 $wih(1) $wih(1) {Barton Deakin} \ 942 4 $wih(1) $wih(2) {Barton Deakin Watson} \ 943 5 $wih(2) $wih(1) {Barton Deakin Watson} \ 944 6 $wih(2) $wih(2) {Barton Deakin Watson} \ 945 7 $wih(1) $wih(1) {Barton Deakin} \ 946 8 {0 0 0 0 0 0 0 0 0 0 0 0} {0 0 0 0 0 0 0 0 0 0 0 0} {Barton Deakin Watson} 947 ] { 948 do_test wal2-9.$tn { 949 set_tvfs_hdr $::filename $hdr1 $hdr2 950 execsql { SELECT * FROM x } db2 951 } $res 952 } 953 954 db2 close 955 db close 956 957 #------------------------------------------------------------------------- 958 # This block of tests - wal2-10.* - focus on the libraries response to 959 # new versions of the wal or wal-index formats. 960 # 961 # wal2-10.1.*: Test that the library refuses to "recover" a new WAL 962 # format. 963 # 964 # wal2-10.2.*: Test that the library refuses to read or write a database 965 # if the wal-index version is newer than it understands. 966 # 967 # At time of writing, the only versions of the wal and wal-index formats 968 # that exist are versions 3007000 (corresponding to SQLite version 3.7.0, 969 # the first version of SQLite to feature wal mode). 970 # 971 do_test wal2-10.1.1 { 972 faultsim_delete_and_reopen 973 execsql { 974 PRAGMA journal_mode = WAL; 975 CREATE TABLE t1(a, b); 976 PRAGMA wal_checkpoint; 977 INSERT INTO t1 VALUES(1, 2); 978 INSERT INTO t1 VALUES(3, 4); 979 } 980 faultsim_save_and_close 981 } {} 982 do_test wal2-10.1.2 { 983 faultsim_restore_and_reopen 984 execsql { SELECT * FROM t1 } 985 } {1 2 3 4} 986 do_test wal2-10.1.3 { 987 faultsim_restore_and_reopen 988 set hdr [wal_set_walhdr test.db-wal] 989 lindex $hdr 1 990 } {3007000} 991 do_test wal2-10.1.4 { 992 lset hdr 1 3007001 993 wal_set_walhdr test.db-wal $hdr 994 catchsql { SELECT * FROM t1 } 995 } {1 {unable to open database file}} 996 997 testvfs tvfs -default 1 998 do_test wal2-10.2.1 { 999 faultsim_restore_and_reopen 1000 execsql { SELECT * FROM t1 } 1001 } {1 2 3 4} 1002 do_test wal2-10.2.2 { 1003 set hdr [set_tvfs_hdr $::filename] 1004 lindex $hdr 0 1005 } {3007000} 1006 do_test wal2-10.2.3 { 1007 lset hdr 0 3007001 1008 wal_fix_walindex_cksum hdr 1009 set_tvfs_hdr $::filename $hdr 1010 catchsql { SELECT * FROM t1 } 1011 } {1 {unable to open database file}} 1012 db close 1013 tvfs delete 1014 1015 #------------------------------------------------------------------------- 1016 # This block of tests - wal2-11.* - tests that it is not possible to put 1017 # the library into an infinite loop by presenting it with a corrupt 1018 # hash table (one that appears to contain a single chain of infinite 1019 # length). 1020 # 1021 # wal2-11.1.*: While reading the hash-table. 1022 # 1023 # wal2-11.2.*: While writing the hash-table. 1024 # 1025 testvfs tvfs -default 1 1026 do_test wal2-11.0 { 1027 faultsim_delete_and_reopen 1028 execsql { 1029 PRAGMA journal_mode = WAL; 1030 CREATE TABLE t1(a, b, c); 1031 INSERT INTO t1 VALUES(1, 2, 3); 1032 INSERT INTO t1 VALUES(4, 5, 6); 1033 INSERT INTO t1 VALUES(7, 8, 9); 1034 SELECT * FROM t1; 1035 } 1036 } {wal 1 2 3 4 5 6 7 8 9} 1037 1038 do_test wal2-11.1.1 { 1039 sqlite3 db2 test.db 1040 execsql { SELECT name FROM sqlite_master } db2 1041 } {t1} 1042 1043 if {$::tcl_version>=8.5} { 1044 # Set all zeroed slots in the first hash table to invalid values. 1045 # 1046 set blob [string range [tvfs shm $::filename] 0 16383] 1047 set I [string range [tvfs shm $::filename] 16384 end] 1048 binary scan $I t* L 1049 set I [list] 1050 foreach p $L { 1051 lappend I [expr $p ? $p : 400] 1052 } 1053 append blob [binary format t* $I] 1054 tvfs shm $::filename $blob 1055 do_test wal2-11.2 { 1056 catchsql { INSERT INTO t1 VALUES(10, 11, 12) } 1057 } {1 {database disk image is malformed}} 1058 1059 # Fill up the hash table on the first page of shared memory with 0x55 bytes. 1060 # 1061 set blob [string range [tvfs shm $::filename] 0 16383] 1062 append blob [string repeat [binary format c 55] 16384] 1063 tvfs shm $::filename $blob 1064 do_test wal2-11.3 { 1065 catchsql { SELECT * FROM t1 } db2 1066 } {1 {database disk image is malformed}} 1067 } 1068 1069 db close 1070 db2 close 1071 tvfs delete 1072 1073 #------------------------------------------------------------------------- 1074 # If a connection is required to create a WAL or SHM file, it creates 1075 # the new files with the same file-system permissions as the database 1076 # file itself. Test this. 1077 # 1078 if {$::tcl_platform(platform) == "unix"} { 1079 faultsim_delete_and_reopen 1080 # Changed on 2012-02-13: umask is deliberately ignored for -wal files. 1081 #set umask [exec /bin/sh -c umask] 1082 set umask 0 1083 1084 1085 do_test wal2-12.1 { 1086 sqlite3 db test.db 1087 execsql { 1088 CREATE TABLE tx(y, z); 1089 PRAGMA journal_mode = WAL; 1090 } 1091 db close 1092 list [file exists test.db-wal] [file exists test.db-shm] 1093 } {0 0} 1094 1095 foreach {tn permissions} { 1096 1 00644 1097 2 00666 1098 3 00600 1099 4 00755 1100 } { 1101 set effective [format %.5o [expr $permissions & ~$umask]] 1102 do_test wal2-12.2.$tn.1 { 1103 file attributes test.db -permissions $permissions 1104 string map {o 0} [file attributes test.db -permissions] 1105 } $permissions 1106 do_test wal2-12.2.$tn.2 { 1107 list [file exists test.db-wal] [file exists test.db-shm] 1108 } {0 0} 1109 do_test wal2-12.2.$tn.3 { 1110 sqlite3 db test.db 1111 execsql { INSERT INTO tx DEFAULT VALUES } 1112 list [file exists test.db-wal] [file exists test.db-shm] 1113 } {1 1} 1114 do_test wal2-12.2.$tn.4 { 1115 set x [list [file attr test.db-wal -perm] [file attr test.db-shm -perm]] 1116 string map {o 0} $x 1117 } [list $effective $effective] 1118 do_test wal2-12.2.$tn.5 { 1119 db close 1120 list [file exists test.db-wal] [file exists test.db-shm] 1121 } {0 0} 1122 } 1123 } 1124 1125 #------------------------------------------------------------------------- 1126 # Test the libraries response to discovering that one or more of the 1127 # database, wal or shm files cannot be opened, or can only be opened 1128 # read-only. 1129 # 1130 if {$::tcl_platform(platform) == "unix"} { 1131 proc perm {} { 1132 set L [list] 1133 foreach f {test.db test.db-wal test.db-shm} { 1134 if {[file exists $f]} { 1135 lappend L [file attr $f -perm] 1136 } else { 1137 lappend L {} 1138 } 1139 } 1140 set L 1141 } 1142 1143 faultsim_delete_and_reopen 1144 execsql { 1145 PRAGMA journal_mode = WAL; 1146 CREATE TABLE t1(a, b); 1147 PRAGMA wal_checkpoint; 1148 INSERT INTO t1 VALUES('3.14', '2.72'); 1149 } 1150 do_test wal2-13.1.1 { 1151 list [file exists test.db-shm] [file exists test.db-wal] 1152 } {1 1} 1153 faultsim_save_and_close 1154 1155 foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} { 1156 2 00644 00644 00644 1 1 1 1157 3 00644 00400 00644 1 1 0 1158 4 00644 00644 00400 1 1 0 1159 5 00400 00644 00644 1 1 0 1160 1161 7 00644 00000 00644 1 0 0 1162 8 00644 00644 00000 1 0 0 1163 9 00000 00644 00644 0 0 0 1164 } { 1165 faultsim_restore 1166 do_test wal2-13.$tn.1 { 1167 file attr test.db -perm $db_perm 1168 file attr test.db-wal -perm $wal_perm 1169 file attr test.db-shm -perm $shm_perm 1170 1171 set L [file attr test.db -perm] 1172 lappend L [file attr test.db-wal -perm] 1173 lappend L [file attr test.db-shm -perm] 1174 string map {o 0} $L 1175 } [list $db_perm $wal_perm $shm_perm] 1176 1177 # If $can_open is true, then it should be possible to open a database 1178 # handle. Otherwise, if $can_open is 0, attempting to open the db 1179 # handle throws an "unable to open database file" exception. 1180 # 1181 set r(1) {0 ok} 1182 set r(0) {1 {unable to open database file}} 1183 do_test wal2-13.$tn.2 { 1184 list [catch {sqlite3 db test.db ; set {} ok} msg] $msg 1185 } $r($can_open) 1186 1187 if {$can_open} { 1188 1189 # If $can_read is true, then the client should be able to read from 1190 # the database file. If $can_read is false, attempting to read should 1191 # throw the "unable to open database file" exception. 1192 # 1193 set a(0) {1 {unable to open database file}} 1194 set a(1) {0 {3.14 2.72}} 1195 do_test wal2-13.$tn.3 { 1196 catchsql { SELECT * FROM t1 } 1197 } $a($can_read) 1198 1199 # Now try to write to the db file. If the client can read but not 1200 # write, then it should throw the familiar "unable to open db file" 1201 # exception. If it can read but not write, the exception should 1202 # be "attempt to write a read only database". 1203 # 1204 # If the client can read and write, the operation should succeed. 1205 # 1206 set b(0,0) {1 {unable to open database file}} 1207 set b(1,0) {1 {attempt to write a readonly database}} 1208 set b(1,1) {0 {}} 1209 do_test wal2-13.$tn.4 { 1210 catchsql { INSERT INTO t1 DEFAULT VALUES } 1211 } $b($can_read,$can_write) 1212 } 1213 catch { db close } 1214 } 1215 } 1216 1217 #------------------------------------------------------------------------- 1218 # Test that "PRAGMA checkpoint_fullsync" appears to be working. 1219 # 1220 foreach {tn sql reslist} { 1221 1 { } {10 0 4 0 6 0} 1222 2 { PRAGMA checkpoint_fullfsync = 1 } {10 6 4 3 6 3} 1223 3 { PRAGMA checkpoint_fullfsync = 0 } {10 0 4 0 6 0} 1224 } { 1225 ifcapable default_ckptfullfsync { 1226 if {[string trim $sql]==""} continue 1227 } 1228 faultsim_delete_and_reopen 1229 1230 execsql {PRAGMA auto_vacuum = 0; PRAGMA synchronous = FULL;} 1231 execsql $sql 1232 do_execsql_test wal2-14.$tn.0 { PRAGMA page_size = 4096 } {} 1233 do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal} 1234 1235 set sqlite_sync_count 0 1236 set sqlite_fullsync_count 0 1237 1238 do_execsql_test wal2-14.$tn.2 { 1239 PRAGMA wal_autocheckpoint = 10; 1240 CREATE TABLE t1(a, b); -- 2 wal syncs 1241 INSERT INTO t1 VALUES(1, 2); -- 2 wal sync 1242 PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync 1243 BEGIN; 1244 INSERT INTO t1 VALUES(3, 4); 1245 INSERT INTO t1 VALUES(5, 6); 1246 COMMIT; -- 2 wal sync 1247 PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync 1248 } {10 0 3 3 0 1 1} 1249 1250 do_test wal2-14.$tn.3 { 1251 cond_incr_sync_count 1 1252 list $sqlite_sync_count $sqlite_fullsync_count 1253 } [lrange $reslist 0 1] 1254 1255 set sqlite_sync_count 0 1256 set sqlite_fullsync_count 0 1257 1258 do_test wal2-14.$tn.4 { 1259 execsql { INSERT INTO t1 VALUES(7, zeroblob(12*4096)) } 1260 list $sqlite_sync_count $sqlite_fullsync_count 1261 } [lrange $reslist 2 3] 1262 1263 set sqlite_sync_count 0 1264 set sqlite_fullsync_count 0 1265 1266 do_test wal2-14.$tn.5 { 1267 execsql { PRAGMA wal_autocheckpoint = 1000 } 1268 execsql { INSERT INTO t1 VALUES(9, 10) } 1269 execsql { INSERT INTO t1 VALUES(11, 12) } 1270 execsql { INSERT INTO t1 VALUES(13, 14) } 1271 db close 1272 list $sqlite_sync_count $sqlite_fullsync_count 1273 } [lrange $reslist 4 5] 1274 } 1275 1276 catch { db close } 1277 1278 # PRAGMA checkpoint_fullsync 1279 # PRAGMA fullfsync 1280 # PRAGMA synchronous 1281 # 1282 foreach {tn settings restart_sync commit_sync ckpt_sync} { 1283 1 {0 0 off} {0 0} {0 0} {0 0} 1284 2 {0 0 normal} {1 0} {0 0} {2 0} 1285 3 {0 0 full} {2 0} {1 0} {2 0} 1286 1287 4 {0 1 off} {0 0} {0 0} {0 0} 1288 5 {0 1 normal} {0 1} {0 0} {0 2} 1289 6 {0 1 full} {0 2} {0 1} {0 2} 1290 1291 7 {1 0 off} {0 0} {0 0} {0 0} 1292 8 {1 0 normal} {0 1} {0 0} {0 2} 1293 9 {1 0 full} {1 1} {1 0} {0 2} 1294 1295 10 {1 1 off} {0 0} {0 0} {0 0} 1296 11 {1 1 normal} {0 1} {0 0} {0 2} 1297 12 {1 1 full} {0 2} {0 1} {0 2} 1298 } { 1299 forcedelete test.db 1300 1301 testvfs tvfs -default 1 1302 tvfs filter xSync 1303 tvfs script xSyncCb 1304 proc xSyncCb {method file fileid flags} { 1305 incr ::sync($flags) 1306 } 1307 1308 sqlite3 db test.db 1309 do_execsql_test 15.$tn.1 " 1310 PRAGMA page_size = 4096; 1311 CREATE TABLE t1(x); 1312 PRAGMA wal_autocheckpoint = OFF; 1313 PRAGMA journal_mode = WAL; 1314 PRAGMA checkpoint_fullfsync = [lindex $settings 0]; 1315 PRAGMA fullfsync = [lindex $settings 1]; 1316 PRAGMA synchronous = [lindex $settings 2]; 1317 " {0 wal} 1318 1319 do_test 15.$tn.2 { 1320 set sync(normal) 0 1321 set sync(full) 0 1322 execsql { INSERT INTO t1 VALUES('abc') } 1323 list $::sync(normal) $::sync(full) 1324 } $restart_sync 1325 1326 do_test 15.$tn.3 { 1327 set sync(normal) 0 1328 set sync(full) 0 1329 execsql { INSERT INTO t1 VALUES('abc') } 1330 list $::sync(normal) $::sync(full) 1331 } $commit_sync 1332 1333 do_test 15.$tn.4 { 1334 set sync(normal) 0 1335 set sync(full) 0 1336 execsql { INSERT INTO t1 VALUES('def') } 1337 list $::sync(normal) $::sync(full) 1338 } $commit_sync 1339 1340 do_test 15.$tn.5 { 1341 set sync(normal) 0 1342 set sync(full) 0 1343 execsql { PRAGMA wal_checkpoint } 1344 list $::sync(normal) $::sync(full) 1345 } $ckpt_sync 1346 1347 db close 1348 tvfs delete 1349 } 1350 1351 1352 1353 finish_test