xref: /sqlite-3.40.0/test/walro2.test (revision d6b44ec3)
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