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 forcecopy test.db test2.db 98 forcecopy test.db-wal test2.db-wal 99 forcedelete 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 forcedelete 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 execsql { CREATE TABLE filler(a,b,c); } 221 222 set ::syncs [list] 223 T filter xSync 224 execsql { 225 CREATE TABLE x(y); 226 INSERT INTO x VALUES('z'); 227 PRAGMA wal_checkpoint; 228 } 229 T filter {} 230 set ::syncs 231 } $synccount 232 233 db close 234 T delete 235} 236 237#------------------------------------------------------------------------- 238# When recovering the contents of a WAL file, a process obtains the WRITER 239# lock, then locks all other bytes before commencing recovery. If it fails 240# to lock all other bytes (because some other process is holding a read 241# lock) it should retry up to 100 times. Then return SQLITE_PROTOCOL to the 242# caller. Test this (test case wal3-4.3). 243# 244# Also test the effect of hitting an SQLITE_BUSY while attempting to obtain 245# the WRITER lock (should be the same). Test case wal3-4.4. 246# 247proc lock_callback {method filename handle lock} { 248 lappend ::locks $lock 249} 250do_test wal3-4.1 { 251 testvfs T 252 T filter xShmLock 253 T script lock_callback 254 set ::locks [list] 255 sqlite3 db test.db -vfs T 256 execsql { SELECT * FROM x } 257 lrange $::locks 0 3 258} [list {0 1 lock exclusive} {1 7 lock exclusive} \ 259 {1 7 unlock exclusive} {0 1 unlock exclusive} \ 260] 261do_test wal3-4.2 { 262 db close 263 set ::locks [list] 264 sqlite3 db test.db -vfs T 265 execsql { SELECT * FROM x } 266 lrange $::locks 0 3 267} [list {0 1 lock exclusive} {1 7 lock exclusive} \ 268 {1 7 unlock exclusive} {0 1 unlock exclusive} \ 269] 270proc lock_callback {method filename handle lock} { 271 if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY } 272 return SQLITE_OK 273} 274puts " Warning: This next test case causes SQLite to call xSleep(1) 100 times." 275puts " Normally this equates to a 100ms delay, but if SQLite is built on unix" 276puts " without HAVE_USLEEP defined, it may be 100 seconds." 277do_test wal3-4.3 { 278 db close 279 set ::locks [list] 280 sqlite3 db test.db -vfs T 281 catchsql { SELECT * FROM x } 282} {1 {locking protocol}} 283 284puts " Warning: Same again!" 285proc lock_callback {method filename handle lock} { 286 if {$lock == "0 1 lock exclusive"} { return SQLITE_BUSY } 287 return SQLITE_OK 288} 289do_test wal3-4.4 { 290 db close 291 set ::locks [list] 292 sqlite3 db test.db -vfs T 293 catchsql { SELECT * FROM x } 294} {1 {locking protocol}} 295db close 296T delete 297 298 299#------------------------------------------------------------------------- 300# Only one client may run recovery at a time. Test this mechanism. 301# 302# When client-2 tries to open a read transaction while client-1 is 303# running recovery, it fails to obtain a lock on an aReadMark[] slot 304# (because they are all locked by recovery). It then tries to obtain 305# a shared lock on the RECOVER lock to see if there really is a 306# recovery running or not. 307# 308# This block of tests checks the effect of an SQLITE_BUSY or SQLITE_IOERR 309# being returned when client-2 attempts a shared lock on the RECOVER byte. 310# 311# An SQLITE_BUSY should be converted to an SQLITE_BUSY_RECOVERY. An 312# SQLITE_IOERR should be returned to the caller. 313# 314do_test wal3-5.1 { 315 faultsim_delete_and_reopen 316 execsql { 317 PRAGMA journal_mode = WAL; 318 CREATE TABLE t1(a, b); 319 INSERT INTO t1 VALUES(1, 2); 320 INSERT INTO t1 VALUES(3, 4); 321 } 322 faultsim_save_and_close 323} {} 324 325testvfs T -default 1 326T script method_callback 327 328proc method_callback {method args} { 329 if {$method == "xShmBarrier"} { 330 incr ::barrier_count 331 if {$::barrier_count == 2} { 332 # This code is executed within the xShmBarrier() callback invoked 333 # by the client running recovery as part of writing the recovered 334 # wal-index header. If a second client attempts to access the 335 # database now, it reads a corrupt (partially written) wal-index 336 # header. But it cannot even get that far, as the first client 337 # is still holding all the locks (recovery takes an exclusive lock 338 # on *all* db locks, preventing access by any other client). 339 # 340 # If global variable ::wal3_do_lockfailure is non-zero, then set 341 # things up so that an IO error occurs within an xShmLock() callback 342 # made by the second client (aka [db2]). 343 # 344 sqlite3 db2 test.db 345 if { $::wal3_do_lockfailure } { T filter xShmLock } 346 set ::testrc [ catch { db2 eval "SELECT * FROM t1" } ::testmsg ] 347 T filter {} 348 db2 close 349 } 350 } 351 352 if {$method == "xShmLock"} { 353 foreach {file handle spec} $args break 354 if { $spec == "2 1 lock shared" } { 355 return SQLITE_IOERR 356 } 357 } 358 359 return SQLITE_OK 360} 361 362# Test a normal SQLITE_BUSY return. 363# 364T filter xShmBarrier 365set testrc "" 366set testmsg "" 367set barrier_count 0 368set wal3_do_lockfailure 0 369do_test wal3-5.2 { 370 faultsim_restore_and_reopen 371 execsql { SELECT * FROM t1 } 372} {1 2 3 4} 373do_test wal3-5.3 { 374 list $::testrc $::testmsg 375} {1 {database is locked}} 376db close 377 378# Test an SQLITE_IOERR return. 379# 380T filter xShmBarrier 381set barrier_count 0 382set wal3_do_lockfailure 1 383set testrc "" 384set testmsg "" 385do_test wal3-5.4 { 386 faultsim_restore_and_reopen 387 execsql { SELECT * FROM t1 } 388} {1 2 3 4} 389do_test wal3-5.5 { 390 list $::testrc $::testmsg 391} {1 {disk I/O error}} 392 393db close 394T delete 395 396#------------------------------------------------------------------------- 397# When opening a read-transaction on a database, if the entire log has 398# already been copied to the database file, the reader grabs a special 399# kind of read lock (on aReadMark[0]). This set of test cases tests the 400# outcome of the following: 401# 402# + The reader discovering that between the time when it determined 403# that the log had been completely backfilled and the lock is obtained 404# that a writer has written to the log. In this case the reader should 405# acquire a different read-lock (not aReadMark[0]) and read the new 406# snapshot. 407# 408# + The attempt to obtain the lock on aReadMark[0] fails with SQLITE_BUSY. 409# This can happen if a checkpoint is ongoing. In this case also simply 410# obtain a different read-lock. 411# 412catch {db close} 413testvfs T -default 1 414do_test wal3-6.1.1 { 415 forcedelete test.db test.db-journal test.db wal 416 sqlite3 db test.db 417 execsql { PRAGMA auto_vacuum = off } 418 execsql { PRAGMA journal_mode = WAL } 419 execsql { 420 CREATE TABLE t1(a, b); 421 INSERT INTO t1 VALUES('o', 't'); 422 INSERT INTO t1 VALUES('t', 'f'); 423 } 424} {} 425do_test wal3-6.1.2 { 426 sqlite3 db2 test.db 427 sqlite3 db3 test.db 428 execsql { BEGIN ; SELECT * FROM t1 } db3 429} {o t t f} 430do_test wal3-6.1.3 { 431 execsql { PRAGMA wal_checkpoint } db2 432} {0 7 7} 433 434# At this point the log file has been fully checkpointed. However, 435# connection [db3] holds a lock that prevents the log from being wrapped. 436# Test case 3.6.1.4 has [db] attempt a read-lock on aReadMark[0]. But 437# as it is obtaining the lock, [db2] appends to the log file. 438# 439T filter xShmLock 440T script lock_callback 441proc lock_callback {method file handle spec} { 442 if {$spec == "3 1 lock shared"} { 443 # This is the callback for [db] to obtain the read lock on aReadMark[0]. 444 # Disable future callbacks using [T filter {}] and write to the log 445 # file using [db2]. [db3] is preventing [db2] from wrapping the log 446 # here, so this is an append. 447 T filter {} 448 db2 eval { INSERT INTO t1 VALUES('f', 's') } 449 } 450 return SQLITE_OK 451} 452do_test wal3-6.1.4 { 453 execsql { 454 BEGIN; 455 SELECT * FROM t1; 456 } 457} {o t t f f s} 458 459# [db] should be left holding a read-lock on some slot other than 460# aReadMark[0]. Test this by demonstrating that the read-lock is preventing 461# the log from being wrapped. 462# 463do_test wal3-6.1.5 { 464 db3 eval COMMIT 465 db2 eval { PRAGMA wal_checkpoint } 466 set sz1 [file size test.db-wal] 467 db2 eval { INSERT INTO t1 VALUES('s', 'e') } 468 set sz2 [file size test.db-wal] 469 expr {$sz2>$sz1} 470} {1} 471 472# Test that if [db2] had not interfered when [db] was trying to grab 473# aReadMark[0], it would have been possible to wrap the log in 3.6.1.5. 474# 475do_test wal3-6.1.6 { 476 execsql { COMMIT } 477 execsql { PRAGMA wal_checkpoint } db2 478 execsql { 479 BEGIN; 480 SELECT * FROM t1; 481 } 482} {o t t f f s s e} 483do_test wal3-6.1.7 { 484 db2 eval { PRAGMA wal_checkpoint } 485 set sz1 [file size test.db-wal] 486 db2 eval { INSERT INTO t1 VALUES('n', 't') } 487 set sz2 [file size test.db-wal] 488 expr {$sz2==$sz1} 489} {1} 490 491db3 close 492db2 close 493db close 494 495do_test wal3-6.2.1 { 496 forcedelete test.db test.db-journal test.db wal 497 sqlite3 db test.db 498 sqlite3 db2 test.db 499 execsql { PRAGMA auto_vacuum = off } 500 execsql { PRAGMA journal_mode = WAL } 501 execsql { 502 CREATE TABLE t1(a, b); 503 INSERT INTO t1 VALUES('h', 'h'); 504 INSERT INTO t1 VALUES('l', 'b'); 505 } 506} {} 507 508T filter xShmLock 509T script lock_callback 510proc lock_callback {method file handle spec} { 511 if {$spec == "3 1 unlock exclusive"} { 512 T filter {} 513 set ::R [db2 eval { 514 BEGIN; 515 SELECT * FROM t1; 516 }] 517 } 518} 519do_test wal3-6.2.2 { 520 execsql { PRAGMA wal_checkpoint } 521} {0 7 7} 522do_test wal3-6.2.3 { 523 set ::R 524} {h h l b} 525do_test wal3-6.2.4 { 526 set sz1 [file size test.db-wal] 527 execsql { INSERT INTO t1 VALUES('b', 'c'); } 528 set sz2 [file size test.db-wal] 529 expr {$sz2 > $sz1} 530} {1} 531do_test wal3-6.2.5 { 532 db2 eval { COMMIT } 533 execsql { PRAGMA wal_checkpoint } 534 set sz1 [file size test.db-wal] 535 execsql { INSERT INTO t1 VALUES('n', 'o'); } 536 set sz2 [file size test.db-wal] 537 expr {$sz2 == $sz1} 538} {1} 539 540db2 close 541db close 542T delete 543 544#------------------------------------------------------------------------- 545# When opening a read-transaction on a database, if the entire log has 546# not yet been copied to the database file, the reader grabs a read 547# lock on aReadMark[x], where x>0. The following test cases experiment 548# with the outcome of the following: 549# 550# + The reader discovering that between the time when it read the 551# wal-index header and the lock was obtained that a writer has 552# written to the log. In this case the reader should re-read the 553# wal-index header and lock a snapshot corresponding to the new 554# header. 555# 556# + The value in the aReadMark[x] slot has been modified since it was 557# read. 558# 559catch {db close} 560testvfs T -default 1 561do_test wal3-7.1.1 { 562 forcedelete test.db test.db-journal test.db wal 563 sqlite3 db test.db 564 execsql { 565 PRAGMA journal_mode = WAL; 566 CREATE TABLE blue(red PRIMARY KEY, green); 567 } 568} {wal} 569 570T script method_callback 571T filter xOpen 572proc method_callback {method args} { 573 if {$method == "xOpen"} { return "reader" } 574} 575do_test wal3-7.1.2 { 576 sqlite3 db2 test.db 577 execsql { SELECT * FROM blue } db2 578} {} 579 580T filter xShmLock 581set ::locks [list] 582proc method_callback {method file handle spec} { 583 if {$handle != "reader" } { return } 584 if {$method == "xShmLock"} { 585 catch { execsql { INSERT INTO blue VALUES(1, 2) } } 586 catch { execsql { INSERT INTO blue VALUES(3, 4) } } 587 } 588 lappend ::locks $spec 589} 590do_test wal3-7.1.3 { 591 execsql { SELECT * FROM blue } db2 592} {1 2 3 4} 593do_test wal3-7.1.4 { 594 set ::locks 595} {{4 1 lock shared} {4 1 unlock shared} {5 1 lock shared} {5 1 unlock shared}} 596 597set ::locks [list] 598proc method_callback {method file handle spec} { 599 if {$handle != "reader" } { return } 600 if {$method == "xShmLock"} { 601 catch { execsql { INSERT INTO blue VALUES(5, 6) } } 602 } 603 lappend ::locks $spec 604} 605do_test wal3-7.2.1 { 606 execsql { SELECT * FROM blue } db2 607} {1 2 3 4 5 6} 608do_test wal3-7.2.2 { 609 set ::locks 610} {{5 1 lock shared} {5 1 unlock shared} {4 1 lock shared} {4 1 unlock shared}} 611 612db close 613db2 close 614T delete 615 616#------------------------------------------------------------------------- 617# 618do_test wal3-8.1 { 619 forcedelete test.db test.db-journal test.db wal 620 sqlite3 db test.db 621 sqlite3 db2 test.db 622 execsql { 623 PRAGMA auto_vacuum = off; 624 PRAGMA journal_mode = WAL; 625 CREATE TABLE b(c); 626 INSERT INTO b VALUES('Tehran'); 627 INSERT INTO b VALUES('Qom'); 628 INSERT INTO b VALUES('Markazi'); 629 PRAGMA wal_checkpoint; 630 } 631} {wal 0 9 9} 632do_test wal3-8.2 { 633 execsql { SELECT * FROM b } 634} {Tehran Qom Markazi} 635do_test wal3-8.3 { 636 db eval { SELECT * FROM b } { 637 db eval { INSERT INTO b VALUES('Qazvin') } 638 set r [db2 eval { SELECT * FROM b }] 639 break 640 } 641 set r 642} {Tehran Qom Markazi Qazvin} 643do_test wal3-8.4 { 644 execsql { 645 INSERT INTO b VALUES('Gilan'); 646 INSERT INTO b VALUES('Ardabil'); 647 } 648} {} 649db2 close 650 651faultsim_save_and_close 652testvfs T -default 1 653faultsim_restore_and_reopen 654T filter xShmLock 655T script lock_callback 656 657proc lock_callback {method file handle spec} { 658 if {$spec == "4 1 unlock exclusive"} { 659 T filter {} 660 set ::r [catchsql { SELECT * FROM b } db2] 661 } 662} 663sqlite3 db test.db 664sqlite3 db2 test.db 665do_test wal3-8.5 { 666 execsql { SELECT * FROM b } 667} {Tehran Qom Markazi Qazvin Gilan Ardabil} 668do_test wal3-8.6 { 669 set ::r 670} {1 {locking protocol}} 671 672db close 673db2 close 674 675faultsim_restore_and_reopen 676sqlite3 db2 test.db 677T filter xShmLock 678T script lock_callback 679proc lock_callback {method file handle spec} { 680 if {$spec == "1 7 unlock exclusive"} { 681 T filter {} 682 set ::r [catchsql { SELECT * FROM b } db2] 683 } 684} 685unset ::r 686do_test wal3-8.5 { 687 execsql { SELECT * FROM b } 688} {Tehran Qom Markazi Qazvin Gilan Ardabil} 689do_test wal3-8.6 { 690 set ::r 691} {1 {locking protocol}} 692 693db close 694db2 close 695T delete 696 697#------------------------------------------------------------------------- 698# When a connection opens a read-lock on the database, it searches for 699# an aReadMark[] slot that is already set to the mxFrame value for the 700# new transaction. If it cannot find one, it attempts to obtain an 701# exclusive lock on an aReadMark[] slot for the purposes of modifying 702# the value, then drops back to a shared-lock for the duration of the 703# transaction. 704# 705# This test case verifies that if an exclusive lock cannot be obtained 706# on any aReadMark[] slot (because there are already several readers), 707# the client takes a shared-lock on a slot without modifying the value 708# and continues. 709# 710set nConn 50 711if { [string match *BSD $tcl_platform(os)] } { set nConn 25 } 712do_test wal3-9.0 { 713 forcedelete test.db test.db-journal test.db wal 714 sqlite3 db test.db 715 execsql { 716 PRAGMA page_size = 1024; 717 PRAGMA journal_mode = WAL; 718 CREATE TABLE whoami(x); 719 INSERT INTO whoami VALUES('nobody'); 720 } 721} {wal} 722for {set i 0} {$i < $nConn} {incr i} { 723 set c db$i 724 do_test wal3-9.1.$i { 725 sqlite3 $c test.db 726 execsql { UPDATE whoami SET x = $c } 727 execsql { 728 BEGIN; 729 SELECT * FROM whoami 730 } $c 731 } $c 732} 733for {set i 0} {$i < $nConn} {incr i} { 734 set c db$i 735 do_test wal3-9.2.$i { 736 execsql { SELECT * FROM whoami } $c 737 } $c 738} 739 740set sz [expr 1024 * (2+$AUTOVACUUM)] 741do_test wal3-9.3 { 742 for {set i 0} {$i < ($nConn-1)} {incr i} { db$i close } 743 execsql { PRAGMA wal_checkpoint } 744 byte_is_zero test.db [expr $sz-1024] 745} {1} 746do_test wal3-9.4 { 747 db[expr $nConn-1] close 748 execsql { PRAGMA wal_checkpoint } 749 set sz2 [file size test.db] 750 byte_is_zero test.db [expr $sz-1024] 751} {0} 752 753do_multiclient_test tn { 754 do_test wal3-10.$tn.1 { 755 sql1 { 756 PRAGMA page_size = 1024; 757 CREATE TABLE t1(x); 758 PRAGMA journal_mode = WAL; 759 PRAGMA wal_autocheckpoint = 100000; 760 BEGIN; 761 INSERT INTO t1 VALUES(randomblob(800)); 762 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 2 763 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 4 764 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 8 765 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 16 766 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 32 767 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 64 768 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 128 769 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 256 770 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 512 771 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 1024 772 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 2048 773 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 4096 774 INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 8192 775 COMMIT; 776 CREATE INDEX i1 ON t1(x); 777 } 778 779 expr {[file size test.db-wal] > [expr 1032*9000]} 780 } 1 781 782 do_test wal3-10.$tn.2 { 783 sql2 {PRAGMA integrity_check} 784 } {ok} 785} 786 787finish_test 788