xref: /sqlite-3.40.0/test/walro.test (revision f12ba66c)
14edc6bf3Sdan# 2011 May 09
24edc6bf3Sdan#
34edc6bf3Sdan# The author disclaims copyright to this source code.  In place of
44edc6bf3Sdan# a legal notice, here is a blessing:
54edc6bf3Sdan#
64edc6bf3Sdan#    May you do good and not evil.
74edc6bf3Sdan#    May you find forgiveness for yourself and forgive others.
84edc6bf3Sdan#    May you share freely, never taking more than you give.
94edc6bf3Sdan#
104edc6bf3Sdan#***********************************************************************
114edc6bf3Sdan#
124edc6bf3Sdan# This file contains tests for using WAL databases in read-only mode.
134edc6bf3Sdan#
144edc6bf3Sdan
154edc6bf3Sdanset testdir [file dirname $argv0]
164edc6bf3Sdansource $testdir/tester.tcl
174edc6bf3Sdansource $testdir/lock_common.tcl
184edc6bf3Sdanset ::testprefix walro
194edc6bf3Sdan
204edc6bf3Sdan# These tests are only going to work on unix.
214edc6bf3Sdan#
2205fd9aabSshanehif {$::tcl_platform(platform) != "unix"} {
2305fd9aabSshaneh  finish_test
2405fd9aabSshaneh  return
2505fd9aabSshaneh}
264edc6bf3Sdan
275209132aSdan# And only if the build is WAL-capable.
285209132aSdan#
295209132aSdanifcapable !wal {
305209132aSdan  finish_test
315209132aSdan  return
325209132aSdan}
335209132aSdan
3405fd9aabSshanehdo_multiclient_test tn {
354edc6bf3Sdan
364edc6bf3Sdan  # Close all connections and delete the database.
374edc6bf3Sdan  #
384edc6bf3Sdan  code1 { db close  }
394edc6bf3Sdan  code2 { db2 close }
404edc6bf3Sdan  code3 { db3 close }
414edc6bf3Sdan  forcedelete test.db
424edc6bf3Sdan  forcedelete walro
434edc6bf3Sdan
4498c91905Sdan  # Do not run tests with the connections in the same process.
4598c91905Sdan  #
4698c91905Sdan  if {$tn==2} continue
4798c91905Sdan
48b6d2f9c5Sdan  foreach c {code1 code2 code3} {
49b6d2f9c5Sdan    $c {
50b6d2f9c5Sdan      sqlite3_shutdown
51b6d2f9c5Sdan      sqlite3_config_uri 1
52b6d2f9c5Sdan    }
53b6d2f9c5Sdan  }
54b6d2f9c5Sdan
554edc6bf3Sdan  file mkdir walro
564edc6bf3Sdan
574edc6bf3Sdan  do_test 1.1.1 {
584edc6bf3Sdan    code2 { sqlite3 db2 test.db }
594edc6bf3Sdan    sql2 {
6081f0740eSdan      PRAGMA auto_vacuum = 0;
614edc6bf3Sdan      PRAGMA journal_mode = WAL;
624edc6bf3Sdan      CREATE TABLE t1(x, y);
634edc6bf3Sdan      INSERT INTO t1 VALUES('a', 'b');
644edc6bf3Sdan    }
654edc6bf3Sdan    file exists test.db-shm
664edc6bf3Sdan  } {1}
674edc6bf3Sdan
684edc6bf3Sdan  do_test 1.1.2 {
694edc6bf3Sdan    file attributes test.db-shm -permissions r--r--r--
70b6d2f9c5Sdan    code1 { sqlite3 db file:test.db?readonly_shm=1 }
714edc6bf3Sdan  } {}
724edc6bf3Sdan
734edc6bf3Sdan  do_test 1.1.3 { sql1 "SELECT * FROM t1" }                {a b}
744edc6bf3Sdan  do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
754edc6bf3Sdan  do_test 1.1.5 { sql1 "SELECT * FROM t1" }                {a b c d}
764edc6bf3Sdan
774edc6bf3Sdan  # Check that the read-only connection cannot write or checkpoint the db.
784edc6bf3Sdan  #
794edc6bf3Sdan  do_test 1.1.6 {
804edc6bf3Sdan    csql1 "INSERT INTO t1 VALUES('e', 'f')"
814edc6bf3Sdan  } {1 {attempt to write a readonly database}}
824edc6bf3Sdan  do_test 1.1.7 {
834edc6bf3Sdan    csql1 "PRAGMA wal_checkpoint"
844edc6bf3Sdan  } {1 {attempt to write a readonly database}}
854edc6bf3Sdan
864edc6bf3Sdan  do_test 1.1.9  { sql2 "INSERT INTO t1 VALUES('e', 'f')" } {}
874edc6bf3Sdan  do_test 1.1.10 { sql1 "SELECT * FROM t1" }                {a b c d e f}
884edc6bf3Sdan
894edc6bf3Sdan  do_test 1.1.11 {
904edc6bf3Sdan    sql2 {
914edc6bf3Sdan      INSERT INTO t1 VALUES('g', 'h');
924edc6bf3Sdan      PRAGMA wal_checkpoint;
934edc6bf3Sdan    }
944edc6bf3Sdan    set {} {}
954edc6bf3Sdan  } {}
964edc6bf3Sdan  do_test 1.1.12 { sql1 "SELECT * FROM t1" }                {a b c d e f g h}
974edc6bf3Sdan  do_test 1.1.13  { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}
984edc6bf3Sdan
994edc6bf3Sdan  do_test 1.2.1 {
1004edc6bf3Sdan    code2 { db2 close }
1014edc6bf3Sdan    code1 { db close }
1024edc6bf3Sdan    list [file exists test.db-wal] [file exists test.db-shm]
1034edc6bf3Sdan  } {1 1}
104ab04eff8Sdan
1054edc6bf3Sdan  do_test 1.2.2 {
106b6d2f9c5Sdan    code1 { sqlite3 db file:test.db?readonly_shm=1 }
107ab04eff8Sdan    list [catch { sql1 { SELECT * FROM t1 } } msg] $msg
10811caf4f4Sdan  } {0 {a b c d e f g h i j}}
1094edc6bf3Sdan
1104edc6bf3Sdan  do_test 1.2.3 {
1114edc6bf3Sdan    code1 { db close }
1124edc6bf3Sdan    file attributes test.db-shm -permissions rw-r--r--
1134edc6bf3Sdan    hexio_write test.db-shm 0 01020304
1144edc6bf3Sdan    file attributes test.db-shm -permissions r--r--r--
115b6d2f9c5Sdan    code1 { sqlite3 db file:test.db?readonly_shm=1 }
1164edc6bf3Sdan    csql1 { SELECT * FROM t1 }
11711caf4f4Sdan  } {0 {a b c d e f g h i j}}
1184edc6bf3Sdan  do_test 1.2.4 {
1194edc6bf3Sdan    code1 { sqlite3_extended_errcode db }
12011caf4f4Sdan  } {SQLITE_OK}
1214edc6bf3Sdan
1224edc6bf3Sdan  do_test 1.2.5 {
1234edc6bf3Sdan    file attributes test.db-shm -permissions rw-r--r--
1244edc6bf3Sdan    code2 { sqlite3 db2 test.db }
1254edc6bf3Sdan    sql2 "SELECT * FROM t1"
1264edc6bf3Sdan  } {a b c d e f g h i j}
1274edc6bf3Sdan  file attributes test.db-shm -permissions r--r--r--
1284edc6bf3Sdan  do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}
1294edc6bf3Sdan
1304edc6bf3Sdan  do_test 1.2.7 {
1314edc6bf3Sdan    sql2 {
1324edc6bf3Sdan      PRAGMA wal_checkpoint;
1334edc6bf3Sdan      INSERT INTO t1 VALUES('k', 'l');
1344edc6bf3Sdan    }
1354edc6bf3Sdan    set {} {}
1364edc6bf3Sdan  } {}
1374edc6bf3Sdan  do_test 1.2.8 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j k l}
1383640db58Sdan
1393640db58Sdan  # Now check that if the readonly_shm option is not supplied, or if it
1403640db58Sdan  # is set to zero, it is not possible to connect to the database without
1413640db58Sdan  # read-write access to the shm.
142*f12ba66cSdan  #
143*f12ba66cSdan  # UPDATE: os_unix.c now opens the *-shm file in readonly mode
144*f12ba66cSdan  # automatically.
145*f12ba66cSdan  #
1463640db58Sdan  do_test 1.3.1 {
1473640db58Sdan    code1 { db close }
1483640db58Sdan    code1 { sqlite3 db test.db }
1493640db58Sdan    csql1 { SELECT * FROM t1 }
150*f12ba66cSdan  } {0 {a b c d e f g h i j k l}}
1513640db58Sdan
1523640db58Sdan  # Also test that if the -shm file can be opened for read/write access,
1533ec4a0c1Sdrh  # it is not if readonly_shm=1 is present in the URI.
1543640db58Sdan  do_test 1.3.2.1 {
1553640db58Sdan    code1 { db close }
1563640db58Sdan    code2 { db2 close }
1573640db58Sdan    file exists test.db-shm
1583640db58Sdan  } {0}
1593640db58Sdan  do_test 1.3.2.2 {
1603640db58Sdan    code1 { sqlite3 db file:test.db?readonly_shm=1 }
1613ec4a0c1Sdrh    csql1 { SELECT * FROM sqlite_master }
1623ec4a0c1Sdrh  } {1 {unable to open database file}}
1633640db58Sdan  do_test 1.3.2.3 {
1643640db58Sdan    code1 { db close }
1653640db58Sdan    close [open test.db-shm w]
1663640db58Sdan    file attributes test.db-shm -permissions r--r--r--
1673640db58Sdan    code1 { sqlite3 db file:test.db?readonly_shm=1 }
1683640db58Sdan    csql1 { SELECT * FROM t1 }
16911caf4f4Sdan  } {0 {a b c d e f g h i j k l}}
1703640db58Sdan  do_test 1.3.2.4 {
1713640db58Sdan    code1 { sqlite3_extended_errcode db }
17211caf4f4Sdan  } {SQLITE_OK}
1735373b76bSdan
1745373b76bSdan  #-----------------------------------------------------------------------
1755373b76bSdan  # Test cases 1.4.* check that checkpoints and log wraps don't prevent
1765373b76bSdan  # read-only connections from reading the database.
1775373b76bSdan  do_test 1.4.1 {
1785373b76bSdan    code1 { db close }
1795373b76bSdan    forcedelete test.db-shm
1805373b76bSdan    file exists test.db-shm
1815373b76bSdan  } {0}
1825373b76bSdan
1835373b76bSdan  # Open one read-only and one read-write connection. Write some data
1845373b76bSdan  # and then run a checkpoint using the read-write connection. Then
1855373b76bSdan  # check the read-only connection can still read.
1865373b76bSdan  do_test 1.4.2 {
1875373b76bSdan    code1 { sqlite3 db file:test.db?readonly_shm=1 }
1885373b76bSdan    code2 { sqlite3 db2 test.db }
1895373b76bSdan    csql2 {
1905373b76bSdan      INSERT INTO t1 VALUES(1, 2);
1915373b76bSdan      INSERT INTO t1 VALUES(3, 4);
1925373b76bSdan      INSERT INTO t1 VALUES(5, 6);
1935373b76bSdan      PRAGMA wal_checkpoint;
1945373b76bSdan    }
1955373b76bSdan  } {0 {0 3 3}}
1965373b76bSdan  do_test 1.4.3 {
1975373b76bSdan    csql1 { SELECT * FROM t1 }
1985373b76bSdan  } {0 {a b c d e f g h i j k l 1 2 3 4 5 6}}
1995373b76bSdan
2005373b76bSdan  # Using the read-write connection, open a transaction and write lots
2015373b76bSdan  # of data - causing a cache spill and a log wrap. Then check that the
2025373b76bSdan  # read-only connection can still read the database.
2035373b76bSdan  do_test 1.4.4.1 {
2045373b76bSdan    csql2 {
2055373b76bSdan      PRAGMA cache_size = 10;
2065373b76bSdan      BEGIN;
2075373b76bSdan      CREATE TABLE t2(x, y);
2085373b76bSdan      INSERT INTO t2 VALUES('abc', 'xyz');
2095373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2105373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2115373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2125373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2135373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2145373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2155373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2165373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2175373b76bSdan      INSERT INTO t2 SELECT x||y, y||x FROM t2;
2185373b76bSdan    }
2195373b76bSdan    file size test.db-wal
2207da56b4fSdrh  } [expr {[nonzero_reserved_bytes]?148848:147800}]
2215373b76bSdan  do_test 1.4.4.2 {
2225373b76bSdan    csql1 { SELECT * FROM t1 }
2235373b76bSdan  } {0 {a b c d e f g h i j k l 1 2 3 4 5 6}}
2245373b76bSdan  do_test 1.4.4.3 {
2255373b76bSdan    csql2 COMMIT
2265373b76bSdan    csql1 { SELECT count(*) FROM t2 }
2275373b76bSdan  } {0 512}
2285373b76bSdan  do_test 1.4.5 {
2295373b76bSdan    code2 { db2 close }
2305373b76bSdan    code1 { db close }
2315373b76bSdan  } {}
2325373b76bSdan}
2335373b76bSdan
2345373b76bSdanforcedelete test.db
2355373b76bSdan
2365373b76bSdan#-----------------------------------------------------------------------
2375373b76bSdan# Test cases 2.* check that a read-only connection may read the
2385373b76bSdan# database file while a checkpoint operation is ongoing.
2395373b76bSdan#
2405373b76bSdando_multiclient_test tn {
2415373b76bSdan
2425373b76bSdan  # Close all connections and delete the database.
2435373b76bSdan  #
2445373b76bSdan  code1 { db close  }
2455373b76bSdan  code2 { db2 close }
2465373b76bSdan  code3 { db3 close }
2475373b76bSdan  forcedelete test.db
2485373b76bSdan  forcedelete walro
2495373b76bSdan
25098c91905Sdan  # Do not run tests with the connections in the same process.
25198c91905Sdan  #
25298c91905Sdan  if {$tn==2} continue
25398c91905Sdan
2545373b76bSdan  foreach c {code1 code2 code3} {
2555373b76bSdan    $c {
2565373b76bSdan      sqlite3_shutdown
2575373b76bSdan      sqlite3_config_uri 1
2585373b76bSdan    }
2595373b76bSdan  }
2605373b76bSdan
2615373b76bSdan  proc tv_hook {x file args} {
2625373b76bSdan    if {[file tail $file]=="test.db-wal"} {
2635373b76bSdan      do_test 2.1.2 {
2645373b76bSdan        code2 { sqlite3 db2 file:test.db?readonly_shm=1 }
2655373b76bSdan        csql2 { SELECT count(*) FROM t2 }
2665373b76bSdan      } {0 4}
2675373b76bSdan      do_test 2.1.3 {
2685373b76bSdan        code2 { db2 close }
2695373b76bSdan      } {}
2705373b76bSdan    }
2715373b76bSdan  }
2725373b76bSdan
2735373b76bSdan  do_test 2.1.1 {
2745373b76bSdan    testvfs tv -default 1 -fullshm 1
2755373b76bSdan    tv script tv_hook
2765373b76bSdan    tv filter {}
2775373b76bSdan    code1 { sqlite3 db test.db }
2785373b76bSdan    csql1 {
27981f0740eSdan      PRAGMA auto_vacuum = 0;
2805373b76bSdan      PRAGMA journal_mode = WAL;
2815373b76bSdan      BEGIN;
2825373b76bSdan        CREATE TABLE t2(x, y);
2835373b76bSdan        INSERT INTO t2 VALUES('abc', 'xyz');
2845373b76bSdan        INSERT INTO t2 SELECT x||y, y||x FROM t2;
2855373b76bSdan        INSERT INTO t2 SELECT x||y, y||x FROM t2;
2865373b76bSdan      COMMIT;
2875373b76bSdan    }
2885373b76bSdan  } {0 wal}
2895373b76bSdan
2905373b76bSdan  tv filter xSync
2915373b76bSdan  set res [csql1 { PRAGMA wal_checkpoint }]
2925373b76bSdan  do_test 2.1.4 { set res } {0 {0 2 2}}
2935373b76bSdan
2945373b76bSdan  do_test 2.1.5 {
2955373b76bSdan    code1 { db close }
2965373b76bSdan    code1 { tv delete }
2975373b76bSdan  } {}
2984edc6bf3Sdan}
2994edc6bf3Sdan
3004edc6bf3Sdanfinish_test
301