1# 2010 April 13 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 16set testdir [file dirname $argv0] 17source $testdir/tester.tcl 18source $testdir/lock_common.tcl 19source $testdir/wal_common.tcl 20source $testdir/malloc_common.tcl 21ifcapable !wal {finish_test ; return } 22 23set a_string_counter 1 24proc a_string {n} { 25 global a_string_counter 26 incr a_string_counter 27 string range [string repeat "${a_string_counter}." $n] 1 $n 28} 29db func a_string a_string 30 31#------------------------------------------------------------------------- 32# When a rollback or savepoint rollback occurs, the client may remove 33# elements from one of the hash tables in the wal-index. This block 34# of test cases tests that nothing appears to go wrong when this is 35# done. 36# 37do_test wal3-1.0 { 38 execsql { 39 PRAGMA cache_size = 2000; 40 PRAGMA page_size = 1024; 41 PRAGMA auto_vacuum = off; 42 PRAGMA synchronous = normal; 43 PRAGMA journal_mode = WAL; 44 PRAGMA wal_autocheckpoint = 0; 45 BEGIN; 46 CREATE TABLE t1(x); 47 INSERT INTO t1 VALUES( a_string(800) ); /* 1 */ 48 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */ 49 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */ 50 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */ 51 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */ 52 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */ 53 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 64 */ 54 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 128*/ 55 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 256 */ 56 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 512 */ 57 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 1024 */ 58 INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2048 */ 59 INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 1970; /* 4018 */ 60 COMMIT; 61 PRAGMA cache_size = 10; 62 } 63 wal_frame_count test.db-wal 1024 64} 4056 65 66for {set i 1} {$i < 50} {incr i} { 67 68 do_test wal3-1.$i.1 { 69 set str [a_string 800] 70 execsql { UPDATE t1 SET x = $str WHERE rowid = $i } 71 lappend L [wal_frame_count test.db-wal 1024] 72 execsql { 73 BEGIN; 74 INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 100; 75 ROLLBACK; 76 PRAGMA integrity_check; 77 } 78 } {ok} 79 80 # Check that everything looks OK from the point of view of an 81 # external connection. 82 # 83 sqlite3 db2 test.db 84 do_test wal3-1.$i.2 { 85 execsql { SELECT count(*) FROM t1 } db2 86 } 4018 87 do_test wal3-1.$i.3 { 88 execsql { SELECT x FROM t1 WHERE rowid = $i } 89 } $str 90 do_test wal3-1.$i.4 { 91 execsql { PRAGMA integrity_check } db2 92 } {ok} 93 db2 close 94 95 # Check that the file-system in its current state can be recovered. 96 # 97 file copy -force test.db test2.db 98 file copy -force test.db-wal test2.db-wal 99 file delete -force test2.db-journal 100 sqlite3 db2 test2.db 101 do_test wal3-1.$i.5 { 102 execsql { SELECT count(*) FROM t1 } db2 103 } 4018 104 do_test wal3-1.$i.6 { 105 execsql { SELECT x FROM t1 WHERE rowid = $i } 106 } $str 107 do_test wal3-1.$i.7 { 108 execsql { PRAGMA integrity_check } db2 109 } {ok} 110 db2 close 111} 112 113proc byte_is_zero {file offset} { 114 if {[file size test.db] <= $offset} { return 1 } 115 expr { [hexio_read $file $offset 1] == "00" } 116} 117 118do_multiclient_test i { 119 120 set testname(1) multiproc 121 set testname(2) singleproc 122 set tn $testname($i) 123 124 do_test wal3-2.$tn.1 { 125 sql1 { 126 PRAGMA page_size = 1024; 127 PRAGMA journal_mode = WAL; 128 } 129 sql1 { 130 CREATE TABLE t1(a, b); 131 INSERT INTO t1 VALUES(1, 'one'); 132 BEGIN; 133 SELECT * FROM t1; 134 } 135 } {1 one} 136 do_test wal3-2.$tn.2 { 137 sql2 { 138 CREATE TABLE t2(a, b); 139 INSERT INTO t2 VALUES(2, 'two'); 140 BEGIN; 141 SELECT * FROM t2; 142 } 143 } {2 two} 144 do_test wal3-2.$tn.3 { 145 sql3 { 146 CREATE TABLE t3(a, b); 147 INSERT INTO t3 VALUES(3, 'three'); 148 BEGIN; 149 SELECT * FROM t3; 150 } 151 } {3 three} 152 153 # Try to checkpoint the database using [db]. It should be possible to 154 # checkpoint everything except the table added by [db3] (checkpointing 155 # these frames would clobber the snapshot currently being used by [db2]). 156 # 157 # After [db2] has committed, a checkpoint can copy the entire log to the 158 # database file. Checkpointing after [db3] has committed is therefore a 159 # no-op, as the entire log has already been backfilled. 160 # 161 do_test wal3-2.$tn.4 { 162 sql1 { 163 COMMIT; 164 PRAGMA wal_checkpoint; 165 } 166 byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024] 167 } {1} 168 do_test wal3-2.$tn.5 { 169 sql2 { 170 COMMIT; 171 PRAGMA wal_checkpoint; 172 } 173 list [byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]] \ 174 [byte_is_zero test.db [expr $AUTOVACUUM ? 5*1024 : 4*1024]] 175 } {0 1} 176 do_test wal3-2.$tn.6 { 177 sql3 { 178 COMMIT; 179 PRAGMA wal_checkpoint; 180 } 181 list [byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]] \ 182 [byte_is_zero test.db [expr $AUTOVACUUM ? 5*1024 : 4*1024]] 183 } {0 1} 184} 185catch {db close} 186 187#------------------------------------------------------------------------- 188# Test that that for the simple test: 189# 190# CREATE TABLE x(y); 191# INSERT INTO x VALUES('z'); 192# PRAGMA wal_checkpoint; 193# 194# in WAL mode the xSync method is invoked as expected for each of 195# synchronous=off, synchronous=normal and synchronous=full. 196# 197foreach {tn syncmode synccount} { 198 1 off 199 {} 200 2 normal 201 {test.db-wal normal test.db normal} 202 3 full 203 {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal} 204} { 205 206 proc sync_counter {args} { 207 foreach {method filename id flags} $args break 208 lappend ::syncs [file tail $filename] $flags 209 } 210 do_test wal3-3.$tn { 211 file delete -force test.db test.db-wal test.db-journal 212 213 testvfs T 214 T filter {} 215 T script sync_counter 216 sqlite3 db test.db -vfs T 217 218 execsql "PRAGMA synchronous = $syncmode" 219 execsql { PRAGMA journal_mode = WAL } 220 221 set ::syncs [list] 222 T filter xSync 223 execsql { 224 CREATE TABLE x(y); 225 INSERT INTO x VALUES('z'); 226 PRAGMA wal_checkpoint; 227 } 228 T filter {} 229 set ::syncs 230 } $synccount 231 232 db close 233 T delete 234} 235 236#------------------------------------------------------------------------- 237# When recovering the contents of a WAL file, a process obtains the WRITER 238# lock, then locks all other bytes before commencing recovery. If it fails 239# to lock all other bytes (because some other process is holding a read 240# lock) it should retry up to 100 times. Then return SQLITE_PROTOCOL to the 241# caller. Test this (test case wal3-4.3). 242# 243# Also test the effect of hitting an SQLITE_BUSY while attempting to obtain 244# the WRITER lock (should be the same). Test case wal3-4.4. 245# 246proc lock_callback {method filename handle lock} { 247 lappend ::locks $lock 248} 249do_test wal3-4.1 { 250 testvfs T 251 T filter xShmLock 252 T script lock_callback 253 set ::locks [list] 254 sqlite3 db test.db -vfs T 255 execsql { SELECT * FROM x } 256 lrange $::locks 0 3 257} [list {0 1 lock exclusive} {1 7 lock exclusive} \ 258 {1 7 unlock exclusive} {0 1 unlock exclusive} \ 259] 260do_test wal3-4.2 { 261 db close 262 set ::locks [list] 263 sqlite3 db test.db -vfs T 264 execsql { SELECT * FROM x } 265 lrange $::locks 0 3 266} [list {0 1 lock exclusive} {1 7 lock exclusive} \ 267 {1 7 unlock exclusive} {0 1 unlock exclusive} \ 268] 269proc lock_callback {method filename handle lock} { 270 if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY } 271 return SQLITE_OK 272} 273puts " Warning: This next test case causes SQLite to call xSleep(1) 100 times." 274puts " Normally this equates to a 100ms delay, but if SQLite is built on unix" 275puts " without HAVE_USLEEP defined, it may be 100 seconds." 276do_test wal3-4.3 { 277 db close 278 set ::locks [list] 279 sqlite3 db test.db -vfs T 280 catchsql { SELECT * FROM x } 281} {1 {locking protocol}} 282 283puts " Warning: Same again!" 284proc lock_callback {method filename handle lock} { 285 if {$lock == "0 1 lock exclusive"} { return SQLITE_BUSY } 286 return SQLITE_OK 287} 288do_test wal3-4.4 { 289 db close 290 set ::locks [list] 291 sqlite3 db test.db -vfs T 292 catchsql { SELECT * FROM x } 293} {1 {locking protocol}} 294db close 295T delete 296 297 298#------------------------------------------------------------------------- 299# Only one client may run recovery at a time. Test this mechanism. 300# 301# When client-2 tries to open a read transaction while client-1 is 302# running recovery, it fails to obtain a lock on an aReadMark[] slot 303# (because they are all locked by recovery). It then tries to obtain 304# a shared lock on the RECOVER lock to see if there really is a 305# recovery running or not. 306# 307# This block of tests checks the effect of an SQLITE_BUSY or SQLITE_IOERR 308# being returned when client-2 attempts a shared lock on the RECOVER byte. 309# 310# An SQLITE_BUSY should be converted to an SQLITE_BUSY_RECOVERY. An 311# SQLITE_IOERR should be returned to the caller. 312# 313do_test wal3-5.1 { 314 faultsim_delete_and_reopen 315 execsql { 316 PRAGMA journal_mode = WAL; 317 CREATE TABLE t1(a, b); 318 INSERT INTO t1 VALUES(1, 2); 319 INSERT INTO t1 VALUES(3, 4); 320 } 321 faultsim_save_and_close 322} {} 323 324testvfs T -default 1 325T script method_callback 326 327proc method_callback {method args} { 328 if {$method == "xShmBarrier"} { 329 incr ::barrier_count 330 if {$::barrier_count == 2} { 331 # This code is executed within the xShmBarrier() callback invoked 332 # by the client running recovery as part of writing the recovered 333 # wal-index header. If a second client attempts to access the 334 # database now, it reads a corrupt (partially written) wal-index 335 # header. But it cannot even get that far, as the first client 336 # is still holding all the locks (recovery takes an exclusive lock 337 # on *all* db locks, preventing access by any other client). 338 # 339 # If global variable ::wal3_do_lockfailure is non-zero, then set 340 # things up so that an IO error occurs within an xShmLock() callback 341 # made by the second client (aka [db2]). 342 # 343 sqlite3 db2 test.db 344 if { $::wal3_do_lockfailure } { T filter xShmLock } 345 set ::testrc [ catch { db2 eval "SELECT * FROM t1" } ::testmsg ] 346 T filter {} 347 db2 close 348 } 349 } 350 351 if {$method == "xShmLock"} { 352 foreach {file handle spec} $args break 353 if { $spec == "2 1 lock shared" } { 354 return SQLITE_IOERR 355 } 356 } 357 358 return SQLITE_OK 359} 360 361# Test a normal SQLITE_BUSY return. 362# 363T filter xShmBarrier 364set testrc "" 365set testmsg "" 366set barrier_count 0 367set wal3_do_lockfailure 0 368do_test wal3-5.2 { 369 faultsim_restore_and_reopen 370 execsql { SELECT * FROM t1 } 371} {1 2 3 4} 372do_test wal3-5.3 { 373 list $::testrc $::testmsg 374} {1 {database is locked}} 375db close 376 377# Test an SQLITE_IOERR return. 378# 379T filter xShmBarrier 380set barrier_count 0 381set wal3_do_lockfailure 1 382set testrc "" 383set testmsg "" 384do_test wal3-5.4 { 385 faultsim_restore_and_reopen 386 execsql { SELECT * FROM t1 } 387} {1 2 3 4} 388do_test wal3-5.5 { 389 list $::testrc $::testmsg 390} {1 {disk I/O error}} 391 392db close 393T delete 394 395#------------------------------------------------------------------------- 396# When opening a read-transaction on a database, if the entire log has 397# already been copied to the database file, the reader grabs a special 398# kind of read lock (on aReadMark[0]). This set of test cases tests the 399# outcome of the following: 400# 401# + The reader discovering that between the time when it determined 402# that the log had been completely backfilled and the lock is obtained 403# that a writer has written to the log. In this case the reader should 404# acquire a different read-lock (not aReadMark[0]) and read the new 405# snapshot. 406# 407# + The attempt to obtain the lock on aReadMark[0] fails with SQLITE_BUSY. 408# This can happen if a checkpoint is ongoing. In this case also simply 409# obtain a different read-lock. 410# 411catch {db close} 412testvfs T -default 1 413do_test wal3-6.1.1 { 414 file delete -force test.db test.db-journal test.db wal 415 sqlite3 db test.db 416 execsql { PRAGMA auto_vacuum = off } 417 execsql { PRAGMA journal_mode = WAL } 418 execsql { 419 CREATE TABLE t1(a, b); 420 INSERT INTO t1 VALUES('o', 't'); 421 INSERT INTO t1 VALUES('t', 'f'); 422 } 423} {} 424do_test wal3-6.1.2 { 425 sqlite3 db2 test.db 426 sqlite3 db3 test.db 427 execsql { BEGIN ; SELECT * FROM t1 } db3 428} {o t t f} 429do_test wal3-6.1.3 { 430 execsql { PRAGMA wal_checkpoint } db2 431} {0 7 7} 432 433# At this point the log file has been fully checkpointed. However, 434# connection [db3] holds a lock that prevents the log from being wrapped. 435# Test case 3.6.1.4 has [db] attempt a read-lock on aReadMark[0]. But 436# as it is obtaining the lock, [db2] appends to the log file. 437# 438T filter xShmLock 439T script lock_callback 440proc lock_callback {method file handle spec} { 441 if {$spec == "3 1 lock shared"} { 442 # This is the callback for [db] to obtain the read lock on aReadMark[0]. 443 # Disable future callbacks using [T filter {}] and write to the log 444 # file using [db2]. [db3] is preventing [db2] from wrapping the log 445 # here, so this is an append. 446 T filter {} 447 db2 eval { INSERT INTO t1 VALUES('f', 's') } 448 } 449 return SQLITE_OK 450} 451do_test wal3-6.1.4 { 452 execsql { 453 BEGIN; 454 SELECT * FROM t1; 455 } 456} {o t t f f s} 457 458# [db] should be left holding a read-lock on some slot other than 459# aReadMark[0]. Test this by demonstrating that the read-lock is preventing 460# the log from being wrapped. 461# 462do_test wal3-6.1.5 { 463 db3 eval COMMIT 464 db2 eval { PRAGMA wal_checkpoint } 465 set sz1 [file size test.db-wal] 466 db2 eval { INSERT INTO t1 VALUES('s', 'e') } 467 set sz2 [file size test.db-wal] 468 expr {$sz2>$sz1} 469} {1} 470 471# Test that if [db2] had not interfered when [db] was trying to grab 472# aReadMark[0], it would have been possible to wrap the log in 3.6.1.5. 473# 474do_test wal3-6.1.6 { 475 execsql { COMMIT } 476 execsql { PRAGMA wal_checkpoint } db2 477 execsql { 478 BEGIN; 479 SELECT * FROM t1; 480 } 481} {o t t f f s s e} 482do_test wal3-6.1.7 { 483 db2 eval { PRAGMA wal_checkpoint } 484 set sz1 [file size test.db-wal] 485 db2 eval { INSERT INTO t1 VALUES('n', 't') } 486 set sz2 [file size test.db-wal] 487 expr {$sz2==$sz1} 488} {1} 489 490db3 close 491db2 close 492db close 493 494do_test wal3-6.2.1 { 495 file delete -force test.db test.db-journal test.db wal 496 sqlite3 db test.db 497 sqlite3 db2 test.db 498 execsql { PRAGMA auto_vacuum = off } 499 execsql { PRAGMA journal_mode = WAL } 500 execsql { 501 CREATE TABLE t1(a, b); 502 INSERT INTO t1 VALUES('h', 'h'); 503 INSERT INTO t1 VALUES('l', 'b'); 504 } 505} {} 506 507T filter xShmLock 508T script lock_callback 509proc lock_callback {method file handle spec} { 510 if {$spec == "3 1 unlock exclusive"} { 511 T filter {} 512 set ::R [db2 eval { 513 BEGIN; 514 SELECT * FROM t1; 515 }] 516 } 517} 518do_test wal3-6.2.2 { 519 execsql { PRAGMA wal_checkpoint } 520} {0 7 7} 521do_test wal3-6.2.3 { 522 set ::R 523} {h h l b} 524do_test wal3-6.2.4 { 525 set sz1 [file size test.db-wal] 526 execsql { INSERT INTO t1 VALUES('b', 'c'); } 527 set sz2 [file size test.db-wal] 528 expr {$sz2 > $sz1} 529} {1} 530do_test wal3-6.2.5 { 531 db2 eval { COMMIT } 532 execsql { PRAGMA wal_checkpoint } 533 set sz1 [file size test.db-wal] 534 execsql { INSERT INTO t1 VALUES('n', 'o'); } 535 set sz2 [file size test.db-wal] 536 expr {$sz2 == $sz1} 537} {1} 538 539db2 close 540db close 541T delete 542 543#------------------------------------------------------------------------- 544# When opening a read-transaction on a database, if the entire log has 545# not yet been copied to the database file, the reader grabs a read 546# lock on aReadMark[x], where x>0. The following test cases experiment 547# with the outcome of the following: 548# 549# + The reader discovering that between the time when it read the 550# wal-index header and the lock was obtained that a writer has 551# written to the log. In this case the reader should re-read the 552# wal-index header and lock a snapshot corresponding to the new 553# header. 554# 555# + The value in the aReadMark[x] slot has been modified since it was 556# read. 557# 558catch {db close} 559testvfs T -default 1 560do_test wal3-7.1.1 { 561 file delete -force test.db test.db-journal test.db wal 562 sqlite3 db test.db 563 execsql { 564 PRAGMA journal_mode = WAL; 565 CREATE TABLE blue(red PRIMARY KEY, green); 566 } 567} {wal} 568 569T script method_callback 570T filter xOpen 571proc method_callback {method args} { 572 if {$method == "xOpen"} { return "reader" } 573} 574do_test wal3-7.1.2 { 575 sqlite3 db2 test.db 576 execsql { SELECT * FROM blue } db2 577} {} 578 579T filter xShmLock 580set ::locks [list] 581proc method_callback {method file handle spec} { 582 if {$handle != "reader" } { return } 583 if {$method == "xShmLock"} { 584 catch { execsql { INSERT INTO blue VALUES(1, 2) } } 585 catch { execsql { INSERT INTO blue VALUES(3, 4) } } 586 } 587 lappend ::locks $spec 588} 589do_test wal3-7.1.3 { 590 execsql { SELECT * FROM blue } db2 591} {1 2 3 4} 592do_test wal3-7.1.4 { 593 set ::locks 594} {{4 1 lock shared} {4 1 unlock shared} {5 1 lock shared} {5 1 unlock shared}} 595 596set ::locks [list] 597proc method_callback {method file handle spec} { 598 if {$handle != "reader" } { return } 599 if {$method == "xShmLock"} { 600 catch { execsql { INSERT INTO blue VALUES(5, 6) } } 601 } 602 lappend ::locks $spec 603} 604do_test wal3-7.2.1 { 605 execsql { SELECT * FROM blue } db2 606} {1 2 3 4 5 6} 607do_test wal3-7.2.2 { 608 set ::locks 609} {{5 1 lock shared} {5 1 unlock shared} {4 1 lock shared} {4 1 unlock shared}} 610 611db close 612db2 close 613T delete 614 615#------------------------------------------------------------------------- 616# 617do_test wal3-8.1 { 618 file delete -force test.db test.db-journal test.db wal 619 sqlite3 db test.db 620 sqlite3 db2 test.db 621 execsql { 622 PRAGMA auto_vacuum = off; 623 PRAGMA journal_mode = WAL; 624 CREATE TABLE b(c); 625 INSERT INTO b VALUES('Tehran'); 626 INSERT INTO b VALUES('Qom'); 627 INSERT INTO b VALUES('Markazi'); 628 PRAGMA wal_checkpoint; 629 } 630} {wal 0 9 9} 631do_test wal3-8.2 { 632 execsql { SELECT * FROM b } 633} {Tehran Qom Markazi} 634do_test wal3-8.3 { 635 db eval { SELECT * FROM b } { 636 db eval { INSERT INTO b VALUES('Qazvin') } 637 set r [db2 eval { SELECT * FROM b }] 638 break 639 } 640 set r 641} {Tehran Qom Markazi Qazvin} 642do_test wal3-8.4 { 643 execsql { 644 INSERT INTO b VALUES('Gilan'); 645 INSERT INTO b VALUES('Ardabil'); 646 } 647} {} 648db2 close 649 650faultsim_save_and_close 651testvfs T -default 1 652faultsim_restore_and_reopen 653T filter xShmLock 654T script lock_callback 655 656proc lock_callback {method file handle spec} { 657 if {$spec == "4 1 unlock exclusive"} { 658 T filter {} 659 set ::r [catchsql { SELECT * FROM b } db2] 660 } 661} 662sqlite3 db test.db 663sqlite3 db2 test.db 664do_test wal3-8.5 { 665 execsql { SELECT * FROM b } 666} {Tehran Qom Markazi Qazvin Gilan Ardabil} 667do_test wal3-8.6 { 668 set ::r 669} {1 {locking protocol}} 670 671db close 672db2 close 673 674faultsim_restore_and_reopen 675sqlite3 db2 test.db 676T filter xShmLock 677T script lock_callback 678proc lock_callback {method file handle spec} { 679 if {$spec == "1 7 unlock exclusive"} { 680 T filter {} 681 set ::r [catchsql { SELECT * FROM b } db2] 682 } 683} 684unset ::r 685do_test wal3-8.5 { 686 execsql { SELECT * FROM b } 687} {Tehran Qom Markazi Qazvin Gilan Ardabil} 688do_test wal3-8.6 { 689 set ::r 690} {1 {locking protocol}} 691 692db close 693db2 close 694T delete 695 696#------------------------------------------------------------------------- 697# When a connection opens a read-lock on the database, it searches for 698# an aReadMark[] slot that is already set to the mxFrame value for the 699# new transaction. If it cannot find one, it attempts to obtain an 700# exclusive lock on an aReadMark[] slot for the purposes of modifying 701# the value, then drops back to a shared-lock for the duration of the 702# transaction. 703# 704# This test case verifies that if an exclusive lock cannot be obtained 705# on any aReadMark[] slot (because there are already several readers), 706# the client takes a shared-lock on a slot without modifying the value 707# and continues. 708# 709set nConn 50 710if { [string match *BSD $tcl_platform(os)] } { set nConn 35 } 711do_test wal3-9.0 { 712 file delete -force test.db test.db-journal test.db wal 713 sqlite3 db test.db 714 execsql { 715 PRAGMA page_size = 1024; 716 PRAGMA journal_mode = WAL; 717 CREATE TABLE whoami(x); 718 INSERT INTO whoami VALUES('nobody'); 719 } 720} {wal} 721for {set i 0} {$i < $nConn} {incr i} { 722 set c db$i 723 do_test wal3-9.1.$i { 724 sqlite3 $c test.db 725 execsql { UPDATE whoami SET x = $c } 726 execsql { 727 BEGIN; 728 SELECT * FROM whoami 729 } $c 730 } $c 731} 732for {set i 0} {$i < $nConn} {incr i} { 733 set c db$i 734 do_test wal3-9.2.$i { 735 execsql { SELECT * FROM whoami } $c 736 } $c 737} 738 739set sz [expr 1024 * (2+$AUTOVACUUM)] 740do_test wal3-9.3 { 741 for {set i 0} {$i < ($nConn-1)} {incr i} { db$i close } 742 execsql { PRAGMA wal_checkpoint } 743 byte_is_zero test.db [expr $sz-1024] 744} {1} 745do_test wal3-9.4 { 746 db[expr $nConn-1] close 747 execsql { PRAGMA wal_checkpoint } 748 set sz2 [file size test.db] 749 byte_is_zero test.db [expr $sz-1024] 750} {0} 751 752do_multiclient_test tn { 753 do_test wal3-10.$tn.1 { 754 sql1 { 755 PRAGMA page_size = 1024; 756 CREATE TABLE t1(x); 757 PRAGMA journal_mode = WAL; 758 PRAGMA wal_autocheckpoint = 100000; 759 BEGIN; 760 INSERT INTO t1 VALUES(randomblob(800)); 761 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 2 762 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 4 763 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 8 764 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 16 765 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 32 766 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 64 767 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 128 768 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 256 769 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 512 770 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 1024 771 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 2048 772 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 4096 773 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 8192 774 COMMIT; 775 CREATE INDEX i1 ON t1(x); 776 } 777 778 expr {[file size test.db-wal] > [expr 1032*9000]} 779 } 1 780 781 do_test wal3-10.$tn.2 { 782 sql2 {PRAGMA integrity_check} 783 } {ok} 784} 785 786finish_test 787 788