17c24610eSdan# 2010 March 17 27c24610eSdan# 37c24610eSdan# The author disclaims copyright to this source code. In place of 47c24610eSdan# a legal notice, here is a blessing: 57c24610eSdan# 67c24610eSdan# May you do good and not evil. 77c24610eSdan# May you find forgiveness for yourself and forgive others. 87c24610eSdan# May you share freely, never taking more than you give. 97c24610eSdan# 107c24610eSdan#*********************************************************************** 11d3f8f946Sdan# This file implements regression tests for SQLite library. The 12d3f8f946Sdan# focus of this file is testing the operation of the library in 13d3f8f946Sdan# "PRAGMA journal_mode=WAL" mode. The tests in this file use 14d3f8f946Sdan# brute force methods, so may take a while to run. 157c24610eSdan# 167c24610eSdan 177c24610eSdanset testdir [file dirname $argv0] 187c24610eSdansource $testdir/tester.tcl 19*be7721d1Sdansource $testdir/wal_common.tcl 20*be7721d1Sdansource $testdir/lock_common.tcl 217c24610eSdan 225cf53537Sdanifcapable !wal {finish_test ; return } 235cf53537Sdan 24*be7721d1Sdanset testprefix walslow 25*be7721d1Sdan 267c24610eSdanproc reopen_db {} { 277c24610eSdan catch { db close } 28fda06befSmistachkin forcedelete test.db test.db-wal 297c24610eSdan sqlite3 db test.db 307c24610eSdan execsql { PRAGMA journal_mode = wal } 317c24610eSdan} 327c24610eSdan 337c24610eSdandb close 347c24610eSdansave_prng_state 357c24610eSdanfor {set seed 1} {$seed<10} {incr seed} { 367c24610eSdan expr srand($seed) 377c24610eSdan restore_prng_state 387c24610eSdan reopen_db 397c24610eSdan do_test walslow-1.seed=$seed.0 { 407c24610eSdan execsql { CREATE TABLE t1(a, b) } 417c24610eSdan execsql { CREATE INDEX i1 ON t1(a) } 427c24610eSdan execsql { CREATE INDEX i2 ON t1(b) } 437c24610eSdan } {} 447c24610eSdan 457c24610eSdan for {set iTest 1} {$iTest < 100} {incr iTest} { 467c24610eSdan 477c24610eSdan do_test walslow-1.seed=$seed.$iTest.1 { 487c24610eSdan set w [expr int(rand()*2000)] 497c24610eSdan set x [expr int(rand()*2000)] 507c24610eSdan execsql { INSERT INTO t1 VALUES(randomblob($w), randomblob($x)) } 517c24610eSdan execsql { PRAGMA integrity_check } 527c24610eSdan } {ok} 537c24610eSdan 547c24610eSdan do_test walslow-1.seed=$seed.$iTest.2 { 555a299f91Sdan execsql "PRAGMA wal_checkpoint;" 567c24610eSdan execsql { PRAGMA integrity_check } 577c24610eSdan } {ok} 587c24610eSdan 597c24610eSdan do_test walslow-1.seed=$seed.$iTest.3 { 60fda06befSmistachkin forcedelete testX.db testX.db-wal 61fda06befSmistachkin copy_file test.db testX.db 62fda06befSmistachkin copy_file test.db-wal testX.db-wal 637c24610eSdan 647c24610eSdan sqlite3 db2 testX.db 657c24610eSdan execsql { PRAGMA journal_mode = WAL } db2 667c24610eSdan execsql { PRAGMA integrity_check } db2 677c24610eSdan } {ok} 687c24610eSdan 697c24610eSdan do_test walslow-1.seed=$seed.$iTest.4 { 707c24610eSdan execsql { SELECT count(*) FROM t1 WHERE a!=b } db2 717c24610eSdan } [execsql { SELECT count(*) FROM t1 WHERE a!=b }] 727c24610eSdan db2 close 737c24610eSdan } 747c24610eSdan} 757c24610eSdan 76*be7721d1Sdan#------------------------------------------------------------------------- 77*be7721d1Sdan# Test case walslow-3.* tests that the checksum calculation detects single 78*be7721d1Sdan# byte changes to frame or frame-header data and considers the frame 79*be7721d1Sdan# invalid as a result. 80*be7721d1Sdan# 81*be7721d1Sdanreset_db 82*be7721d1Sdando_test 3.1 { 83*be7721d1Sdan 84*be7721d1Sdan execsql { 85*be7721d1Sdan PRAGMA synchronous = NORMAL; 86*be7721d1Sdan PRAGMA page_size = 1024; 87*be7721d1Sdan CREATE TABLE t1(a, b); 88*be7721d1Sdan INSERT INTO t1 VALUES(1, randomblob(300)); 89*be7721d1Sdan INSERT INTO t1 VALUES(2, randomblob(300)); 90*be7721d1Sdan PRAGMA journal_mode = WAL; 91*be7721d1Sdan INSERT INTO t1 VALUES(3, randomblob(300)); 92*be7721d1Sdan } 93*be7721d1Sdan 94*be7721d1Sdan file size test.db-wal 95*be7721d1Sdan} [wal_file_size 1 1024] 96*be7721d1Sdando_test 3.2 { 97*be7721d1Sdan forcecopy test.db-wal test2.db-wal 98*be7721d1Sdan forcecopy test.db test2.db 99*be7721d1Sdan sqlite3 db2 test2.db 100*be7721d1Sdan execsql { SELECT a FROM t1 } db2 101*be7721d1Sdan} {1 2 3} 102*be7721d1Sdandb2 close 103*be7721d1Sdanforcecopy test.db test2.db 104*be7721d1Sdan 105*be7721d1Sdanforeach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} { 106*be7721d1Sdan do_test 3.3.$incr { 107*be7721d1Sdan set FAIL 0 108*be7721d1Sdan for {set iOff 0} {$iOff < [wal_file_size 1 1024]} {incr iOff} { 109*be7721d1Sdan 110*be7721d1Sdan forcecopy test.db-wal test2.db-wal 111*be7721d1Sdan set fd [open test2.db-wal r+] 112*be7721d1Sdan fconfigure $fd -encoding binary 113*be7721d1Sdan fconfigure $fd -translation binary 114*be7721d1Sdan 115*be7721d1Sdan seek $fd $iOff 116*be7721d1Sdan binary scan [read $fd 1] c x 117*be7721d1Sdan seek $fd $iOff 118*be7721d1Sdan puts -nonewline $fd [binary format c [expr {($x+$incr)&0xFF}]] 119*be7721d1Sdan close $fd 120*be7721d1Sdan 121*be7721d1Sdan sqlite3 db2 test2.db 122*be7721d1Sdan if { [execsql { SELECT a FROM t1 } db2] != "1 2" } {set FAIL 1} 123*be7721d1Sdan db2 close 124*be7721d1Sdan } 125*be7721d1Sdan set FAIL 126*be7721d1Sdan } {0} 127*be7721d1Sdan} 128*be7721d1Sdan 129*be7721d1Sdan 130*be7721d1Sdan#------------------------------------------------------------------------- 131*be7721d1Sdan# Test large log summaries. 132*be7721d1Sdan# 133*be7721d1Sdan# In this case "large" usually means a log file that requires a wal-index 134*be7721d1Sdan# mapping larger than 64KB (the default initial allocation). A 64KB wal-index 135*be7721d1Sdan# is large enough for a log file that contains approximately 13100 frames. 136*be7721d1Sdan# So the following tests create logs containing at least this many frames. 137*be7721d1Sdan# 138*be7721d1Sdan# 4.1.*: This test case creates a very large log file within the 139*be7721d1Sdan# file-system (around 200MB). The log file does not contain 140*be7721d1Sdan# any valid frames. Test that the database file can still be 141*be7721d1Sdan# opened and queried, and that the invalid log file causes no 142*be7721d1Sdan# problems. 143*be7721d1Sdan# 144*be7721d1Sdan# 4.2.*: Test that a process may create a large log file and query 145*be7721d1Sdan# the database (including the log file that it itself created). 146*be7721d1Sdan# 147*be7721d1Sdan# 4.3.*: Test that if a very large log file is created, and then a 148*be7721d1Sdan# second connection is opened on the database file, it is possible 149*be7721d1Sdan# to query the database (and the very large log) using the 150*be7721d1Sdan# second connection. 151*be7721d1Sdan# 152*be7721d1Sdan# 4.4.*: Same test as wal-13.3.*. Except in this case the second 153*be7721d1Sdan# connection is opened by an external process. 154*be7721d1Sdan# 155*be7721d1Sdanset ::blobcnt 0 156*be7721d1Sdanproc blob {nByte} { 157*be7721d1Sdan incr ::blobcnt 158*be7721d1Sdan return [string range [string repeat "${::blobcnt}x" $nByte] 1 $nByte] 159*be7721d1Sdan} 160*be7721d1Sdan 161*be7721d1Sdanreset_db 162*be7721d1Sdando_execsql_test 4.1 { 163*be7721d1Sdan PRAGMA journal_mode = wal; 164*be7721d1Sdan CREATE TABLE t1(x, y); 165*be7721d1Sdan INSERT INTO "t1" VALUES('A',0); 166*be7721d1Sdan CREATE TABLE t2(x, y); 167*be7721d1Sdan INSERT INTO "t2" VALUES('B',2); 168*be7721d1Sdan} {wal} 169*be7721d1Sdandb close 170*be7721d1Sdan 171*be7721d1Sdando_test 4.1.1 { 172*be7721d1Sdan list [file exists test.db] [file exists test.db-wal] 173*be7721d1Sdan} {1 0} 174*be7721d1Sdando_test 4.1.2 { 175*be7721d1Sdan set fd [open test.db-wal w] 176*be7721d1Sdan seek $fd [expr 200*1024*1024] 177*be7721d1Sdan puts $fd "" 178*be7721d1Sdan close $fd 179*be7721d1Sdan sqlite3 db test.db 180*be7721d1Sdan execsql { SELECT * FROM t2 } 181*be7721d1Sdan} {B 2} 182*be7721d1Sdando_test 4.1.3 { 183*be7721d1Sdan db close 184*be7721d1Sdan file exists test.db-wal 185*be7721d1Sdan} {0} 186*be7721d1Sdan 187*be7721d1Sdando_test 4.2.1 { 188*be7721d1Sdan sqlite3 db test.db 189*be7721d1Sdan execsql { SELECT count(*) FROM t2 } 190*be7721d1Sdan} {1} 191*be7721d1Sdando_test 4.2.2 { 192*be7721d1Sdan db function blob blob 193*be7721d1Sdan for {set i 0} {$i < 16} {incr i} { 194*be7721d1Sdan execsql { INSERT INTO t2 SELECT blob(400), blob(400) FROM t2 } 195*be7721d1Sdan } 196*be7721d1Sdan execsql { SELECT count(*) FROM t2 } 197*be7721d1Sdan} [expr int(pow(2, 16))] 198*be7721d1Sdando_test 4.2.3 { 199*be7721d1Sdan expr [file size test.db-wal] > [wal_file_size 33000 1024] 200*be7721d1Sdan} 1 201*be7721d1Sdan 202*be7721d1Sdando_multiclient_test tn { 203*be7721d1Sdan incr tn 2 204*be7721d1Sdan 205*be7721d1Sdan do_test 4.$tn.0 { 206*be7721d1Sdan sql1 { 207*be7721d1Sdan PRAGMA journal_mode = WAL; 208*be7721d1Sdan CREATE TABLE t1(x); 209*be7721d1Sdan INSERT INTO t1 SELECT randomblob(800); 210*be7721d1Sdan } 211*be7721d1Sdan sql1 { SELECT count(*) FROM t1 } 212*be7721d1Sdan } {1} 213*be7721d1Sdan 214*be7721d1Sdan for {set ii 1} {$ii<16} {incr ii} { 215*be7721d1Sdan do_test 4.$tn.$ii.a { 216*be7721d1Sdan sql2 { INSERT INTO t1 SELECT randomblob(800) FROM t1 } 217*be7721d1Sdan sql2 { SELECT count(*) FROM t1 } 218*be7721d1Sdan } [expr (1<<$ii)] 219*be7721d1Sdan do_test 4.$tn.$ii.b { 220*be7721d1Sdan sql1 { SELECT count(*) FROM t1 } 221*be7721d1Sdan } [expr (1<<$ii)] 222*be7721d1Sdan do_test 4.$tn.$ii.c { 223*be7721d1Sdan sql1 { SELECT count(*) FROM t1 } 224*be7721d1Sdan } [expr (1<<$ii)] 225*be7721d1Sdan do_test 4.$tn.$ii.d { 226*be7721d1Sdan sql1 { PRAGMA integrity_check } 227*be7721d1Sdan } {ok} 228*be7721d1Sdan } 229*be7721d1Sdan} 2307c24610eSdan 2317c24610eSdanfinish_test 232