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 # Most systems allocate the *-shm file in 32KB trunks. But on UNIX systems
43 # for which the getpagesize() call returns greater than 32K, the *-shm
44 # file is allocated in page-sized units (since you cannot mmap part of
45 # a page). The following code sets variable $MINSHMSZ to the smallest
46 # possible *-shm file (i.e. the greater of 32KB and the system page-size).
49 PRAGMA journal_mode = wal;
52 set MINSHMSZ [file size test.db-shm]
54 foreach bZeroShm {0 1} {
55 set TN [expr $bZeroShm+1]
56 do_multiclient_test tn {
58 # Close all connections and delete the database.
65 # Do not run tests with the connections in the same process.
69 foreach c {code1 code2 code3} {
77 code2 { sqlite3 db2 test.db }
79 CREATE TABLE t1(x, y);
80 PRAGMA journal_mode = WAL;
81 INSERT INTO t1 VALUES('a', 'b');
82 INSERT INTO t1 VALUES('c', 'd');
84 file exists test.db-shm
88 copy_to_test2 $bZeroShm
90 sqlite3 db file:test.db2?readonly_shm=1
93 sql1 { SELECT * FROM t1 }
96 sql1 { SELECT * FROM t1 }
100 code3 { sqlite3 db3 test.db2 }
101 sql3 { SELECT * FROM t1 }
105 sql1 { SELECT * FROM t1 }
113 code2 { sqlite3 db2 test.db }
115 INSERT INTO t1 VALUES('e', 'f');
116 INSERT INTO t1 VALUES('g', 'h');
118 file exists test.db-shm
122 copy_to_test2 $bZeroShm
124 sqlite3 db file:test.db2?readonly_shm=1
133 code3 { sqlite3 db3 test.db2 }
134 sql3 { SELECT * FROM t1 }
137 sql3 { INSERT INTO t1 VALUES('i', 'j') }
142 sql1 { SELECT * FROM t1 }
143 } {a b c d e f g h i j}
146 #-----------------------------------------------------------------------
147 # 3.1.*: That a readonly_shm connection can read a database file if both
148 # the *-wal and *-shm files are zero bytes in size.
150 # 3.2.*: That it flushes the cache if, between transactions on a db with a
151 # zero byte *-wal file, some other connection modifies the db, then
152 # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file
153 # back to zero bytes in size.
155 # 3.3.*: That, if between transactions some other process wraps the wal
156 # file, the readonly_shm client reruns recovery.
158 catch { code1 { db close } }
159 catch { code2 { db2 close } }
160 catch { code3 { db3 close } }
162 list [file exists test.db-wal] [file exists test.db-shm]
165 close [open test.db-wal w]
166 close [open test.db-shm w]
168 sqlite3 db file:test.db?readonly_shm=1
170 sql1 { SELECT * FROM t1 }
174 list [file size test.db-wal] [file size test.db-shm]
177 code2 { sqlite3 db2 test.db }
178 sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate }
180 sql1 { SELECT * FROM t1 }
181 } {a b c d e f g h 1 2}
183 list [file size test.db-wal] [file size test.db-shm]
187 code2 { sqlite3 db2 test.db }
189 INSERT INTO t1 VALUES(3, 4);
190 INSERT INTO t1 VALUES(5, 6);
191 INSERT INTO t1 VALUES(7, 8);
192 INSERT INTO t1 VALUES(9, 10);
196 list [file size test.db-wal] [file size test.db-shm]
197 } [list [wal_file_size 4 1024] $MINSHMSZ]
199 code1 { sqlite3 db file:test.db?readonly_shm=1 }
200 sql1 { SELECT * FROM t1 }
201 } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10}
203 code2 { sqlite3 db2 test.db }
205 PRAGMA wal_checkpoint;
207 INSERT INTO t1 VALUES('i', 'ii');
210 list [file size test.db-wal] [file size test.db-shm]
211 } [list [wal_file_size 4 1024] $MINSHMSZ]
213 sql1 { SELECT * FROM t1 }
216 #-----------------------------------------------------------------------
219 catch { code1 { db close } }
220 catch { code2 { db2 close } }
221 catch { code3 { db3 close } }
224 code1 { forcedelete test.db }
225 code1 { sqlite3 db test.db }
227 PRAGMA journal_mode = wal;
229 INSERT INTO t1 VALUES('hello');
230 INSERT INTO t1 VALUES('world');
233 copy_to_test2 $bZeroShm
239 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
240 sql2 { SELECT * FROM t1 }
244 code3 { sqlite3 db3 test.db2 }
246 INSERT INTO t1 VALUES('!');
247 PRAGMA wal_checkpoint = truncate;
252 sql2 { SELECT * FROM t1 }
255 catch { code1 { db close } }
256 catch { code2 { db2 close } }
257 catch { code3 { db3 close } }
260 code1 { sqlite3 db test.db }
262 INSERT INTO t1 VALUES('!');
263 INSERT INTO t1 VALUES('!');
265 PRAGMA cache_size = 10;
270 SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
272 INSERT INTO t2 SELECT randomblob(500) FROM s;
273 SELECT count(*) FROM t2;
276 set sz [file size test.db-wal]
277 do_test $TN.4.2.2.(sz=$sz) {
281 file_control_persist_wal db 1; db close
283 copy_to_test2 $bZeroShm
284 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
287 SELECT count(*) FROM t2;
289 } {hello world ! ! 0}
291 #-----------------------------------------------------------------------
294 catch { code1 { db close } }
295 catch { code2 { db2 close } }
296 catch { code3 { db3 close } }
299 code1 { forcedelete test.db }
300 code1 { sqlite3 db test.db }
302 PRAGMA journal_mode = wal;
304 INSERT INTO t1 VALUES('hello');
305 INSERT INTO t1 VALUES('world');
306 INSERT INTO t1 VALUES('!');
307 INSERT INTO t1 VALUES('world');
308 INSERT INTO t1 VALUES('hello');
311 copy_to_test2 $bZeroShm
317 code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
321 } {hello world ! world hello}
325 proc handle_read {op args} {
326 if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
327 set ::res2 [sql2 { SELECT * FROM t1 }]
329 puts "$msg xRead $args"
332 testvfs tvfs -fullshm 1
334 sqlite3 db file:test.db2?vfs=tvfs
335 db eval { SELECT * FROM sqlite_master }
338 tvfs script handle_read
341 PRAGMA wal_checkpoint = truncate;
344 } {hello world ! world hello}
348 code1 { tvfs delete }
351 #-----------------------------------------------------------------------
354 catch { code1 { db close } }
355 catch { code2 { db2 close } }
356 catch { code3 { db3 close } }
359 code1 { forcedelete test.db }
360 code1 { sqlite3 db test.db }
362 PRAGMA journal_mode = wal;
364 INSERT INTO t1 VALUES('hello');
365 INSERT INTO t1 VALUES('world');
366 INSERT INTO t1 VALUES('!');
367 INSERT INTO t1 VALUES('world');
368 INSERT INTO t1 VALUES('hello');
371 copy_to_test2 $bZeroShm
379 proc handle_read {op args} {
380 if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
383 code2 { sqlite3 db2 test.db2 }
384 sql2 { PRAGMA wal_checkpoint = truncate }
389 testvfs tvfs -fullshm 1
392 tvfs script handle_read
394 sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs
395 db eval { SELECT * FROM t1 }
397 } {hello world ! world hello}
401 code1 { tvfs delete }
404 } ;# foreach bZeroShm