xref: /sqlite-3.40.0/test/wal2.test (revision cddfc392)
19a6b4e9aSdan# 2010 May 5
29a6b4e9aSdan#
39a6b4e9aSdan# The author disclaims copyright to this source code.  In place of
49a6b4e9aSdan# a legal notice, here is a blessing:
59a6b4e9aSdan#
69a6b4e9aSdan#    May you do good and not evil.
79a6b4e9aSdan#    May you find forgiveness for yourself and forgive others.
89a6b4e9aSdan#    May you share freely, never taking more than you give.
99a6b4e9aSdan#
109a6b4e9aSdan#***********************************************************************
119a6b4e9aSdan# This file implements regression tests for SQLite library.  The
129a6b4e9aSdan# focus of this file is testing the operation of the library in
139a6b4e9aSdan# "PRAGMA journal_mode=WAL" mode.
149a6b4e9aSdan#
159a6b4e9aSdan
169a6b4e9aSdanset testdir [file dirname $argv0]
179a6b4e9aSdansource $testdir/tester.tcl
189a6b4e9aSdansource $testdir/lock_common.tcl
1910f5a50eSdansource $testdir/malloc_common.tcl
2010f5a50eSdansource $testdir/wal_common.tcl
2110f5a50eSdan
2218826195Sdanset testprefix wal2
2318826195Sdan
249a6b4e9aSdanifcapable !wal {finish_test ; return }
259a6b4e9aSdan
269dd6e080Sshanehset sqlite_sync_count 0
279dd6e080Sshanehproc cond_incr_sync_count {adj} {
289dd6e080Sshaneh  global sqlite_sync_count
299dd6e080Sshaneh  if {$::tcl_platform(platform) == "windows"} {
309dd6e080Sshaneh    incr sqlite_sync_count $adj
319dd6e080Sshaneh  } {
329dd6e080Sshaneh    ifcapable !dirsync {
339dd6e080Sshaneh      incr sqlite_sync_count $adj
349dd6e080Sshaneh    }
359dd6e080Sshaneh  }
369dd6e080Sshaneh}
379dd6e080Sshaneh
389a6b4e9aSdanproc set_tvfs_hdr {file args} {
3971d89919Sdan
4071d89919Sdan  # Set $nHdr to the number of bytes in the wal-index header:
4110f5a50eSdan  set nHdr 48
4271d89919Sdan  set nInt [expr {$nHdr/4}]
4371d89919Sdan
4423f71920Sdan  if {[llength $args]>2} {
4523f71920Sdan    error {wrong # args: should be "set_tvfs_hdr fileName ?val1? ?val2?"}
469a6b4e9aSdan  }
479a6b4e9aSdan
489a6b4e9aSdan  set blob [tvfs shm $file]
49957ed0b3Sdrh  if {$::tcl_platform(byteOrder)=="bigEndian"} {set fmt I} {set fmt i}
50d0aa3427Sdan
519a6b4e9aSdan  if {[llength $args]} {
5294b7f76bSdan    set ia [lindex $args 0]
5323f71920Sdan    set ib $ia
5423f71920Sdan    if {[llength $args]==2} {
5523f71920Sdan      set ib [lindex $args 1]
5623f71920Sdan    }
57d0aa3427Sdan    binary scan $blob a[expr $nHdr*2]a* dummy tail
58957ed0b3Sdrh    set blob [binary format ${fmt}${nInt}${fmt}${nInt}a* $ia $ib $tail]
599a6b4e9aSdan    tvfs shm $file $blob
609a6b4e9aSdan  }
619a6b4e9aSdan
62957ed0b3Sdrh  binary scan $blob ${fmt}${nInt} ints
639a6b4e9aSdan  return $ints
649a6b4e9aSdan}
659a6b4e9aSdan
669a6b4e9aSdanproc incr_tvfs_hdr {file idx incrval} {
679a6b4e9aSdan  set ints [set_tvfs_hdr $file]
689a6b4e9aSdan  set v [lindex $ints $idx]
699a6b4e9aSdan  incr v $incrval
709a6b4e9aSdan  lset ints $idx $v
719a6b4e9aSdan  set_tvfs_hdr $file $ints
729a6b4e9aSdan}
739a6b4e9aSdan
749a6b4e9aSdan
759a6b4e9aSdan#-------------------------------------------------------------------------
769a6b4e9aSdan# Test case wal2-1.*:
779a6b4e9aSdan#
789a6b4e9aSdan# Set up a small database containing a single table. The database is not
799a6b4e9aSdan# checkpointed during the test - all content resides in the log file.
809a6b4e9aSdan#
819a6b4e9aSdan# Two connections are established to the database file - a writer ([db])
829a6b4e9aSdan# and a reader ([db2]). For each of the 8 integer fields in the wal-index
839a6b4e9aSdan# header (6 fields and 2 checksum values), do the following:
849a6b4e9aSdan#
859a6b4e9aSdan#   1. Modify the database using the writer.
869a6b4e9aSdan#
879a6b4e9aSdan#   2. Attempt to read the database using the reader. Before the reader
889a6b4e9aSdan#      has a chance to snapshot the wal-index header, increment one
89d5578433Smistachkin#      of the integer fields (so that the reader ends up with a corrupted
909a6b4e9aSdan#      header).
919a6b4e9aSdan#
929a6b4e9aSdan#   3. Check that the reader recovers the wal-index and reads the correct
939a6b4e9aSdan#      database content.
949a6b4e9aSdan#
959a6b4e9aSdando_test wal2-1.0 {
9613a3cb82Sdan  proc tvfs_cb {method filename args} {
9713a3cb82Sdan    set ::filename $filename
9813a3cb82Sdan    return SQLITE_OK
9913a3cb82Sdan  }
10013a3cb82Sdan
1011f55e28dSdan  testvfs tvfs
1021f55e28dSdan  tvfs script tvfs_cb
10313a3cb82Sdan  tvfs filter xShmOpen
1049a6b4e9aSdan
1059a6b4e9aSdan  sqlite3 db  test.db -vfs tvfs
1069a6b4e9aSdan  sqlite3 db2 test.db -vfs tvfs
1079a6b4e9aSdan
1089a6b4e9aSdan  execsql {
1099a6b4e9aSdan    PRAGMA journal_mode = WAL;
1109a6b4e9aSdan    CREATE TABLE t1(a);
1119a6b4e9aSdan  } db2
1129a6b4e9aSdan  execsql {
1139a6b4e9aSdan    INSERT INTO t1 VALUES(1);
1149a6b4e9aSdan    INSERT INTO t1 VALUES(2);
1159a6b4e9aSdan    INSERT INTO t1 VALUES(3);
1169a6b4e9aSdan    INSERT INTO t1 VALUES(4);
1179a6b4e9aSdan    SELECT count(a), sum(a) FROM t1;
1189a6b4e9aSdan  }
1199a6b4e9aSdan} {4 10}
1209a6b4e9aSdando_test wal2-1.1 {
1219a6b4e9aSdan  execsql { SELECT count(a), sum(a) FROM t1 } db2
1229a6b4e9aSdan} {4 10}
1239a6b4e9aSdan
124d0aa3427Sdanset RECOVER [list                                      \
125*cddfc392Sdan  {0 1 lock exclusive}   {1 2 lock exclusive}          \
126*cddfc392Sdan  {4 1 lock exclusive}   {4 1 unlock exclusive}        \
127*cddfc392Sdan  {5 1 lock exclusive}   {5 1 unlock exclusive}        \
128*cddfc392Sdan  {6 1 lock exclusive}   {6 1 unlock exclusive}        \
129*cddfc392Sdan  {7 1 lock exclusive}   {7 1 unlock exclusive}        \
130*cddfc392Sdan  {1 2 unlock exclusive} {0 1 unlock exclusive}        \
131d0aa3427Sdan]
132d0aa3427Sdanset READ [list                                         \
133d0aa3427Sdan  {4 1 lock shared}    {4 1 unlock shared}             \
134d0aa3427Sdan]
1355373b76bSdanset INITSLOT [list                                     \
1365373b76bSdan  {4 1 lock exclusive} {4 1 unlock exclusive}          \
1375373b76bSdan]
138d0aa3427Sdan
139d0aa3427Sdanforeach {tn iInsert res wal_index_hdr_mod wal_locks} "
140d0aa3427Sdan         2    5   {5 15}    0             {$RECOVER $READ}
141d0aa3427Sdan         3    6   {6 21}    1             {$RECOVER $READ}
142d0aa3427Sdan         4    7   {7 28}    2             {$RECOVER $READ}
143d0aa3427Sdan         5    8   {8 36}    3             {$RECOVER $READ}
144d0aa3427Sdan         6    9   {9 45}    4             {$RECOVER $READ}
145d0aa3427Sdan         7   10   {10 55}   5             {$RECOVER $READ}
146d0aa3427Sdan         8   11   {11 66}   6             {$RECOVER $READ}
147d0aa3427Sdan         9   12   {12 78}   7             {$RECOVER $READ}
148d0aa3427Sdan        10   13   {13 91}   8             {$RECOVER $READ}
149d0aa3427Sdan        11   14   {14 105}  9             {$RECOVER $READ}
1505373b76bSdan        12   15   {15 120}  -1            {$INITSLOT $READ}
151d0aa3427Sdan" {
1529a6b4e9aSdan
1539a6b4e9aSdan  do_test wal2-1.$tn.1 {
1549a6b4e9aSdan    execsql { INSERT INTO t1 VALUES($iInsert) }
1559a6b4e9aSdan    set ::locks [list]
1569a6b4e9aSdan    proc tvfs_cb {method args} {
15713a3cb82Sdan      lappend ::locks [lindex $args 2]
1589a6b4e9aSdan      return SQLITE_OK
1599a6b4e9aSdan    }
16013a3cb82Sdan    tvfs filter xShmLock
16113a3cb82Sdan    if {$::wal_index_hdr_mod >= 0} {
16213a3cb82Sdan      incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
16313a3cb82Sdan    }
1649a6b4e9aSdan    execsql { SELECT count(a), sum(a) FROM t1 } db2
1659a6b4e9aSdan  } $res
1669a6b4e9aSdan
1679a6b4e9aSdan  do_test wal2-1.$tn.2 {
1689a6b4e9aSdan    set ::locks
1699a6b4e9aSdan  } $wal_locks
1709a6b4e9aSdan}
1719a6b4e9aSdandb close
1729a6b4e9aSdandb2 close
1739a6b4e9aSdantvfs delete
174fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal
1759a6b4e9aSdan
1769a6b4e9aSdan#-------------------------------------------------------------------------
1779a6b4e9aSdan# This test case is very similar to the previous one, except, after
1789a6b4e9aSdan# the reader reads the corrupt wal-index header, but before it has
1799a6b4e9aSdan# a chance to re-read it under the cover of the RECOVER lock, the
1809a6b4e9aSdan# wal-index header is replaced with a valid, but out-of-date, header.
1819a6b4e9aSdan#
1829a6b4e9aSdan# Because the header checksum looks Ok, the reader does not run recovery,
1839a6b4e9aSdan# it simply drops back to a READ lock and proceeds. But because the
1849a6b4e9aSdan# header is out-of-date, the reader reads the out-of-date snapshot.
1859a6b4e9aSdan#
1869a6b4e9aSdan# After this, the header is corrupted again and the reader is allowed
1879a6b4e9aSdan# to run recovery. This time, it sees an up-to-date snapshot of the
1889a6b4e9aSdan# database file.
1899a6b4e9aSdan#
190d0aa3427Sdanset WRITER [list 0 1 lock exclusive]
191d0aa3427Sdanset LOCKS  [list \
192d0aa3427Sdan  {0 1 lock exclusive} {0 1 unlock exclusive} \
193db7f647eSdrh  {4 1 lock exclusive} {4 1 unlock exclusive} \
194d0aa3427Sdan  {4 1 lock shared}    {4 1 unlock shared}    \
195d0aa3427Sdan]
1969a6b4e9aSdando_test wal2-2.0 {
1979a6b4e9aSdan
1981f55e28dSdan  testvfs tvfs
1991f55e28dSdan  tvfs script tvfs_cb
20013a3cb82Sdan  tvfs filter xShmOpen
2019a6b4e9aSdan  proc tvfs_cb {method args} {
20213a3cb82Sdan    set ::filename [lindex $args 0]
2039a6b4e9aSdan    return SQLITE_OK
2049a6b4e9aSdan  }
2059a6b4e9aSdan
2069a6b4e9aSdan  sqlite3 db  test.db -vfs tvfs
2079a6b4e9aSdan  sqlite3 db2 test.db -vfs tvfs
2089a6b4e9aSdan
2099a6b4e9aSdan  execsql {
2109a6b4e9aSdan    PRAGMA journal_mode = WAL;
2119a6b4e9aSdan    CREATE TABLE t1(a);
2129a6b4e9aSdan  } db2
2139a6b4e9aSdan  execsql {
2149a6b4e9aSdan    INSERT INTO t1 VALUES(1);
2159a6b4e9aSdan    INSERT INTO t1 VALUES(2);
2169a6b4e9aSdan    INSERT INTO t1 VALUES(3);
2179a6b4e9aSdan    INSERT INTO t1 VALUES(4);
2189a6b4e9aSdan    SELECT count(a), sum(a) FROM t1;
2199a6b4e9aSdan  }
2209a6b4e9aSdan} {4 10}
2219a6b4e9aSdando_test wal2-2.1 {
2229a6b4e9aSdan  execsql { SELECT count(a), sum(a) FROM t1 } db2
2239a6b4e9aSdan} {4 10}
2249a6b4e9aSdan
2259a6b4e9aSdanforeach {tn iInsert res0 res1 wal_index_hdr_mod} {
2269a6b4e9aSdan         2    5   {4 10}   {5 15}    0
2279a6b4e9aSdan         3    6   {5 15}   {6 21}    1
2289a6b4e9aSdan         4    7   {6 21}   {7 28}    2
2299a6b4e9aSdan         5    8   {7 28}   {8 36}    3
2309a6b4e9aSdan         6    9   {8 36}   {9 45}    4
2319a6b4e9aSdan         7   10   {9 45}   {10 55}   5
2329a6b4e9aSdan         8   11   {10 55}  {11 66}   6
2339a6b4e9aSdan         9   12   {11 66}  {12 78}   7
2349a6b4e9aSdan} {
23513a3cb82Sdan  tvfs filter xShmLock
23613a3cb82Sdan
2377e263728Sdrh  do_test wal2-2.$tn.1 {
23813a3cb82Sdan    set oldhdr [set_tvfs_hdr $::filename]
2399a6b4e9aSdan    execsql { INSERT INTO t1 VALUES($iInsert) }
2409a6b4e9aSdan    execsql { SELECT count(a), sum(a) FROM t1 }
2419a6b4e9aSdan  } $res1
2429a6b4e9aSdan
2439a6b4e9aSdan  do_test wal2-2.$tn.2 {
2449a6b4e9aSdan    set ::locks [list]
2459a6b4e9aSdan    proc tvfs_cb {method args} {
2469a6b4e9aSdan      set lock [lindex $args 2]
2479a6b4e9aSdan      lappend ::locks $lock
248d0aa3427Sdan      if {$lock == $::WRITER} {
24913a3cb82Sdan        set_tvfs_hdr $::filename $::oldhdr
2509a6b4e9aSdan      }
2519a6b4e9aSdan      return SQLITE_OK
2529a6b4e9aSdan    }
2539a6b4e9aSdan
25413a3cb82Sdan    if {$::wal_index_hdr_mod >= 0} {
25513a3cb82Sdan      incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
25613a3cb82Sdan    }
2579a6b4e9aSdan    execsql { SELECT count(a), sum(a) FROM t1 } db2
2589a6b4e9aSdan  } $res0
2599a6b4e9aSdan
2609a6b4e9aSdan  do_test wal2-2.$tn.3 {
2619a6b4e9aSdan    set ::locks
262d0aa3427Sdan  } $LOCKS
2639a6b4e9aSdan
2649a6b4e9aSdan  do_test wal2-2.$tn.4 {
2659a6b4e9aSdan    set ::locks [list]
2669a6b4e9aSdan    proc tvfs_cb {method args} {
2679a6b4e9aSdan      set lock [lindex $args 2]
2689a6b4e9aSdan      lappend ::locks $lock
2699a6b4e9aSdan      return SQLITE_OK
2709a6b4e9aSdan    }
2719a6b4e9aSdan
27213a3cb82Sdan    if {$::wal_index_hdr_mod >= 0} {
27313a3cb82Sdan      incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
27413a3cb82Sdan    }
2759a6b4e9aSdan    execsql { SELECT count(a), sum(a) FROM t1 } db2
2769a6b4e9aSdan  } $res1
2779a6b4e9aSdan}
2789a6b4e9aSdandb close
2799a6b4e9aSdandb2 close
2809a6b4e9aSdantvfs delete
281fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal
2829a6b4e9aSdan
283d0aa3427Sdan
284d0aa3427Sdanif 0 {
285ff6dfc73Sdan#-------------------------------------------------------------------------
286ff6dfc73Sdan# This test case - wal2-3.* - tests the response of the library to an
287ff6dfc73Sdan# SQLITE_BUSY when attempting to obtain a READ or RECOVER lock.
288ff6dfc73Sdan#
289ff6dfc73Sdan#   wal2-3.0 - 2: SQLITE_BUSY when obtaining a READ lock
290ff6dfc73Sdan#   wal2-3.3 - 6: SQLITE_BUSY when obtaining a RECOVER lock
291ff6dfc73Sdan#
292ff6dfc73Sdando_test wal2-3.0 {
293ff6dfc73Sdan  proc tvfs_cb {method args} {
294ff6dfc73Sdan    if {$method == "xShmLock"} {
295ff6dfc73Sdan      if {[info exists ::locked]} { return SQLITE_BUSY }
296ff6dfc73Sdan    }
297ff6dfc73Sdan    return SQLITE_OK
298ff6dfc73Sdan  }
299ff6dfc73Sdan
300ff6dfc73Sdan  proc busyhandler x {
301ff6dfc73Sdan    if {$x>3} { unset -nocomplain ::locked }
302ff6dfc73Sdan    return 0
303ff6dfc73Sdan  }
304ff6dfc73Sdan
3051f55e28dSdan  testvfs tvfs
3061f55e28dSdan  tvfs script tvfs_cb
307ff6dfc73Sdan  sqlite3 db test.db -vfs tvfs
308ff6dfc73Sdan  db busy busyhandler
309ff6dfc73Sdan
310ff6dfc73Sdan  execsql {
311ff6dfc73Sdan    PRAGMA journal_mode = WAL;
312ff6dfc73Sdan    CREATE TABLE t1(a);
313ff6dfc73Sdan    INSERT INTO t1 VALUES(1);
314ff6dfc73Sdan    INSERT INTO t1 VALUES(2);
315ff6dfc73Sdan    INSERT INTO t1 VALUES(3);
316ff6dfc73Sdan    INSERT INTO t1 VALUES(4);
317ff6dfc73Sdan  }
318ff6dfc73Sdan
319ff6dfc73Sdan  set ::locked 1
320ff6dfc73Sdan  info exists ::locked
321ff6dfc73Sdan} {1}
322ff6dfc73Sdando_test wal2-3.1 {
323ff6dfc73Sdan  execsql { SELECT count(a), sum(a) FROM t1 }
324ff6dfc73Sdan} {4 10}
325ff6dfc73Sdando_test wal2-3.2 {
326ff6dfc73Sdan  info exists ::locked
327ff6dfc73Sdan} {0}
328ff6dfc73Sdan
329ff6dfc73Sdando_test wal2-3.3 {
330ff6dfc73Sdan  proc tvfs_cb {method args} {
331ff6dfc73Sdan    if {$method == "xShmLock"} {
332ff6dfc73Sdan      if {[info exists ::sabotage]} {
333ff6dfc73Sdan        unset -nocomplain ::sabotage
334ff6dfc73Sdan        incr_tvfs_hdr [lindex $args 0] 1 1
335ff6dfc73Sdan      }
336ff6dfc73Sdan      if {[info exists ::locked] && [lindex $args 2] == "RECOVER"} {
337ff6dfc73Sdan        return SQLITE_BUSY
338ff6dfc73Sdan      }
339ff6dfc73Sdan    }
340ff6dfc73Sdan    return SQLITE_OK
341ff6dfc73Sdan  }
342ff6dfc73Sdan  set ::sabotage 1
343ff6dfc73Sdan  set ::locked 1
344ff6dfc73Sdan  list [info exists ::sabotage] [info exists ::locked]
345ff6dfc73Sdan} {1 1}
346ff6dfc73Sdando_test wal2-3.4 {
347ff6dfc73Sdan  execsql { SELECT count(a), sum(a) FROM t1 }
348ff6dfc73Sdan} {4 10}
349ff6dfc73Sdando_test wal2-3.5 {
350ff6dfc73Sdan  list [info exists ::sabotage] [info exists ::locked]
351ff6dfc73Sdan} {0 0}
352ff6dfc73Sdandb close
353ff6dfc73Sdantvfs delete
354fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal
355ff6dfc73Sdan
356d0aa3427Sdan}
357d0aa3427Sdan
358576bc329Sdan#-------------------------------------------------------------------------
359576bc329Sdan# Test that a database connection using a VFS that does not support the
360576bc329Sdan# xShmXXX interfaces cannot open a WAL database.
361576bc329Sdan#
362576bc329Sdando_test wal2-4.1 {
363576bc329Sdan  sqlite3 db test.db
364576bc329Sdan  execsql {
3657fa65fbfSdan    PRAGMA auto_vacuum = 0;
366576bc329Sdan    PRAGMA journal_mode = WAL;
367576bc329Sdan    CREATE TABLE data(x);
368576bc329Sdan    INSERT INTO data VALUES('need xShmOpen to see this');
369576bc329Sdan    PRAGMA wal_checkpoint;
370576bc329Sdan  }
3710774bb59Sdan  # Three pages in the WAL file at this point: One copy of page 1 and two
3720774bb59Sdan  # of the root page for table "data".
3730774bb59Sdan} {wal 0 3 3}
374576bc329Sdando_test wal2-4.2 {
375576bc329Sdan  db close
3761f55e28dSdan  testvfs tvfs -noshm 1
377576bc329Sdan  sqlite3 db test.db -vfs tvfs
378576bc329Sdan  catchsql { SELECT * FROM data }
379576bc329Sdan} {1 {unable to open database file}}
380576bc329Sdando_test wal2-4.3 {
381576bc329Sdan  db close
3821f55e28dSdan  testvfs tvfs
383576bc329Sdan  sqlite3 db test.db -vfs tvfs
384576bc329Sdan  catchsql { SELECT * FROM data }
385576bc329Sdan} {0 {{need xShmOpen to see this}}}
386576bc329Sdandb close
387576bc329Sdantvfs delete
388576bc329Sdan
3895273f58fSdan#-------------------------------------------------------------------------
3905273f58fSdan# Test that if a database connection is forced to run recovery before it
39165be0d8cSdan# can perform a checkpoint, it does not transition into RECOVER state.
3925273f58fSdan#
393d0aa3427Sdan# UPDATE: This has now changed. When running a checkpoint, if recovery is
394d0aa3427Sdan# required the client grabs all exclusive locks (just as it would for a
395d0aa3427Sdan# recovery performed as a pre-cursor to a normal database transaction).
396d0aa3427Sdan#
3975f3f3b29Sdanset expected_locks [list]
3985f3f3b29Sdanlappend expected_locks {1 1 lock exclusive}   ;# Lock checkpoint
3995f3f3b29Sdanlappend expected_locks {0 1 lock exclusive}   ;# Lock writer
40044c8a97eSdanlappend expected_locks {2 1 lock exclusive}   ;# Lock recovery
401*cddfc392Sdan# lappend expected_locks {4 4 lock exclusive}   ;# Lock all aReadMark[]
402*cddfc392Sdanlappend expected_locks {4 1 lock exclusive}   ;# Lock aReadMark[1]
403*cddfc392Sdanlappend expected_locks {4 1 unlock exclusive} ;# Unlock aReadMark[1]
404*cddfc392Sdanlappend expected_locks {5 1 lock exclusive}
405*cddfc392Sdanlappend expected_locks {5 1 unlock exclusive}
406*cddfc392Sdanlappend expected_locks {6 1 lock exclusive}
407*cddfc392Sdanlappend expected_locks {6 1 unlock exclusive}
408*cddfc392Sdanlappend expected_locks {7 1 lock exclusive}
409*cddfc392Sdanlappend expected_locks {7 1 unlock exclusive}
41044c8a97eSdanlappend expected_locks {2 1 unlock exclusive} ;# Unlock recovery
411*cddfc392Sdan# lappend expected_locks {4 4 unlock exclusive} ;# Unlock all aReadMark[]
4125f3f3b29Sdanlappend expected_locks {0 1 unlock exclusive} ;# Unlock writer
4135f3f3b29Sdanlappend expected_locks {3 1 lock exclusive}   ;# Lock aReadMark[0]
4145f3f3b29Sdanlappend expected_locks {3 1 unlock exclusive} ;# Unlock aReadMark[0]
4155f3f3b29Sdanlappend expected_locks {1 1 unlock exclusive} ;# Unlock checkpoint
4165273f58fSdando_test wal2-5.1 {
4175273f58fSdan  proc tvfs_cb {method args} {
4185273f58fSdan    set ::shm_file [lindex $args 0]
4195273f58fSdan    if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
4205273f58fSdan    return $::tvfs_cb_return
4215273f58fSdan  }
4225273f58fSdan  set tvfs_cb_return SQLITE_OK
4235273f58fSdan
4241f55e28dSdan  testvfs tvfs
4251f55e28dSdan  tvfs script tvfs_cb
4265273f58fSdan
4275273f58fSdan  sqlite3 db test.db -vfs tvfs
4285273f58fSdan  execsql {
4295273f58fSdan    PRAGMA journal_mode = WAL;
4305273f58fSdan    CREATE TABLE x(y);
4315273f58fSdan    INSERT INTO x VALUES(1);
4325273f58fSdan  }
4335273f58fSdan
4345273f58fSdan  incr_tvfs_hdr $::shm_file 1 1
4355273f58fSdan  set ::locks [list]
4365273f58fSdan  execsql { PRAGMA wal_checkpoint }
4375273f58fSdan  set ::locks
4385f3f3b29Sdan} $expected_locks
43965be0d8cSdandb close
44065be0d8cSdantvfs delete
4415273f58fSdan
4425543759bSdan#-------------------------------------------------------------------------
4435543759bSdan# This block, test cases wal2-6.*, tests the operation of WAL with
4445543759bSdan# "PRAGMA locking_mode=EXCLUSIVE" set.
4455543759bSdan#
4465543759bSdan#   wal2-6.1.*: Changing to WAL mode before setting locking_mode=exclusive.
4475543759bSdan#
4485543759bSdan#   wal2-6.2.*: Changing to WAL mode after setting locking_mode=exclusive.
4495543759bSdan#
4505543759bSdan#   wal2-6.3.*: Changing back to rollback mode from WAL mode after setting
4515543759bSdan#               locking_mode=exclusive.
4525543759bSdan#
4535543759bSdan#   wal2-6.4.*: Check that xShmLock calls are omitted in exclusive locking
4545543759bSdan#               mode.
4555543759bSdan#
4563cac5dc9Sdan#   wal2-6.5.*:
4573cac5dc9Sdan#
4583cac5dc9Sdan#   wal2-6.6.*: Check that if the xShmLock() to reaquire a WAL read-lock when
4593cac5dc9Sdan#               exiting exclusive mode fails (i.e. SQLITE_IOERR), then the
4603cac5dc9Sdan#               connection silently remains in exclusive mode.
4613cac5dc9Sdan#
4625543759bSdando_test wal2-6.1.1 {
463fda06befSmistachkin  forcedelete test.db test.db-wal test.db-journal
4645543759bSdan  sqlite3 db test.db
4655543759bSdan  execsql {
4665543759bSdan    Pragma Journal_Mode = Wal;
4675543759bSdan  }
4688c408004Sdan} {wal}
4695543759bSdando_test wal2-6.1.2 {
4705543759bSdan  execsql { PRAGMA lock_status }
4715543759bSdan} {main unlocked temp closed}
4725543759bSdando_test wal2-6.1.3 {
4735543759bSdan  execsql {
4748c408004Sdan    SELECT * FROM sqlite_master;
4758c408004Sdan    Pragma Locking_Mode = Exclusive;
4768c408004Sdan  }
4778c408004Sdan  execsql {
4785543759bSdan    BEGIN;
4795543759bSdan      CREATE TABLE t1(a, b);
4805543759bSdan      INSERT INTO t1 VALUES(1, 2);
4815543759bSdan    COMMIT;
4825543759bSdan    PRAGMA lock_status;
4835543759bSdan  }
4845543759bSdan} {main exclusive temp closed}
4855543759bSdando_test wal2-6.1.4 {
4865543759bSdan  execsql {
4875543759bSdan    PRAGMA locking_mode = normal;
4885543759bSdan    PRAGMA lock_status;
4895543759bSdan  }
4905543759bSdan} {normal main exclusive temp closed}
4915543759bSdando_test wal2-6.1.5 {
4925543759bSdan  execsql {
4935543759bSdan    SELECT * FROM t1;
4945543759bSdan    PRAGMA lock_status;
4955543759bSdan  }
496d0864087Sdan} {1 2 main shared temp closed}
4975543759bSdando_test wal2-6.1.6 {
4985543759bSdan  execsql {
4995543759bSdan    INSERT INTO t1 VALUES(3, 4);
5005543759bSdan    PRAGMA lock_status;
5015543759bSdan  }
5025543759bSdan} {main shared temp closed}
5035543759bSdandb close
5045543759bSdan
5055543759bSdando_test wal2-6.2.1 {
506fda06befSmistachkin  forcedelete test.db test.db-wal test.db-journal
5075543759bSdan  sqlite3 db test.db
5085543759bSdan  execsql {
5095543759bSdan    Pragma Locking_Mode = Exclusive;
5105543759bSdan    Pragma Journal_Mode = Wal;
5115543759bSdan    Pragma Lock_Status;
5125543759bSdan  }
5135543759bSdan} {exclusive wal main exclusive temp closed}
5145543759bSdando_test wal2-6.2.2 {
5155543759bSdan  execsql {
5165543759bSdan    BEGIN;
5175543759bSdan      CREATE TABLE t1(a, b);
5185543759bSdan      INSERT INTO t1 VALUES(1, 2);
5195543759bSdan    COMMIT;
5205543759bSdan    Pragma loCK_STATus;
5215543759bSdan  }
5225543759bSdan} {main exclusive temp closed}
5235543759bSdando_test wal2-6.2.3 {
5245543759bSdan  db close
5255543759bSdan  sqlite3 db test.db
5268c408004Sdan  execsql { SELECT * FROM sqlite_master }
5275543759bSdan  execsql { PRAGMA LOCKING_MODE = EXCLUSIVE }
5285543759bSdan} {exclusive}
5295543759bSdando_test wal2-6.2.4 {
5305543759bSdan  execsql {
5315543759bSdan    SELECT * FROM t1;
5325543759bSdan    pragma lock_status;
5335543759bSdan  }
5345543759bSdan} {1 2 main shared temp closed}
5355543759bSdando_test wal2-6.2.5 {
5365543759bSdan  execsql {
5375543759bSdan    INSERT INTO t1 VALUES(3, 4);
5385543759bSdan    pragma lock_status;
5395543759bSdan  }
5405543759bSdan} {main exclusive temp closed}
5415543759bSdando_test wal2-6.2.6 {
5425543759bSdan  execsql {
5435543759bSdan    PRAGMA locking_mode = NORMAL;
5445543759bSdan    pragma lock_status;
5455543759bSdan  }
5465543759bSdan} {normal main exclusive temp closed}
5475543759bSdando_test wal2-6.2.7 {
5485543759bSdan  execsql {
5495543759bSdan    BEGIN IMMEDIATE; COMMIT;
5505543759bSdan    pragma lock_status;
5515543759bSdan  }
5525543759bSdan} {main shared temp closed}
5535543759bSdando_test wal2-6.2.8 {
5545543759bSdan  execsql {
5555543759bSdan    PRAGMA locking_mode = EXCLUSIVE;
5565543759bSdan    BEGIN IMMEDIATE; COMMIT;
5575543759bSdan    PRAGMA locking_mode = NORMAL;
5585543759bSdan  }
5595543759bSdan  execsql {
5605543759bSdan    SELECT * FROM t1;
5615543759bSdan    pragma lock_status;
5625543759bSdan  }
563d0864087Sdan} {1 2 3 4 main shared temp closed}
5645543759bSdando_test wal2-6.2.9 {
5655543759bSdan  execsql {
5665543759bSdan    INSERT INTO t1 VALUES(5, 6);
5675543759bSdan    SELECT * FROM t1;
5685543759bSdan    pragma lock_status;
5695543759bSdan  }
5705543759bSdan} {1 2 3 4 5 6 main shared temp closed}
5715543759bSdandb close
5725543759bSdan
5735543759bSdando_test wal2-6.3.1 {
574fda06befSmistachkin  forcedelete test.db test.db-wal test.db-journal
5755543759bSdan  sqlite3 db test.db
5765543759bSdan  execsql {
5775543759bSdan    PRAGMA journal_mode = WAL;
5785543759bSdan    PRAGMA locking_mode = exclusive;
5795543759bSdan    BEGIN;
5805543759bSdan      CREATE TABLE t1(x);
5815543759bSdan      INSERT INTO t1 VALUES('Chico');
5825543759bSdan      INSERT INTO t1 VALUES('Harpo');
5835543759bSdan    COMMIT;
5845543759bSdan  }
5855543759bSdan  list [file exists test.db-wal] [file exists test.db-journal]
5865543759bSdan} {1 0}
5875543759bSdando_test wal2-6.3.2 {
5885543759bSdan  execsql { PRAGMA journal_mode = DELETE }
5895543759bSdan  file exists test.db-wal
5905543759bSdan} {0}
5915543759bSdando_test wal2-6.3.3 {
5925543759bSdan  execsql { PRAGMA lock_status }
5935543759bSdan} {main exclusive temp closed}
5945543759bSdando_test wal2-6.3.4 {
5955543759bSdan  execsql {
5965543759bSdan    BEGIN;
5975543759bSdan      INSERT INTO t1 VALUES('Groucho');
5985543759bSdan  }
59969aedc8dSdan} {}
60069aedc8dSdanif {[atomic_batch_write test.db]==0} {
60169aedc8dSdan  do_test wal2-6.3.4.1 {
6025543759bSdan    list [file exists test.db-wal] [file exists test.db-journal]
6035543759bSdan  } {0 1}
60469aedc8dSdan}
6055543759bSdando_test wal2-6.3.5 {
6065543759bSdan  execsql { PRAGMA lock_status }
6075543759bSdan} {main exclusive temp closed}
6085543759bSdando_test wal2-6.3.6 {
6095543759bSdan  execsql { COMMIT }
61069aedc8dSdan} {}
61169aedc8dSdanif {[atomic_batch_write test.db]==0} {
61269aedc8dSdan  do_test wal2-6.3.6.1 {
6135543759bSdan    list [file exists test.db-wal] [file exists test.db-journal]
6145543759bSdan  } {0 1}
61569aedc8dSdan}
6165543759bSdando_test wal2-6.3.7 {
6175543759bSdan  execsql { PRAGMA lock_status }
6185543759bSdan} {main exclusive temp closed}
6195543759bSdandb close
6205543759bSdan
6215f3f3b29Sdan
6225f3f3b29Sdan# This test - wal2-6.4.* - uses a single database connection and the
6235f3f3b29Sdan# [testvfs] instrumentation to test that xShmLock() is being called
6245f3f3b29Sdan# as expected when a WAL database is used with locking_mode=exclusive.
6255f3f3b29Sdan#
6265543759bSdando_test wal2-6.4.1 {
627fda06befSmistachkin  forcedelete test.db test.db-wal test.db-journal
6285543759bSdan  proc tvfs_cb {method args} {
6295543759bSdan    set ::shm_file [lindex $args 0]
6305543759bSdan    if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
6315543759bSdan    return "SQLITE_OK"
6325543759bSdan  }
6331f55e28dSdan  testvfs tvfs
6341f55e28dSdan  tvfs script tvfs_cb
6355543759bSdan  sqlite3 db test.db -vfs tvfs
636262765a7Sdan  set {} {}
6375f3f3b29Sdan} {}
6385543759bSdan
6395f3f3b29Sdanset RECOVERY {
640*cddfc392Sdan  {0 1 lock exclusive}   {1 2 lock exclusive}
641*cddfc392Sdan  {4 1 lock exclusive}   {4 1 unlock exclusive}
642*cddfc392Sdan  {5 1 lock exclusive}   {5 1 unlock exclusive}
643*cddfc392Sdan  {6 1 lock exclusive}   {6 1 unlock exclusive}
644*cddfc392Sdan  {7 1 lock exclusive}   {7 1 unlock exclusive}
645*cddfc392Sdan  {1 2 unlock exclusive} {0 1 unlock exclusive}
6465f3f3b29Sdan}
6475f3f3b29Sdanset READMARK0_READ {
6485f3f3b29Sdan  {3 1 lock shared} {3 1 unlock shared}
6495f3f3b29Sdan}
6505f3f3b29Sdanset READMARK0_WRITE {
6515f3f3b29Sdan  {3 1 lock shared}
6525f3f3b29Sdan  {0 1 lock exclusive} {3 1 unlock shared}
6535f3f3b29Sdan  {4 1 lock exclusive} {4 1 unlock exclusive} {4 1 lock shared}
6545f3f3b29Sdan  {0 1 unlock exclusive} {4 1 unlock shared}
6555f3f3b29Sdan}
6565f3f3b29Sdanset READMARK1_SET {
6575f3f3b29Sdan  {4 1 lock exclusive} {4 1 unlock exclusive}
6585f3f3b29Sdan}
6595f3f3b29Sdanset READMARK1_READ {
6605f3f3b29Sdan  {4 1 lock shared} {4 1 unlock shared}
6615f3f3b29Sdan}
662d0864087Sdanset READMARK1_WRITE {
663d0864087Sdan  {4 1 lock shared}
664d0864087Sdan    {0 1 lock exclusive} {0 1 unlock exclusive}
665d0864087Sdan  {4 1 unlock shared}
666d0864087Sdan}
6675f3f3b29Sdan
6685f3f3b29Sdanforeach {tn sql res expected_locks} {
6695f3f3b29Sdan  2 {
6707fa65fbfSdan    PRAGMA auto_vacuum = 0;
6715543759bSdan    PRAGMA journal_mode = WAL;
6725f3f3b29Sdan    BEGIN;
6735543759bSdan      CREATE TABLE t1(x);
6745543759bSdan      INSERT INTO t1 VALUES('Leonard');
6755543759bSdan      INSERT INTO t1 VALUES('Arthur');
6765f3f3b29Sdan    COMMIT;
6775f3f3b29Sdan  } {wal} {
6785f3f3b29Sdan    $RECOVERY
6795f3f3b29Sdan    $READMARK0_WRITE
6805f3f3b29Sdan  }
6815f3f3b29Sdan
6825f3f3b29Sdan  3 {
6835f3f3b29Sdan    # This test should do the READMARK1_SET locking to populate the
6845f3f3b29Sdan    # aReadMark[1] slot with the current mxFrame value. Followed by
6855f3f3b29Sdan    # READMARK1_READ to read the database.
6865f3f3b29Sdan    #
6875f3f3b29Sdan    SELECT * FROM t1
6885f3f3b29Sdan  } {Leonard Arthur} {
6895f3f3b29Sdan    $READMARK1_SET
6905f3f3b29Sdan    $READMARK1_READ
6915f3f3b29Sdan  }
6925f3f3b29Sdan
6935f3f3b29Sdan  4 {
6945f3f3b29Sdan    # aReadMark[1] is already set to mxFrame. So just READMARK1_READ
6955f3f3b29Sdan    # this time, not READMARK1_SET.
6965f3f3b29Sdan    #
6975f3f3b29Sdan    SELECT * FROM t1 ORDER BY x
6985f3f3b29Sdan  } {Arthur Leonard} {
6995f3f3b29Sdan    $READMARK1_READ
7005f3f3b29Sdan  }
7015f3f3b29Sdan
7025f3f3b29Sdan  5 {
7035f3f3b29Sdan    PRAGMA locking_mode = exclusive
7045f3f3b29Sdan  } {exclusive} { }
7055f3f3b29Sdan
7065f3f3b29Sdan  6 {
7075f3f3b29Sdan    INSERT INTO t1 VALUES('Julius Henry');
7085f3f3b29Sdan    SELECT * FROM t1;
7095f3f3b29Sdan  } {Leonard Arthur {Julius Henry}} {
7105f3f3b29Sdan    $READMARK1_READ
7115f3f3b29Sdan  }
7125f3f3b29Sdan
7135f3f3b29Sdan  7 {
7145f3f3b29Sdan    INSERT INTO t1 VALUES('Karl');
7155f3f3b29Sdan    SELECT * FROM t1;
7165f3f3b29Sdan  } {Leonard Arthur {Julius Henry} Karl} { }
7175f3f3b29Sdan
7185f3f3b29Sdan  8 {
7195f3f3b29Sdan    PRAGMA locking_mode = normal
7205f3f3b29Sdan  } {normal} { }
7215f3f3b29Sdan
7225f3f3b29Sdan  9 {
7235f3f3b29Sdan    SELECT * FROM t1 ORDER BY x
724d0864087Sdan  } {Arthur {Julius Henry} Karl Leonard} $READMARK1_READ
7255f3f3b29Sdan
726d0864087Sdan  10 { DELETE FROM t1 } {} $READMARK1_WRITE
7275f3f3b29Sdan
7285f3f3b29Sdan  11 {
7295f3f3b29Sdan    SELECT * FROM t1
7305f3f3b29Sdan  } {} {
7315f3f3b29Sdan    $READMARK1_SET
7325f3f3b29Sdan    $READMARK1_READ
7335f3f3b29Sdan  }
7345f3f3b29Sdan} {
7355f3f3b29Sdan
7365f3f3b29Sdan  set L [list]
7375f3f3b29Sdan  foreach el [subst $expected_locks] { lappend L $el }
7385f3f3b29Sdan
7395f3f3b29Sdan  set S ""
7405f3f3b29Sdan  foreach sq [split $sql "\n"] {
7415f3f3b29Sdan    set sq [string trim $sq]
7425f3f3b29Sdan    if {[string match {#*} $sq]==0} {append S "$sq\n"}
7435543759bSdan  }
7445543759bSdan
7455543759bSdan  set ::locks [list]
7465f3f3b29Sdan  do_test wal2-6.4.$tn.1 { execsql $S } $res
7475f3f3b29Sdan  do_test wal2-6.4.$tn.2 { set ::locks  } $L
7485543759bSdan}
7495f3f3b29Sdan
7505543759bSdandb close
751ed36020dSdantvfs delete
752ed36020dSdan
753ed36020dSdando_test wal2-6.5.1 {
754ed36020dSdan  sqlite3 db test.db
755ed36020dSdan  execsql {
7567fa65fbfSdan    PRAGMA auto_vacuum = 0;
757ed36020dSdan    PRAGMA journal_mode = wal;
758ed36020dSdan    PRAGMA locking_mode = exclusive;
759ed36020dSdan    CREATE TABLE t2(a, b);
760ed36020dSdan    PRAGMA wal_checkpoint;
761ed36020dSdan    INSERT INTO t2 VALUES('I', 'II');
762ed36020dSdan    PRAGMA journal_mode;
763ed36020dSdan  }
7640774bb59Sdan} {wal exclusive 0 2 2 wal}
76514740f1cSdando_test wal2-6.5.2 {
76614740f1cSdan  execsql {
76714740f1cSdan    PRAGMA locking_mode = normal;
76814740f1cSdan    INSERT INTO t2 VALUES('III', 'IV');
76914740f1cSdan    PRAGMA locking_mode = exclusive;
77014740f1cSdan    SELECT * FROM t2;
77114740f1cSdan  }
77214740f1cSdan} {normal exclusive I II III IV}
77314740f1cSdando_test wal2-6.5.3 {
77414740f1cSdan  execsql { PRAGMA wal_checkpoint }
7750774bb59Sdan} {0 2 2}
776ed36020dSdandb close
7775543759bSdan
7783cac5dc9Sdanproc lock_control {method filename handle spec} {
7793cac5dc9Sdan  foreach {start n op type} $spec break
7803cac5dc9Sdan  if {$op == "lock"} { return SQLITE_IOERR }
7813cac5dc9Sdan  return SQLITE_OK
7823cac5dc9Sdan}
7833cac5dc9Sdando_test wal2-6.6.1 {
7843cac5dc9Sdan  testvfs T
7853cac5dc9Sdan  T script lock_control
7863cac5dc9Sdan  T filter {}
7873cac5dc9Sdan  sqlite3 db test.db -vfs T
7888c408004Sdan  execsql { SELECT * FROM sqlite_master }
7893cac5dc9Sdan  execsql { PRAGMA locking_mode = exclusive }
7903cac5dc9Sdan  execsql { INSERT INTO t2 VALUES('V', 'VI') }
7913cac5dc9Sdan} {}
7923cac5dc9Sdando_test wal2-6.6.2 {
7933cac5dc9Sdan  execsql { PRAGMA locking_mode = normal }
7943cac5dc9Sdan  T filter xShmLock
7953cac5dc9Sdan  execsql { INSERT INTO t2 VALUES('VII', 'VIII') }
7963cac5dc9Sdan} {}
7973cac5dc9Sdando_test wal2-6.6.3 {
7983cac5dc9Sdan  # At this point the connection should still be in exclusive-mode, even
7993cac5dc9Sdan  # though it tried to exit exclusive-mode when committing the INSERT
8003cac5dc9Sdan  # statement above. To exit exclusive mode, SQLite has to take a read-lock
8013cac5dc9Sdan  # on the WAL file using xShmLock(). Since that call failed, it remains
8023cac5dc9Sdan  # in exclusive mode.
8033cac5dc9Sdan  #
8043cac5dc9Sdan  sqlite3 db2 test.db -vfs T
8053cac5dc9Sdan  catchsql { SELECT * FROM t2 } db2
8063cac5dc9Sdan} {1 {database is locked}}
8073cac5dc9Sdando_test wal2-6.6.2 {
8083cac5dc9Sdan  db2 close
8093cac5dc9Sdan  T filter {}
8103cac5dc9Sdan  execsql { INSERT INTO t2 VALUES('IX', 'X') }
8113cac5dc9Sdan} {}
8128c408004Sdando_test wal2-6.6.4 {
8133cac5dc9Sdan  # This time, we have successfully exited exclusive mode. So the second
8143cac5dc9Sdan  # connection can read the database.
8153cac5dc9Sdan  sqlite3 db2 test.db -vfs T
8163cac5dc9Sdan  catchsql { SELECT * FROM t2 } db2
8173cac5dc9Sdan} {0 {I II III IV V VI VII VIII IX X}}
8183cac5dc9Sdan
8193cac5dc9Sdandb close
8203cac5dc9Sdandb2 close
8213cac5dc9SdanT delete
8223cac5dc9Sdan
8236f150148Sdan#-------------------------------------------------------------------------
8246f150148Sdan# Test a theory about the checksum algorithm. Theory was false and this
8256f150148Sdan# test did not provoke a bug.
8268067adbcSdan#
827fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal
8286f150148Sdando_test wal2-7.1.1 {
8296f150148Sdan  sqlite3 db test.db
8306f150148Sdan  execsql {
8316f150148Sdan    PRAGMA page_size = 4096;
8326f150148Sdan    PRAGMA journal_mode = WAL;
8336f150148Sdan    CREATE TABLE t1(a, b);
8346f150148Sdan  }
8356f150148Sdan  file size test.db
8366f150148Sdan} {4096}
8376f150148Sdando_test wal2-7.1.2 {
838fda06befSmistachkin  forcecopy test.db test2.db
839fda06befSmistachkin  forcecopy test.db-wal test2.db-wal
840e03d7625Sdan  # The first 32 bytes of the WAL file contain the WAL header. Offset 48
841e03d7625Sdan  # is the first byte of the checksum for the first frame in the WAL.
842e03d7625Sdan  # The following three lines replaces the contents of that byte with
843e03d7625Sdan  # a different value.
844e03d7625Sdan  set newval FF
845e03d7625Sdan  if {$newval == [hexio_read test2.db-wal 48 1]} { set newval 00 }
846e03d7625Sdan  hexio_write test2.db-wal 48 $newval
8476f150148Sdan} {1}
8486f150148Sdando_test wal2-7.1.3 {
8496f150148Sdan  sqlite3 db2 test2.db
8506f150148Sdan  execsql { PRAGMA wal_checkpoint } db2
8516f150148Sdan  execsql { SELECT * FROM sqlite_master } db2
8526f150148Sdan} {}
853a1a889ecSshanehdb close
8546f150148Sdandb2 close
855fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal
8568067adbcSdando_test wal2-8.1.2 {
8578067adbcSdan  sqlite3 db test.db
8588067adbcSdan  execsql {
859c2857bf2Sdrh    PRAGMA auto_vacuum=OFF;
8608067adbcSdan    PRAGMA page_size = 1024;
8618067adbcSdan    PRAGMA journal_mode = WAL;
8628067adbcSdan    CREATE TABLE t1(x);
8638067adbcSdan    INSERT INTO t1 VALUES(zeroblob(8188*1020));
8648067adbcSdan    CREATE TABLE t2(y);
865bdd9af0fSdan    PRAGMA wal_checkpoint;
8668067adbcSdan  }
8678067adbcSdan  execsql {
86847ee386fSdan    SELECT rootpage>=8192 FROM sqlite_master WHERE tbl_name = 't2';
8698067adbcSdan  }
87047ee386fSdan} {1}
8718067adbcSdando_test wal2-8.1.3 {
8728067adbcSdan  execsql {
8738067adbcSdan    PRAGMA cache_size = 10;
8748067adbcSdan    CREATE TABLE t3(z);
8758067adbcSdan    BEGIN;
8768067adbcSdan      INSERT INTO t3 VALUES(randomblob(900));
8778067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8788067adbcSdan      INSERT INTO t2 VALUES('hello');
8798067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8808067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8818067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8828067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8838067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8848067adbcSdan      INSERT INTO t3 SELECT randomblob(900) FROM t3;
8858067adbcSdan    ROLLBACK;
8868067adbcSdan  }
8878067adbcSdan  execsql {
8888067adbcSdan    INSERT INTO t2 VALUES('goodbye');
8898067adbcSdan    INSERT INTO t3 SELECT randomblob(900) FROM t3;
8908067adbcSdan    INSERT INTO t3 SELECT randomblob(900) FROM t3;
8918067adbcSdan  }
8928067adbcSdan} {}
8938067adbcSdando_test wal2-8.1.4 {
8948067adbcSdan  sqlite3 db2 test.db
8958067adbcSdan  execsql { SELECT * FROM t2 }
8968067adbcSdan} {goodbye}
8978067adbcSdandb2 close
89823dced35Sdandb close
8998067adbcSdan
90023dced35Sdan#-------------------------------------------------------------------------
90123dced35Sdan# Test that even if the checksums for both are valid, if the two copies
90223dced35Sdan# of the wal-index header in the wal-index do not match, the client
90323dced35Sdan# runs (or at least tries to run) database recovery.
90423dced35Sdan#
90523f71920Sdan#
90623f71920Sdanproc get_name {method args} { set ::filename [lindex $args 0] ; tvfs filter {} }
90723dced35Sdantestvfs tvfs
90823dced35Sdantvfs script get_name
90923dced35Sdantvfs filter xShmOpen
91023dced35Sdan
911fda06befSmistachkinforcedelete test.db test.db-wal test.db-journal
91223dced35Sdando_test wal2-9.1 {
91323dced35Sdan  sqlite3 db test.db -vfs tvfs
91423dced35Sdan  execsql {
91523dced35Sdan    PRAGMA journal_mode = WAL;
91623dced35Sdan    CREATE TABLE x(y);
91723dced35Sdan    INSERT INTO x VALUES('Barton');
91823dced35Sdan    INSERT INTO x VALUES('Deakin');
91923dced35Sdan  }
92023f71920Sdan
92123f71920Sdan  # Set $wih(1) to the contents of the wal-index header after
92223f71920Sdan  # the frames associated with the first two rows in table 'x' have
92323f71920Sdan  # been inserted. Then insert one more row and set $wih(2)
92423f71920Sdan  # to the new value of the wal-index header.
92523f71920Sdan  #
92623f71920Sdan  # If the $wih(1) is written into the wal-index before running
92723f71920Sdan  # a read operation, the client will see only the first two rows. If
92823f71920Sdan  # $wih(2) is written into the wal-index, the client will see
92923f71920Sdan  # three rows. If an invalid header is written into the wal-index, then
93023f71920Sdan  # the client will run recovery and see three rows.
93123f71920Sdan  #
93223f71920Sdan  set wih(1) [set_tvfs_hdr $::filename]
93323dced35Sdan  execsql { INSERT INTO x VALUES('Watson') }
93423f71920Sdan  set wih(2) [set_tvfs_hdr $::filename]
93523f71920Sdan
93623dced35Sdan  sqlite3 db2 test.db -vfs tvfs
93723dced35Sdan  execsql { SELECT * FROM x } db2
93823dced35Sdan} {Barton Deakin Watson}
93923f71920Sdan
94023f71920Sdanforeach {tn hdr1 hdr2 res} [list                                            \
94123f71920Sdan  3  $wih(1)                $wih(1)                {Barton Deakin}          \
94223f71920Sdan  4  $wih(1)                $wih(2)                {Barton Deakin Watson}   \
94323f71920Sdan  5  $wih(2)                $wih(1)                {Barton Deakin Watson}   \
94423f71920Sdan  6  $wih(2)                $wih(2)                {Barton Deakin Watson}   \
94523f71920Sdan  7  $wih(1)                $wih(1)                {Barton Deakin}          \
94610f5a50eSdan  8  {0 0 0 0 0 0 0 0 0 0 0 0} {0 0 0 0 0 0 0 0 0 0 0 0} {Barton Deakin Watson}
94723f71920Sdan] {
94823f71920Sdan  do_test wal2-9.$tn {
94923f71920Sdan    set_tvfs_hdr $::filename $hdr1 $hdr2
95023dced35Sdan    execsql { SELECT * FROM x } db2
95123f71920Sdan  } $res
95223f71920Sdan}
95323dced35Sdan
95423dced35Sdandb2 close
95523dced35Sdandb close
9568067adbcSdan
95710f5a50eSdan#-------------------------------------------------------------------------
95810f5a50eSdan# This block of tests - wal2-10.* - focus on the libraries response to
95910f5a50eSdan# new versions of the wal or wal-index formats.
96010f5a50eSdan#
96110f5a50eSdan#   wal2-10.1.*: Test that the library refuses to "recover" a new WAL
96210f5a50eSdan#                format.
96310f5a50eSdan#
96410f5a50eSdan#   wal2-10.2.*: Test that the library refuses to read or write a database
96510f5a50eSdan#                if the wal-index version is newer than it understands.
96610f5a50eSdan#
96710f5a50eSdan# At time of writing, the only versions of the wal and wal-index formats
96810f5a50eSdan# that exist are versions 3007000 (corresponding to SQLite version 3.7.0,
96910f5a50eSdan# the first version of SQLite to feature wal mode).
97010f5a50eSdan#
97110f5a50eSdando_test wal2-10.1.1 {
97210f5a50eSdan  faultsim_delete_and_reopen
97310f5a50eSdan  execsql {
97410f5a50eSdan    PRAGMA journal_mode = WAL;
97510f5a50eSdan    CREATE TABLE t1(a, b);
97610f5a50eSdan    PRAGMA wal_checkpoint;
97710f5a50eSdan    INSERT INTO t1 VALUES(1, 2);
97810f5a50eSdan    INSERT INTO t1 VALUES(3, 4);
97910f5a50eSdan  }
98010f5a50eSdan  faultsim_save_and_close
98110f5a50eSdan} {}
98210f5a50eSdando_test wal2-10.1.2 {
98310f5a50eSdan  faultsim_restore_and_reopen
98410f5a50eSdan  execsql { SELECT * FROM t1 }
98510f5a50eSdan} {1 2 3 4}
98610f5a50eSdando_test wal2-10.1.3 {
98710f5a50eSdan  faultsim_restore_and_reopen
98810f5a50eSdan  set hdr [wal_set_walhdr test.db-wal]
98910f5a50eSdan  lindex $hdr 1
99010f5a50eSdan} {3007000}
99110f5a50eSdando_test wal2-10.1.4 {
99210f5a50eSdan  lset hdr 1 3007001
99310f5a50eSdan  wal_set_walhdr test.db-wal $hdr
99410f5a50eSdan  catchsql { SELECT * FROM t1 }
99510f5a50eSdan} {1 {unable to open database file}}
99610f5a50eSdan
99710f5a50eSdantestvfs tvfs -default 1
99810f5a50eSdando_test wal2-10.2.1 {
99910f5a50eSdan  faultsim_restore_and_reopen
100010f5a50eSdan  execsql { SELECT * FROM t1 }
100110f5a50eSdan} {1 2 3 4}
100210f5a50eSdando_test wal2-10.2.2 {
100310f5a50eSdan  set hdr [set_tvfs_hdr $::filename]
100410f5a50eSdan  lindex $hdr 0
100510f5a50eSdan} {3007000}
100610f5a50eSdando_test wal2-10.2.3 {
100710f5a50eSdan  lset hdr 0 3007001
100810f5a50eSdan  wal_fix_walindex_cksum hdr
100910f5a50eSdan  set_tvfs_hdr $::filename $hdr
101010f5a50eSdan  catchsql { SELECT * FROM t1 }
101110f5a50eSdan} {1 {unable to open database file}}
1012c3857934Sdandb close
1013c3857934Sdantvfs delete
1014c3857934Sdan
1015c3857934Sdan#-------------------------------------------------------------------------
1016c3857934Sdan# This block of tests - wal2-11.* - tests that it is not possible to put
1017c3857934Sdan# the library into an infinite loop by presenting it with a corrupt
1018c3857934Sdan# hash table (one that appears to contain a single chain of infinite
1019c3857934Sdan# length).
1020c3857934Sdan#
1021c3857934Sdan#   wal2-11.1.*: While reading the hash-table.
1022c3857934Sdan#
1023c3857934Sdan#   wal2-11.2.*: While writing the hash-table.
1024c3857934Sdan#
1025c3857934Sdantestvfs tvfs -default 1
1026c3857934Sdando_test wal2-11.0 {
1027c3857934Sdan  faultsim_delete_and_reopen
1028c3857934Sdan  execsql {
1029c3857934Sdan    PRAGMA journal_mode = WAL;
1030c3857934Sdan    CREATE TABLE t1(a, b, c);
1031c3857934Sdan    INSERT INTO t1 VALUES(1, 2, 3);
1032c3857934Sdan    INSERT INTO t1 VALUES(4, 5, 6);
1033c3857934Sdan    INSERT INTO t1 VALUES(7, 8, 9);
1034c3857934Sdan    SELECT * FROM t1;
1035c3857934Sdan  }
1036c3857934Sdan} {wal 1 2 3 4 5 6 7 8 9}
1037c3857934Sdan
1038c3857934Sdando_test wal2-11.1.1 {
1039c3857934Sdan  sqlite3 db2 test.db
1040c3857934Sdan  execsql { SELECT name FROM sqlite_master } db2
1041c3857934Sdan} {t1}
1042c3857934Sdan
10439e5f1074Sdrhif {$::tcl_version>=8.5} {
1044e84322e5Sdan  # Set all zeroed slots in the first hash table to invalid values.
1045e84322e5Sdan  #
1046e84322e5Sdan  set blob [string range [tvfs shm $::filename] 0 16383]
1047e84322e5Sdan  set I [string range [tvfs shm $::filename] 16384 end]
1048e84322e5Sdan  binary scan $I t* L
1049e84322e5Sdan  set I [list]
1050e84322e5Sdan  foreach p $L {
1051e84322e5Sdan    lappend I [expr $p ? $p : 400]
1052e84322e5Sdan  }
1053e84322e5Sdan  append blob [binary format t* $I]
1054e84322e5Sdan  tvfs shm $::filename $blob
1055e84322e5Sdan  do_test wal2-11.2 {
1056e84322e5Sdan    catchsql { INSERT INTO t1 VALUES(10, 11, 12) }
1057e84322e5Sdan  } {1 {database disk image is malformed}}
1058e84322e5Sdan
1059c3857934Sdan  # Fill up the hash table on the first page of shared memory with 0x55 bytes.
1060c3857934Sdan  #
1061c3857934Sdan  set blob [string range [tvfs shm $::filename] 0 16383]
1062e84322e5Sdan  append blob [string repeat [binary format c 55] 16384]
1063c3857934Sdan  tvfs shm $::filename $blob
1064e84322e5Sdan  do_test wal2-11.3 {
1065c3857934Sdan    catchsql { SELECT * FROM t1 } db2
1066c3857934Sdan  } {1 {database disk image is malformed}}
10679e5f1074Sdrh}
1068c3857934Sdan
1069c3857934Sdandb close
1070c3857934Sdandb2 close
1071c3857934Sdantvfs delete
107210f5a50eSdan
1073ddb0ac4bSdan#-------------------------------------------------------------------------
1074ddb0ac4bSdan# If a connection is required to create a WAL or SHM file, it creates
1075ddb0ac4bSdan# the new files with the same file-system permissions as the database
1076ddb0ac4bSdan# file itself. Test this.
1077ddb0ac4bSdan#
1078ddb0ac4bSdanif {$::tcl_platform(platform) == "unix"} {
1079ddb0ac4bSdan  faultsim_delete_and_reopen
10808c815d14Sdrh  # Changed on 2012-02-13: umask is deliberately ignored for -wal files.
10818c815d14Sdrh  #set umask [exec /bin/sh -c umask]
10828c815d14Sdrh  set umask 0
10838c815d14Sdrh
108450833e32Sdan
1085ddb0ac4bSdan  do_test wal2-12.1 {
1086ddb0ac4bSdan    sqlite3 db test.db
1087ddb0ac4bSdan    execsql {
1088ddb0ac4bSdan      CREATE TABLE tx(y, z);
1089ddb0ac4bSdan      PRAGMA journal_mode = WAL;
1090ddb0ac4bSdan    }
1091ddb0ac4bSdan    db close
1092ddb0ac4bSdan    list [file exists test.db-wal] [file exists test.db-shm]
1093ddb0ac4bSdan  } {0 0}
1094ddb0ac4bSdan
1095ddb0ac4bSdan  foreach {tn permissions} {
1096ddb0ac4bSdan   1 00644
1097ddb0ac4bSdan   2 00666
1098ddb0ac4bSdan   3 00600
1099ddb0ac4bSdan   4 00755
1100ddb0ac4bSdan  } {
1101ddb0ac4bSdan    set effective [format %.5o [expr $permissions & ~$umask]]
1102ddb0ac4bSdan    do_test wal2-12.2.$tn.1 {
1103ddb0ac4bSdan      file attributes test.db -permissions $permissions
1104158931abSdrh      string map {o 0} [file attributes test.db -permissions]
1105ddb0ac4bSdan    } $permissions
1106ddb0ac4bSdan    do_test wal2-12.2.$tn.2 {
1107ddb0ac4bSdan      list [file exists test.db-wal] [file exists test.db-shm]
1108ddb0ac4bSdan    } {0 0}
1109ddb0ac4bSdan    do_test wal2-12.2.$tn.3 {
1110ddb0ac4bSdan      sqlite3 db test.db
1111ddb0ac4bSdan      execsql { INSERT INTO tx DEFAULT VALUES }
1112ddb0ac4bSdan      list [file exists test.db-wal] [file exists test.db-shm]
1113ddb0ac4bSdan    } {1 1}
1114ddb0ac4bSdan    do_test wal2-12.2.$tn.4 {
1115158931abSdrh      set x [list [file attr test.db-wal -perm] [file attr test.db-shm -perm]]
1116158931abSdrh      string map {o 0} $x
1117ddb0ac4bSdan    } [list $effective $effective]
1118ddb0ac4bSdan    do_test wal2-12.2.$tn.5 {
1119ddb0ac4bSdan      db close
1120ddb0ac4bSdan      list [file exists test.db-wal] [file exists test.db-shm]
1121ddb0ac4bSdan    } {0 0}
1122ddb0ac4bSdan  }
1123ddb0ac4bSdan}
1124ddb0ac4bSdan
112550833e32Sdan#-------------------------------------------------------------------------
112650833e32Sdan# Test the libraries response to discovering that one or more of the
112750833e32Sdan# database, wal or shm files cannot be opened, or can only be opened
112850833e32Sdan# read-only.
112950833e32Sdan#
113050833e32Sdanif {$::tcl_platform(platform) == "unix"} {
113150833e32Sdan  proc perm {} {
113250833e32Sdan    set L [list]
113350833e32Sdan    foreach f {test.db test.db-wal test.db-shm} {
113450833e32Sdan      if {[file exists $f]} {
113550833e32Sdan        lappend L [file attr $f -perm]
113650833e32Sdan      } else {
113750833e32Sdan        lappend L {}
113850833e32Sdan      }
113950833e32Sdan    }
114050833e32Sdan    set L
114150833e32Sdan  }
114250833e32Sdan
114350833e32Sdan  faultsim_delete_and_reopen
114450833e32Sdan  execsql {
114550833e32Sdan    PRAGMA journal_mode = WAL;
114650833e32Sdan    CREATE TABLE t1(a, b);
114750833e32Sdan    PRAGMA wal_checkpoint;
114850833e32Sdan    INSERT INTO t1 VALUES('3.14', '2.72');
114950833e32Sdan  }
115050833e32Sdan  do_test wal2-13.1.1 {
115150833e32Sdan    list [file exists test.db-shm] [file exists test.db-wal]
115250833e32Sdan  } {1 1}
115350833e32Sdan  faultsim_save_and_close
115450833e32Sdan
115550833e32Sdan  foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} {
115650833e32Sdan    2   00644   00644   00644   1   1   1
11571e5de5a1Sdan    3   00644   00400   00644   1   1   0
1158f12ba66cSdan    4   00644   00644   00400   1   1   0
115950833e32Sdan    5   00400   00644   00644   1   1   0
116050833e32Sdan
116150833e32Sdan    7   00644   00000   00644   1   0   0
116250833e32Sdan    8   00644   00644   00000   1   0   0
116350833e32Sdan    9   00000   00644   00644   0   0   0
116450833e32Sdan  } {
116550833e32Sdan    faultsim_restore
116650833e32Sdan    do_test wal2-13.$tn.1 {
116750833e32Sdan      file attr test.db     -perm $db_perm
116850833e32Sdan      file attr test.db-wal -perm $wal_perm
116950833e32Sdan      file attr test.db-shm -perm $shm_perm
117050833e32Sdan
117150833e32Sdan      set     L [file attr test.db -perm]
117250833e32Sdan      lappend L [file attr test.db-wal -perm]
117350833e32Sdan      lappend L [file attr test.db-shm -perm]
1174158931abSdrh      string map {o 0} $L
117550833e32Sdan    } [list $db_perm $wal_perm $shm_perm]
117650833e32Sdan
117750833e32Sdan    # If $can_open is true, then it should be possible to open a database
117850833e32Sdan    # handle. Otherwise, if $can_open is 0, attempting to open the db
117950833e32Sdan    # handle throws an "unable to open database file" exception.
118050833e32Sdan    #
118150833e32Sdan    set r(1) {0 ok}
118250833e32Sdan    set r(0) {1 {unable to open database file}}
118350833e32Sdan    do_test wal2-13.$tn.2 {
118450833e32Sdan      list [catch {sqlite3 db test.db ; set {} ok} msg] $msg
118550833e32Sdan    } $r($can_open)
118650833e32Sdan
118750833e32Sdan    if {$can_open} {
118850833e32Sdan
118950833e32Sdan      # If $can_read is true, then the client should be able to read from
119050833e32Sdan      # the database file. If $can_read is false, attempting to read should
119150833e32Sdan      # throw the "unable to open database file" exception.
119250833e32Sdan      #
119350833e32Sdan      set a(0) {1 {unable to open database file}}
119450833e32Sdan      set a(1) {0 {3.14 2.72}}
119550833e32Sdan      do_test wal2-13.$tn.3 {
119650833e32Sdan        catchsql { SELECT * FROM t1 }
119750833e32Sdan      } $a($can_read)
119850833e32Sdan
119950833e32Sdan      # Now try to write to the db file. If the client can read but not
120050833e32Sdan      # write, then it should throw the familiar "unable to open db file"
120150833e32Sdan      # exception. If it can read but not write, the exception should
120250833e32Sdan      # be "attempt to write a read only database".
120350833e32Sdan      #
120450833e32Sdan      # If the client can read and write, the operation should succeed.
120550833e32Sdan      #
120650833e32Sdan      set b(0,0) {1 {unable to open database file}}
120750833e32Sdan      set b(1,0) {1 {attempt to write a readonly database}}
120850833e32Sdan      set b(1,1) {0 {}}
120950833e32Sdan      do_test wal2-13.$tn.4 {
121050833e32Sdan        catchsql { INSERT INTO t1 DEFAULT VALUES }
121150833e32Sdan      } $b($can_read,$can_write)
121250833e32Sdan    }
121350833e32Sdan    catch { db close }
121450833e32Sdan  }
121550833e32Sdan}
121611f273fcSdan
121711f273fcSdan#-------------------------------------------------------------------------
121811f273fcSdan# Test that "PRAGMA checkpoint_fullsync" appears to be working.
121911f273fcSdan#
122011f273fcSdanforeach {tn sql reslist} {
12214eb02a45Sdrh  1 { }                                 {10 0 4 0 6 0}
1222daaae7b9Sdrh  2 { PRAGMA checkpoint_fullfsync = 1 } {10 6 4 3 6 3}
12234eb02a45Sdrh  3 { PRAGMA checkpoint_fullfsync = 0 } {10 0 4 0 6 0}
122411f273fcSdan} {
1225108e5a9aSdrh  ifcapable default_ckptfullfsync {
1226108e5a9aSdrh    if {[string trim $sql]==""} continue
1227108e5a9aSdrh  }
122811f273fcSdan  faultsim_delete_and_reopen
122911f273fcSdan
1230e243de5cSdrh  execsql {PRAGMA auto_vacuum = 0; PRAGMA synchronous = FULL;}
123111f273fcSdan  execsql $sql
12320774bb59Sdan  do_execsql_test wal2-14.$tn.0 { PRAGMA page_size = 4096 }   {}
123311f273fcSdan  do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}
123411f273fcSdan
123511f273fcSdan  set sqlite_sync_count 0
123611f273fcSdan  set sqlite_fullsync_count 0
123711f273fcSdan
123811f273fcSdan  do_execsql_test wal2-14.$tn.2 {
123911f273fcSdan    PRAGMA wal_autocheckpoint = 10;
124011f273fcSdan    CREATE TABLE t1(a, b);                -- 2 wal syncs
12414eb02a45Sdrh    INSERT INTO t1 VALUES(1, 2);          -- 2 wal sync
124211f273fcSdan    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
124311f273fcSdan    BEGIN;
124411f273fcSdan      INSERT INTO t1 VALUES(3, 4);
124511f273fcSdan      INSERT INTO t1 VALUES(5, 6);
12464eb02a45Sdrh    COMMIT;                               -- 2 wal sync
124711f273fcSdan    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
12480774bb59Sdan  } {10 0 3 3 0 1 1}
124911f273fcSdan
125011f273fcSdan  do_test wal2-14.$tn.3 {
12519dd6e080Sshaneh    cond_incr_sync_count 1
125211f273fcSdan    list $sqlite_sync_count $sqlite_fullsync_count
125311f273fcSdan  } [lrange $reslist 0 1]
125411f273fcSdan
125511f273fcSdan  set sqlite_sync_count 0
125611f273fcSdan  set sqlite_fullsync_count 0
125711f273fcSdan
125811f273fcSdan  do_test wal2-14.$tn.4 {
125911f273fcSdan    execsql { INSERT INTO t1 VALUES(7, zeroblob(12*4096)) }
126011f273fcSdan    list $sqlite_sync_count $sqlite_fullsync_count
126111f273fcSdan  } [lrange $reslist 2 3]
126211f273fcSdan
126311f273fcSdan  set sqlite_sync_count 0
126411f273fcSdan  set sqlite_fullsync_count 0
126511f273fcSdan
126611f273fcSdan  do_test wal2-14.$tn.5 {
126711f273fcSdan    execsql { PRAGMA wal_autocheckpoint = 1000 }
126811f273fcSdan    execsql { INSERT INTO t1 VALUES(9, 10) }
126911f273fcSdan    execsql { INSERT INTO t1 VALUES(11, 12) }
127011f273fcSdan    execsql { INSERT INTO t1 VALUES(13, 14) }
127111f273fcSdan    db close
127211f273fcSdan    list $sqlite_sync_count $sqlite_fullsync_count
127311f273fcSdan  } [lrange $reslist 4 5]
127411f273fcSdan}
127511f273fcSdan
127618826195Sdancatch { db close }
127718826195Sdan
127818826195Sdan# PRAGMA checkpoint_fullsync
127918826195Sdan# PRAGMA fullfsync
128018826195Sdan# PRAGMA synchronous
128118826195Sdan#
12824eb02a45Sdrhforeach {tn settings restart_sync commit_sync ckpt_sync} {
12834eb02a45Sdrh  1  {0 0 off}     {0 0}  {0 0}  {0 0}
12844eb02a45Sdrh  2  {0 0 normal}  {1 0}  {0 0}  {2 0}
12854eb02a45Sdrh  3  {0 0 full}    {2 0}  {1 0}  {2 0}
128618826195Sdan
12874eb02a45Sdrh  4  {0 1 off}     {0 0}  {0 0}  {0 0}
12884eb02a45Sdrh  5  {0 1 normal}  {0 1}  {0 0}  {0 2}
12894eb02a45Sdrh  6  {0 1 full}    {0 2}  {0 1}  {0 2}
129018826195Sdan
12914eb02a45Sdrh  7  {1 0 off}     {0 0}  {0 0}  {0 0}
1292daaae7b9Sdrh  8  {1 0 normal}  {0 1}  {0 0}  {0 2}
1293daaae7b9Sdrh  9  {1 0 full}    {1 1}  {1 0}  {0 2}
129418826195Sdan
12954eb02a45Sdrh  10 {1 1 off}     {0 0}  {0 0}  {0 0}
12964eb02a45Sdrh  11 {1 1 normal}  {0 1}  {0 0}  {0 2}
12974eb02a45Sdrh  12 {1 1 full}    {0 2}  {0 1}  {0 2}
129818826195Sdan} {
129918826195Sdan  forcedelete test.db
130018826195Sdan
130118826195Sdan  testvfs tvfs -default 1
130218826195Sdan  tvfs filter xSync
130318826195Sdan  tvfs script xSyncCb
130418826195Sdan  proc xSyncCb {method file fileid flags} {
130518826195Sdan    incr ::sync($flags)
130618826195Sdan  }
130718826195Sdan
130818826195Sdan  sqlite3 db test.db
130918826195Sdan  do_execsql_test 15.$tn.1 "
13100774bb59Sdan    PRAGMA page_size = 4096;
131118826195Sdan    CREATE TABLE t1(x);
13124eb02a45Sdrh    PRAGMA wal_autocheckpoint = OFF;
131318826195Sdan    PRAGMA journal_mode = WAL;
131418826195Sdan    PRAGMA checkpoint_fullfsync = [lindex $settings 0];
131518826195Sdan    PRAGMA fullfsync = [lindex $settings 1];
131618826195Sdan    PRAGMA synchronous = [lindex $settings 2];
13174eb02a45Sdrh  " {0 wal}
131818826195Sdan
131918826195Sdan  do_test 15.$tn.2 {
132018826195Sdan    set sync(normal) 0
132118826195Sdan    set sync(full) 0
132218826195Sdan    execsql { INSERT INTO t1 VALUES('abc') }
132318826195Sdan    list $::sync(normal) $::sync(full)
13244eb02a45Sdrh  } $restart_sync
132518826195Sdan
132618826195Sdan  do_test 15.$tn.3 {
132718826195Sdan    set sync(normal) 0
132818826195Sdan    set sync(full) 0
13294eb02a45Sdrh    execsql { INSERT INTO t1 VALUES('abc') }
13304eb02a45Sdrh    list $::sync(normal) $::sync(full)
13314eb02a45Sdrh  } $commit_sync
13324eb02a45Sdrh
13334eb02a45Sdrh  do_test 15.$tn.4 {
13344eb02a45Sdrh    set sync(normal) 0
13354eb02a45Sdrh    set sync(full) 0
133618826195Sdan    execsql { INSERT INTO t1 VALUES('def') }
133718826195Sdan    list $::sync(normal) $::sync(full)
133818826195Sdan  } $commit_sync
133918826195Sdan
13404eb02a45Sdrh  do_test 15.$tn.5 {
134118826195Sdan    set sync(normal) 0
134218826195Sdan    set sync(full) 0
134318826195Sdan    execsql { PRAGMA wal_checkpoint }
134418826195Sdan    list $::sync(normal) $::sync(full)
134518826195Sdan  } $ckpt_sync
134618826195Sdan
134718826195Sdan  db close
134818826195Sdan  tvfs delete
134918826195Sdan}
135018826195Sdan
135111f273fcSdan
135250833e32Sdan
13539a6b4e9aSdanfinish_test
1354