3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
12 # This file contains tests for using WAL databases in read-only mode.
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
17 source $testdir/lock_common.tcl
18 source $testdir/wal_common.tcl
19 set ::testprefix walro2
21 # And only if the build is WAL-capable.
28 proc copy_to_test2 {bZeroShm} {
29 forcecopy test.db test.db2
30 forcecopy test.db-wal test.db2-wal
32 forcedelete test.db2-shm
33 set fd [open test.db2-shm w]
34 seek $fd [expr [file size test.db-shm]-1]
35 puts -nonewline $fd "\0"
38 forcecopy test.db-shm test.db2-shm
42 foreach bZeroShm {0 1} {
43 set TN [expr $bZeroShm+1]
44 do_multiclient_test tn {
46 # Close all connections and delete the database.
53 # Do not run tests with the connections in the same process.
57 foreach c {code1 code2 code3} {
65 code2 { sqlite3 db2 test.db }
67 CREATE TABLE t1(x, y);
68 PRAGMA journal_mode = WAL;
69 INSERT INTO t1 VALUES('a', 'b');
70 INSERT INTO t1 VALUES('c', 'd');
72 file exists test.db-shm
76 copy_to_test2 $bZeroShm
78 sqlite3 db file:test.db2?readonly_shm=1
81 sql1 { SELECT * FROM t1 }
84 sql1 { SELECT * FROM t1 }
88 code3 { sqlite3 db3 test.db2 }
89 sql3 { SELECT * FROM t1 }
93 sql1 { SELECT * FROM t1 }
101 code2 { sqlite3 db2 test.db }
103 INSERT INTO t1 VALUES('e', 'f');
104 INSERT INTO t1 VALUES('g', 'h');
106 file exists test.db-shm
110 copy_to_test2 $bZeroShm
112 sqlite3 db file:test.db2?readonly_shm=1
121 code3 { sqlite3 db3 test.db2 }
122 sql3 { SELECT * FROM t1 }
125 sql3 { INSERT INTO t1 VALUES('i', 'j') }
130 sql1 { SELECT * FROM t1 }
131 } {a b c d e f g h i j}
134 #-----------------------------------------------------------------------
135 # 3.1.*: That a readonly_shm connection can read a database file if both
136 # the *-wal and *-shm files are zero bytes in size.
138 # 3.2.*: That it flushes the cache if, between transactions on a db with a
139 # zero byte *-wal file, some other connection modifies the db, then
140 # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file
141 # back to zero bytes in size.
143 # 3.3.*: That, if between transactions some other process wraps the wal
144 # file, the readonly_shm client reruns recovery.
146 catch { code1 { db close } }
147 catch { code2 { db2 close } }
148 catch { code3 { db3 close } }
150 list [file exists test.db-wal] [file exists test.db-shm]
153 close [open test.db-wal w]
154 close [open test.db-shm w]
156 sqlite3 db file:test.db?readonly_shm=1
158 sql1 { SELECT * FROM t1 }
162 list [file size test.db-wal] [file size test.db-shm]
165 code2 { sqlite3 db2 test.db }
166 sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate }
168 sql1 { SELECT * FROM t1 }
169 } {a b c d e f g h 1 2}
171 list [file size test.db-wal] [file size test.db-shm]
175 code2 { sqlite3 db2 test.db }
177 INSERT INTO t1 VALUES(3, 4);
178 INSERT INTO t1 VALUES(5, 6);
179 INSERT INTO t1 VALUES(7, 8);
180 INSERT INTO t1 VALUES(9, 10);
184 list [file size test.db-wal] [file size test.db-shm]
185 } [list [wal_file_size 4 1024] 32768]
187 code1 { sqlite3 db file:test.db?readonly_shm=1 }
188 sql1 { SELECT * FROM t1 }
189 } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10}
191 code2 { sqlite3 db2 test.db }
193 PRAGMA wal_checkpoint;
195 INSERT INTO t1 VALUES('i', 'ii');
198 list [file size test.db-wal] [file size test.db-shm]
199 } [list [wal_file_size 4 1024] 32768]
201 sql1 { SELECT * FROM t1 }
204 #-----------------------------------------------------------------------
207 catch { code1 { db close } }
208 catch { code2 { db2 close } }
209 catch { code3 { db3 close } }
212 code1 { forcedelete test.db }
213 code1 { sqlite3 db test.db }
215 PRAGMA journal_mode = wal;
217 INSERT INTO t1 VALUES('hello');
218 INSERT INTO t1 VALUES('world');
221 copy_to_test2 $bZeroShm
227 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
228 sql2 { SELECT * FROM t1 }
232 code3 { sqlite3 db3 test.db2 }
234 INSERT INTO t1 VALUES('!');
235 PRAGMA wal_checkpoint = truncate;
240 sql2 { SELECT * FROM t1 }
243 catch { code1 { db close } }
244 catch { code2 { db2 close } }
245 catch { code3 { db3 close } }
248 code1 { sqlite3 db test.db }
250 INSERT INTO t1 VALUES('!');
251 INSERT INTO t1 VALUES('!');
253 PRAGMA cache_size = 10;
258 SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
260 INSERT INTO t2 SELECT randomblob(500) FROM s;
261 SELECT count(*) FROM t2;
265 set sz [file size test.db-wal]
266 expr {$sz>400000 && $sz<500000}
269 file_control_persist_wal db 1; db close
271 copy_to_test2 $bZeroShm
272 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
275 SELECT count(*) FROM t2;
277 } {hello world ! ! 0}
279 #-----------------------------------------------------------------------
282 catch { code1 { db close } }
283 catch { code2 { db2 close } }
284 catch { code3 { db3 close } }
287 code1 { forcedelete test.db }
288 code1 { sqlite3 db test.db }
290 PRAGMA journal_mode = wal;
292 INSERT INTO t1 VALUES('hello');
293 INSERT INTO t1 VALUES('world');
294 INSERT INTO t1 VALUES('!');
295 INSERT INTO t1 VALUES('world');
296 INSERT INTO t1 VALUES('hello');
299 copy_to_test2 $bZeroShm
305 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
309 } {hello world ! world hello}
313 proc handle_read {op args} {
314 if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
315 set ::res2 [sql2 { SELECT * FROM t1 }]
317 puts "$msg xRead $args"
320 testvfs tvfs -fullshm 1
322 sqlite3 db file:test.db2?vfs=tvfs
323 db eval { SELECT * FROM sqlite_master }
326 tvfs script handle_read
329 PRAGMA wal_checkpoint = truncate;
332 } {hello world ! world hello}
336 code1 { tvfs delete }
339 #-----------------------------------------------------------------------
342 catch { code1 { db close } }
343 catch { code2 { db2 close } }
344 catch { code3 { db3 close } }
347 code1 { forcedelete test.db }
348 code1 { sqlite3 db test.db }
350 PRAGMA journal_mode = wal;
352 INSERT INTO t1 VALUES('hello');
353 INSERT INTO t1 VALUES('world');
354 INSERT INTO t1 VALUES('!');
355 INSERT INTO t1 VALUES('world');
356 INSERT INTO t1 VALUES('hello');
359 copy_to_test2 $bZeroShm
367 proc handle_read {op args} {
368 if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
371 code2 { sqlite3 db2 test.db2 }
372 sql2 { PRAGMA wal_checkpoint = truncate }
377 testvfs tvfs -fullshm 1
380 tvfs script handle_read
382 sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs
383 db eval { SELECT * FROM t1 }
385 } {hello world ! world hello}
389 code1 { tvfs delete }
392 } ;# foreach bZeroShm