fix conversion back to original journal_mode after migration
[sqlcipher.git] / test / walro2.test
blob34408c16954ce6d0f652ee7cb96d4605ce59584a
1 # 2011 May 09
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.
23 ifcapable !wal {
24   finish_test
25   return
28 proc copy_to_test2 {bZeroShm} {
29   forcecopy test.db test.db2
30   forcecopy test.db-wal test.db2-wal
31   if {$bZeroShm} {
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"
36     close $fd
37   } else {
38     forcecopy test.db-shm test.db2-shm
39   }
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).
48 do_execsql_test 0.0 {
49   PRAGMA journal_mode = wal;
50   CREATE TABLE t1(x);
51 } {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 {
57   
58   # Close all connections and delete the database.
59   #
60   code1 { db close  }
61   code2 { db2 close }
62   code3 { db3 close }
63   forcedelete test.db
64   
65   # Do not run tests with the connections in the same process.
66   #
67   if {$tn==2} continue
69   foreach c {code1 code2 code3} {
70     $c {
71       sqlite3_shutdown
72       sqlite3_config_uri 1
73     }
74   }
76   do_test $TN.1.1 {
77     code2 { sqlite3 db2 test.db }
78     sql2 { 
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');
83     }
84     file exists test.db-shm
85   } {1}
87   do_test $TN.1.2.1 {
88     copy_to_test2 $bZeroShm
89     code1 {
90       sqlite3 db file:test.db2?readonly_shm=1
91     }
93     sql1 { SELECT * FROM t1 }
94   } {a b c d}
95   do_test $TN.1.2.2 {
96     sql1 { SELECT * FROM t1 }
97   } {a b c d}
99   do_test $TN.1.3.1 {
100     code3 { sqlite3 db3 test.db2 }
101     sql3 { SELECT * FROM t1 }
102   } {a b c d}
104   do_test $TN.1.3.2 {
105     sql1 { SELECT * FROM t1 }
106   } {a b c d}
108   code1 { db close  }
109   code2 { db2 close }
110   code3 { db3 close }
112   do_test $TN.2.1 {
113     code2 { sqlite3 db2 test.db }
114     sql2 { 
115       INSERT INTO t1 VALUES('e', 'f');
116       INSERT INTO t1 VALUES('g', 'h');
117     }
118     file exists test.db-shm
119   } {1}
121   do_test $TN.2.2 {
122     copy_to_test2 $bZeroShm
123     code1 {
124       sqlite3 db file:test.db2?readonly_shm=1
125     }
126     sql1 { 
127       BEGIN;
128       SELECT * FROM t1;
129     }
130   } {a b c d e f g h}
132   do_test $TN.2.3.1 {
133     code3 { sqlite3 db3 test.db2 }
134     sql3 { SELECT * FROM t1 }
135   } {a b c d e f g h}
136   do_test $TN.2.3.2 {
137     sql3 { INSERT INTO t1 VALUES('i', 'j') }
138     code3 { db3 close }
139     sql1 { COMMIT } 
140   } {}
141   do_test $TN.2.3.3 {
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.
149   #
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.
154   #
155   # 3.3.*: That, if between transactions some other process wraps the wal
156   #        file, the readonly_shm client reruns recovery.
157   #
158   catch { code1 { db close } }
159   catch { code2 { db2 close } }
160   catch { code3 { db3 close } }
161   do_test $TN.3.1.0 {
162     list [file exists test.db-wal] [file exists test.db-shm]
163   } {0 0}
164   do_test $TN.3.1.1 {
165     close [open test.db-wal w]
166     close [open test.db-shm w]
167     code1 {
168       sqlite3 db file:test.db?readonly_shm=1
169     }
170     sql1 { SELECT * FROM t1 }
171   } {a b c d e f g h}
173   do_test $TN.3.2.0 {
174     list [file size test.db-wal] [file size test.db-shm]
175   } {0 0}
176   do_test $TN.3.2.1 {
177     code2 { sqlite3 db2 test.db }
178     sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate }
179     code2 { db2 close }
180     sql1 { SELECT * FROM t1 }
181   } {a b c d e f g h 1 2}
182   do_test $TN.3.2.2 {
183     list [file size test.db-wal] [file size test.db-shm]
184   } [list 0 $MINSHMSZ]
186   do_test $TN.3.3.0 {
187     code2 { sqlite3 db2 test.db }
188     sql2 { 
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);
193     }
194     code2 { db2 close }
195     code1 { db close }
196     list [file size test.db-wal] [file size test.db-shm]
197   } [list [wal_file_size 4 1024] $MINSHMSZ]
198   do_test $TN.3.3.1 {
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}
202   do_test $TN.3.3.2 {
203     code2 { sqlite3 db2 test.db }
204     sql2 { 
205       PRAGMA wal_checkpoint; 
206       DELETE FROM t1;
207       INSERT INTO t1 VALUES('i', 'ii');
208     }
209     code2 { db2 close }
210     list [file size test.db-wal] [file size test.db-shm]
211   } [list [wal_file_size 4 1024] $MINSHMSZ]
212   do_test $TN.3.3.3 {
213     sql1 { SELECT * FROM t1 }
214   } {i ii}
216   #-----------------------------------------------------------------------
217   #
218   #
219   catch { code1 { db close } }
220   catch { code2 { db2 close } }
221   catch { code3 { db3 close } }
223   do_test $TN.4.0 {
224     code1 { forcedelete test.db }
225     code1 { sqlite3 db test.db }
226     sql1 {
227       PRAGMA journal_mode = wal;
228       CREATE TABLE t1(x);
229       INSERT INTO t1 VALUES('hello');
230       INSERT INTO t1 VALUES('world');
231     }
233     copy_to_test2 $bZeroShm
235     code1 { db close }
236   } {}
238   do_test $TN.4.1.1 {
239     code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
240     sql2 { SELECT * FROM t1 }
241   } {hello world}
243   do_test $TN.4.1.2 {
244     code3 { sqlite3 db3 test.db2 }
245     sql3 {
246       INSERT INTO t1 VALUES('!');
247       PRAGMA wal_checkpoint = truncate;
248     }
249     code3 { db3 close }
250   } {}
251   do_test $TN.4.1.3 {
252     sql2 { SELECT * FROM t1 }
253   } {hello world !}
255   catch { code1 { db close } }
256   catch { code2 { db2 close } }
257   catch { code3 { db3 close } }
259   do_test $TN.4.2.1 {
260     code1 { sqlite3 db test.db }
261     sql1 {
262       INSERT INTO t1 VALUES('!');
263       INSERT INTO t1 VALUES('!');
265       PRAGMA cache_size = 10;
266       CREATE TABLE t2(x);
268       BEGIN;
269         WITH s(i) AS (
270           SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
271           )
272         INSERT INTO t2 SELECT randomblob(500) FROM s;
273         SELECT count(*) FROM t2;
274     } 
275   } {500}
276   set sz [file size test.db-wal]
277   do_test $TN.4.2.2.(sz=$sz) {
278     expr {$sz>400000}
279   } {1}
280   do_test $TN.4.2.4 {
281     file_control_persist_wal db 1; db close
283     copy_to_test2 $bZeroShm
284     code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
285     sql2 {
286       SELECT * FROM t1;
287       SELECT count(*) FROM t2;
288     }
289   } {hello world ! ! 0}
291   #-----------------------------------------------------------------------
292   #
293   #
294   catch { code1 { db close } }
295   catch { code2 { db2 close } }
296   catch { code3 { db3 close } }
298   do_test $TN.5.0 {
299     code1 { forcedelete test.db }
300     code1 { sqlite3 db test.db }
301     sql1 {
302       PRAGMA journal_mode = wal;
303       CREATE TABLE t1(x);
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');
309     }
311     copy_to_test2 $bZeroShm
312     
313     code1 { db close }
314   } {}
316   do_test $TN.5.1 {
317     code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
318     sql2 {
319       SELECT * FROM t1;
320     }
321   } {hello world ! world hello}
323   do_test $TN.5.2 {
324     code1 {
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 }]
328         }
329         puts "$msg xRead $args"
330         return "SQLITE_OK"
331       }
332       testvfs tvfs -fullshm 1
334       sqlite3 db file:test.db2?vfs=tvfs
335       db eval { SELECT * FROM sqlite_master }
337       tvfs filter xRead
338       tvfs script handle_read
339     }
340     sql1 {
341       PRAGMA wal_checkpoint = truncate;
342     }
343     code1 { set ::res2 }
344   } {hello world ! world hello}
346   do_test $TN.5.3 {
347     code1 { db close }
348     code1 { tvfs delete }
349   } {}
351   #-----------------------------------------------------------------------
352   #
353   #
354   catch { code1 { db close } }
355   catch { code2 { db2 close } }
356   catch { code3 { db3 close } }
358   do_test $TN.6.1 {
359     code1 { forcedelete test.db }
360     code1 { sqlite3 db test.db }
361     sql1 {
362       PRAGMA journal_mode = wal;
363       CREATE TABLE t1(x);
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');
369     }
371     copy_to_test2 $bZeroShm
372     
373     code1 { db close }
374   } {}
376   do_test $TN.6.2 {
377     code1 {
378       set ::nRem 5
379       proc handle_read {op args} {
380         if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
381           incr ::nRem -1
382           if {$::nRem==0} {
383             code2 { sqlite3 db2 test.db2 }
384             sql2  { PRAGMA wal_checkpoint = truncate }
385           }
386         }
387         return "SQLITE_OK"
388       }
389       testvfs tvfs -fullshm 1
391       tvfs filter xRead
392       tvfs script handle_read
394       sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs
395       db eval { SELECT * FROM t1 }
396     }
397   } {hello world ! world hello}
399   do_test $TN.6.3 {
400     code1 { db close }
401     code1 { tvfs delete }
402   } {}
404 } ;# foreach bZeroShm
406 finish_test