192c02da3Sdan# 2011 May 09 292c02da3Sdan# 392c02da3Sdan# The author disclaims copyright to this source code. In place of 492c02da3Sdan# a legal notice, here is a blessing: 592c02da3Sdan# 692c02da3Sdan# May you do good and not evil. 792c02da3Sdan# May you find forgiveness for yourself and forgive others. 892c02da3Sdan# May you share freely, never taking more than you give. 992c02da3Sdan# 1092c02da3Sdan#*********************************************************************** 1192c02da3Sdan# 1292c02da3Sdan# This file contains tests for using WAL databases in read-only mode. 1392c02da3Sdan# 1492c02da3Sdan 1592c02da3Sdanset testdir [file dirname $argv0] 1692c02da3Sdansource $testdir/tester.tcl 1792c02da3Sdansource $testdir/lock_common.tcl 18cbd33219Sdansource $testdir/wal_common.tcl 19cbd33219Sdanset ::testprefix walro2 2092c02da3Sdan 2192c02da3Sdan# And only if the build is WAL-capable. 2292c02da3Sdan# 2392c02da3Sdanifcapable !wal { 2492c02da3Sdan finish_test 2592c02da3Sdan return 2692c02da3Sdan} 2792c02da3Sdan 28e9418778Sdanproc copy_to_test2 {bZeroShm} { 29e9418778Sdan forcecopy test.db test.db2 30e9418778Sdan forcecopy test.db-wal test.db2-wal 31e9418778Sdan if {$bZeroShm} { 32e9418778Sdan forcedelete test.db2-shm 33e9418778Sdan set fd [open test.db2-shm w] 34e9418778Sdan seek $fd [expr [file size test.db-shm]-1] 35e9418778Sdan puts -nonewline $fd "\0" 36e9418778Sdan close $fd 37e9418778Sdan } else { 38e9418778Sdan forcecopy test.db-shm test.db2-shm 39e9418778Sdan } 40e9418778Sdan} 41e9418778Sdan 4260d72b9bSdan# Most systems allocate the *-shm file in 32KB trunks. But on UNIX systems 4360d72b9bSdan# for which the getpagesize() call returns greater than 32K, the *-shm 4460d72b9bSdan# file is allocated in page-sized units (since you cannot mmap part of 4560d72b9bSdan# a page). The following code sets variable $MINSHMSZ to the smallest 4660d72b9bSdan# possible *-shm file (i.e. the greater of 32KB and the system page-size). 4760d72b9bSdan# 4860d72b9bSdando_execsql_test 0.0 { 4960d72b9bSdan PRAGMA journal_mode = wal; 5060d72b9bSdan CREATE TABLE t1(x); 51d1317095Sdan} {wal} 5260d72b9bSdanset MINSHMSZ [file size test.db-shm] 53*d6b44ec3Sdrhset dfltpgsz [db one {PRAGMA page_size}] 5460d72b9bSdan 55e9418778Sdanforeach bZeroShm {0 1} { 56*d6b44ec3Sdrh for {set pgsz 512} {$pgsz<=65536} {set pgsz [expr {$pgsz*2}]} { 57*d6b44ec3Sdrh set TN [expr $bZeroShm+1]-$pgsz 5892c02da3Sdan do_multiclient_test tn { 5992c02da3Sdan 6092c02da3Sdan # Close all connections and delete the database. 6192c02da3Sdan # 6292c02da3Sdan code1 { db close } 6392c02da3Sdan code2 { db2 close } 6492c02da3Sdan code3 { db3 close } 6592c02da3Sdan forcedelete test.db 6692c02da3Sdan 6792c02da3Sdan # Do not run tests with the connections in the same process. 6892c02da3Sdan # 6992c02da3Sdan if {$tn==2} continue 7092c02da3Sdan 7192c02da3Sdan foreach c {code1 code2 code3} { 7292c02da3Sdan $c { 7392c02da3Sdan sqlite3_shutdown 7492c02da3Sdan sqlite3_config_uri 1 7592c02da3Sdan } 7692c02da3Sdan } 7792c02da3Sdan 78e9418778Sdan do_test $TN.1.1 { 7992c02da3Sdan code2 { sqlite3 db2 test.db } 80*d6b44ec3Sdrh sql2 "PRAGMA page_size=$::pgsz" 8192c02da3Sdan sql2 { 8292c02da3Sdan CREATE TABLE t1(x, y); 8392c02da3Sdan PRAGMA journal_mode = WAL; 8492c02da3Sdan INSERT INTO t1 VALUES('a', 'b'); 8592c02da3Sdan INSERT INTO t1 VALUES('c', 'd'); 8692c02da3Sdan } 8792c02da3Sdan file exists test.db-shm 8892c02da3Sdan } {1} 8992c02da3Sdan 90e9418778Sdan do_test $TN.1.2.1 { 91e9418778Sdan copy_to_test2 $bZeroShm 9292c02da3Sdan code1 { 9392c02da3Sdan sqlite3 db file:test.db2?readonly_shm=1 9492c02da3Sdan } 9592c02da3Sdan 9692c02da3Sdan sql1 { SELECT * FROM t1 } 9711caf4f4Sdan } {a b c d} 98e9418778Sdan do_test $TN.1.2.2 { 9911caf4f4Sdan sql1 { SELECT * FROM t1 } 10011caf4f4Sdan } {a b c d} 10192c02da3Sdan 102e9418778Sdan do_test $TN.1.3.1 { 10392c02da3Sdan code3 { sqlite3 db3 test.db2 } 10492c02da3Sdan sql3 { SELECT * FROM t1 } 10592c02da3Sdan } {a b c d} 10692c02da3Sdan 107e9418778Sdan do_test $TN.1.3.2 { 10892c02da3Sdan sql1 { SELECT * FROM t1 } 10992c02da3Sdan } {a b c d} 11092c02da3Sdan 111dea5ce36Sdan code1 { db close } 112dea5ce36Sdan code2 { db2 close } 113dea5ce36Sdan code3 { db3 close } 114dea5ce36Sdan 115e9418778Sdan do_test $TN.2.1 { 116dea5ce36Sdan code2 { sqlite3 db2 test.db } 117*d6b44ec3Sdrh sql2 "PRAGMA page_size=$::pgsz;" 118dea5ce36Sdan sql2 { 119dea5ce36Sdan INSERT INTO t1 VALUES('e', 'f'); 120dea5ce36Sdan INSERT INTO t1 VALUES('g', 'h'); 121dea5ce36Sdan } 122dea5ce36Sdan file exists test.db-shm 123dea5ce36Sdan } {1} 124dea5ce36Sdan 125e9418778Sdan do_test $TN.2.2 { 126e9418778Sdan copy_to_test2 $bZeroShm 127dea5ce36Sdan code1 { 128dea5ce36Sdan sqlite3 db file:test.db2?readonly_shm=1 129dea5ce36Sdan } 130dea5ce36Sdan sql1 { 131dea5ce36Sdan BEGIN; 132dea5ce36Sdan SELECT * FROM t1; 133dea5ce36Sdan } 13411caf4f4Sdan } {a b c d e f g h} 135dea5ce36Sdan 136e9418778Sdan do_test $TN.2.3.1 { 137dea5ce36Sdan code3 { sqlite3 db3 test.db2 } 138dea5ce36Sdan sql3 { SELECT * FROM t1 } 139dea5ce36Sdan } {a b c d e f g h} 140e9418778Sdan do_test $TN.2.3.2 { 14111caf4f4Sdan sql3 { INSERT INTO t1 VALUES('i', 'j') } 14211caf4f4Sdan code3 { db3 close } 14311caf4f4Sdan sql1 { COMMIT } 14411caf4f4Sdan } {} 145e9418778Sdan do_test $TN.2.3.3 { 14611caf4f4Sdan sql1 { SELECT * FROM t1 } 14711caf4f4Sdan } {a b c d e f g h i j} 148cbd33219Sdan 149cbd33219Sdan 150cbd33219Sdan #----------------------------------------------------------------------- 151cbd33219Sdan # 3.1.*: That a readonly_shm connection can read a database file if both 152cbd33219Sdan # the *-wal and *-shm files are zero bytes in size. 153cbd33219Sdan # 154cbd33219Sdan # 3.2.*: That it flushes the cache if, between transactions on a db with a 155cbd33219Sdan # zero byte *-wal file, some other connection modifies the db, then 156cbd33219Sdan # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file 157cbd33219Sdan # back to zero bytes in size. 158cbd33219Sdan # 159cbd33219Sdan # 3.3.*: That, if between transactions some other process wraps the wal 160cbd33219Sdan # file, the readonly_shm client reruns recovery. 161cbd33219Sdan # 162cbd33219Sdan catch { code1 { db close } } 163cbd33219Sdan catch { code2 { db2 close } } 164cbd33219Sdan catch { code3 { db3 close } } 165e9418778Sdan do_test $TN.3.1.0 { 166cbd33219Sdan list [file exists test.db-wal] [file exists test.db-shm] 167cbd33219Sdan } {0 0} 168e9418778Sdan do_test $TN.3.1.1 { 169cbd33219Sdan close [open test.db-wal w] 170cbd33219Sdan close [open test.db-shm w] 171cbd33219Sdan code1 { 172cbd33219Sdan sqlite3 db file:test.db?readonly_shm=1 173cbd33219Sdan } 174cbd33219Sdan sql1 { SELECT * FROM t1 } 175cbd33219Sdan } {a b c d e f g h} 176cbd33219Sdan 177e9418778Sdan do_test $TN.3.2.0 { 178cbd33219Sdan list [file size test.db-wal] [file size test.db-shm] 179cbd33219Sdan } {0 0} 180e9418778Sdan do_test $TN.3.2.1 { 181cbd33219Sdan code2 { sqlite3 db2 test.db } 182cbd33219Sdan sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } 183cbd33219Sdan code2 { db2 close } 184cbd33219Sdan sql1 { SELECT * FROM t1 } 185cbd33219Sdan } {a b c d e f g h 1 2} 186*d6b44ec3Sdrh if {$pgsz!=$dfltpgsz} continue 187e9418778Sdan do_test $TN.3.2.2 { 188cbd33219Sdan list [file size test.db-wal] [file size test.db-shm] 18960d72b9bSdan } [list 0 $MINSHMSZ] 190e9418778Sdan do_test $TN.3.3.0 { 191cbd33219Sdan code2 { sqlite3 db2 test.db } 192cbd33219Sdan sql2 { 193cbd33219Sdan INSERT INTO t1 VALUES(3, 4); 194cbd33219Sdan INSERT INTO t1 VALUES(5, 6); 195cbd33219Sdan INSERT INTO t1 VALUES(7, 8); 196cbd33219Sdan INSERT INTO t1 VALUES(9, 10); 197cbd33219Sdan } 198cbd33219Sdan code2 { db2 close } 199cbd33219Sdan code1 { db close } 200cbd33219Sdan list [file size test.db-wal] [file size test.db-shm] 20160d72b9bSdan } [list [wal_file_size 4 1024] $MINSHMSZ] 202e9418778Sdan do_test $TN.3.3.1 { 203cbd33219Sdan code1 { sqlite3 db file:test.db?readonly_shm=1 } 204cbd33219Sdan sql1 { SELECT * FROM t1 } 205cbd33219Sdan } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} 206e9418778Sdan do_test $TN.3.3.2 { 207cbd33219Sdan code2 { sqlite3 db2 test.db } 208cbd33219Sdan sql2 { 209cbd33219Sdan PRAGMA wal_checkpoint; 210cbd33219Sdan DELETE FROM t1; 211cbd33219Sdan INSERT INTO t1 VALUES('i', 'ii'); 212cbd33219Sdan } 213cbd33219Sdan code2 { db2 close } 214cbd33219Sdan list [file size test.db-wal] [file size test.db-shm] 21560d72b9bSdan } [list [wal_file_size 4 1024] $MINSHMSZ] 216e9418778Sdan do_test $TN.3.3.3 { 217cbd33219Sdan sql1 { SELECT * FROM t1 } 218cbd33219Sdan } {i ii} 219cbd33219Sdan 220ab548384Sdan #----------------------------------------------------------------------- 221ab548384Sdan # 222ab548384Sdan # 223ab548384Sdan catch { code1 { db close } } 224ab548384Sdan catch { code2 { db2 close } } 225ab548384Sdan catch { code3 { db3 close } } 226ab548384Sdan 227e9418778Sdan do_test $TN.4.0 { 228ab548384Sdan code1 { forcedelete test.db } 229ab548384Sdan code1 { sqlite3 db test.db } 230ab548384Sdan sql1 { 231ab548384Sdan PRAGMA journal_mode = wal; 232ab548384Sdan CREATE TABLE t1(x); 233ab548384Sdan INSERT INTO t1 VALUES('hello'); 234ab548384Sdan INSERT INTO t1 VALUES('world'); 235ab548384Sdan } 236ab548384Sdan 237e9418778Sdan copy_to_test2 $bZeroShm 238ab548384Sdan 239ab548384Sdan code1 { db close } 240ab548384Sdan } {} 241ab548384Sdan 242e9418778Sdan do_test $TN.4.1.1 { 243ab548384Sdan code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } 244ab548384Sdan sql2 { SELECT * FROM t1 } 245ab548384Sdan } {hello world} 246ab548384Sdan 247e9418778Sdan do_test $TN.4.1.2 { 248ab548384Sdan code3 { sqlite3 db3 test.db2 } 249ab548384Sdan sql3 { 250ab548384Sdan INSERT INTO t1 VALUES('!'); 251ab548384Sdan PRAGMA wal_checkpoint = truncate; 252ab548384Sdan } 253ab548384Sdan code3 { db3 close } 254ab548384Sdan } {} 255e9418778Sdan do_test $TN.4.1.3 { 256ab548384Sdan sql2 { SELECT * FROM t1 } 257ab548384Sdan } {hello world !} 258ab548384Sdan 259ab548384Sdan catch { code1 { db close } } 260ab548384Sdan catch { code2 { db2 close } } 261ab548384Sdan catch { code3 { db3 close } } 262ab548384Sdan 263e9418778Sdan do_test $TN.4.2.1 { 264ab548384Sdan code1 { sqlite3 db test.db } 265ab548384Sdan sql1 { 266ab548384Sdan INSERT INTO t1 VALUES('!'); 267ab548384Sdan INSERT INTO t1 VALUES('!'); 268ab548384Sdan 269ab548384Sdan PRAGMA cache_size = 10; 270ab548384Sdan CREATE TABLE t2(x); 271ab548384Sdan 272ab548384Sdan BEGIN; 273ab548384Sdan WITH s(i) AS ( 274ab548384Sdan SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 275ab548384Sdan ) 276ab548384Sdan INSERT INTO t2 SELECT randomblob(500) FROM s; 277ab548384Sdan SELECT count(*) FROM t2; 278ab548384Sdan } 279ab548384Sdan } {500} 28092b67025Sdan set sz [file size test.db-wal] 2813a9b9b77Sdan do_test $TN.4.2.2.(sz=$sz) { 2823a9b9b77Sdan expr {$sz>400000} 28392b67025Sdan } {1} 284e9418778Sdan do_test $TN.4.2.4 { 285bcb416a9Smistachkin file_control_persist_wal db 1; db close 286bcb416a9Smistachkin 287e9418778Sdan copy_to_test2 $bZeroShm 288ab548384Sdan code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } 289ab548384Sdan sql2 { 290ab548384Sdan SELECT * FROM t1; 291ab548384Sdan SELECT count(*) FROM t2; 292ab548384Sdan } 293ab548384Sdan } {hello world ! ! 0} 294ab548384Sdan 295ab548384Sdan #----------------------------------------------------------------------- 296ab548384Sdan # 297ab548384Sdan # 298ab548384Sdan catch { code1 { db close } } 299ab548384Sdan catch { code2 { db2 close } } 300ab548384Sdan catch { code3 { db3 close } } 301ab548384Sdan 302e9418778Sdan do_test $TN.5.0 { 303ab548384Sdan code1 { forcedelete test.db } 304ab548384Sdan code1 { sqlite3 db test.db } 305ab548384Sdan sql1 { 306ab548384Sdan PRAGMA journal_mode = wal; 307ab548384Sdan CREATE TABLE t1(x); 308ab548384Sdan INSERT INTO t1 VALUES('hello'); 309ab548384Sdan INSERT INTO t1 VALUES('world'); 310ab548384Sdan INSERT INTO t1 VALUES('!'); 311ab548384Sdan INSERT INTO t1 VALUES('world'); 312ab548384Sdan INSERT INTO t1 VALUES('hello'); 313ab548384Sdan } 314ab548384Sdan 315e9418778Sdan copy_to_test2 $bZeroShm 316ab548384Sdan 317ab548384Sdan code1 { db close } 318ab548384Sdan } {} 319ab548384Sdan 320e9418778Sdan do_test $TN.5.1 { 321ab548384Sdan code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } 322ab548384Sdan sql2 { 323ab548384Sdan SELECT * FROM t1; 324ab548384Sdan } 325ab548384Sdan } {hello world ! world hello} 326ab548384Sdan 327e9418778Sdan do_test $TN.5.2 { 328ab548384Sdan code1 { 329ab548384Sdan proc handle_read {op args} { 330ab548384Sdan if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { 331ab548384Sdan set ::res2 [sql2 { SELECT * FROM t1 }] 332ab548384Sdan } 333ab548384Sdan puts "$msg xRead $args" 334ab548384Sdan return "SQLITE_OK" 335ab548384Sdan } 336ab548384Sdan testvfs tvfs -fullshm 1 337ab548384Sdan 338ab548384Sdan sqlite3 db file:test.db2?vfs=tvfs 339ab548384Sdan db eval { SELECT * FROM sqlite_master } 340ab548384Sdan 341ab548384Sdan tvfs filter xRead 342ab548384Sdan tvfs script handle_read 343ab548384Sdan } 344ab548384Sdan sql1 { 345ab548384Sdan PRAGMA wal_checkpoint = truncate; 346ab548384Sdan } 347ab548384Sdan code1 { set ::res2 } 348ab548384Sdan } {hello world ! world hello} 349ab548384Sdan 350e9418778Sdan do_test $TN.5.3 { 351ab548384Sdan code1 { db close } 352ab548384Sdan code1 { tvfs delete } 353ab548384Sdan } {} 354ab548384Sdan 35508ecefc5Sdan #----------------------------------------------------------------------- 35608ecefc5Sdan # 35708ecefc5Sdan # 35808ecefc5Sdan catch { code1 { db close } } 35908ecefc5Sdan catch { code2 { db2 close } } 36008ecefc5Sdan catch { code3 { db3 close } } 361ab548384Sdan 362e9418778Sdan do_test $TN.6.1 { 36308ecefc5Sdan code1 { forcedelete test.db } 36408ecefc5Sdan code1 { sqlite3 db test.db } 36508ecefc5Sdan sql1 { 36608ecefc5Sdan PRAGMA journal_mode = wal; 36708ecefc5Sdan CREATE TABLE t1(x); 36808ecefc5Sdan INSERT INTO t1 VALUES('hello'); 36908ecefc5Sdan INSERT INTO t1 VALUES('world'); 37008ecefc5Sdan INSERT INTO t1 VALUES('!'); 37108ecefc5Sdan INSERT INTO t1 VALUES('world'); 37208ecefc5Sdan INSERT INTO t1 VALUES('hello'); 37308ecefc5Sdan } 37408ecefc5Sdan 375e9418778Sdan copy_to_test2 $bZeroShm 37608ecefc5Sdan 37708ecefc5Sdan code1 { db close } 37808ecefc5Sdan } {} 37908ecefc5Sdan 380e9418778Sdan do_test $TN.6.2 { 38108ecefc5Sdan code1 { 38208ecefc5Sdan set ::nRem 5 38308ecefc5Sdan proc handle_read {op args} { 38408ecefc5Sdan if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { 38508ecefc5Sdan incr ::nRem -1 38608ecefc5Sdan if {$::nRem==0} { 38708ecefc5Sdan code2 { sqlite3 db2 test.db2 } 38808ecefc5Sdan sql2 { PRAGMA wal_checkpoint = truncate } 38908ecefc5Sdan } 39008ecefc5Sdan } 39108ecefc5Sdan return "SQLITE_OK" 39208ecefc5Sdan } 39308ecefc5Sdan testvfs tvfs -fullshm 1 39408ecefc5Sdan 39508ecefc5Sdan tvfs filter xRead 39608ecefc5Sdan tvfs script handle_read 39708ecefc5Sdan 39808ecefc5Sdan sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs 39908ecefc5Sdan db eval { SELECT * FROM t1 } 40008ecefc5Sdan } 40108ecefc5Sdan } {hello world ! world hello} 40208ecefc5Sdan 403e9418778Sdan do_test $TN.6.3 { 40408ecefc5Sdan code1 { db close } 40508ecefc5Sdan code1 { tvfs delete } 40608ecefc5Sdan } {} 40792c02da3Sdan } 408*d6b44ec3Sdrh } ;# for pgsz 409e9418778Sdan} ;# foreach bZeroShm 41092c02da3Sdan 41192c02da3Sdanfinish_test 412