walro.test 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. # 2011 May 09
  2. #
  3. # The author disclaims copyright to this source code. In place of
  4. # a legal notice, here is a blessing:
  5. #
  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.
  9. #
  10. #***********************************************************************
  11. #
  12. # This file contains tests for using WAL databases in read-only mode.
  13. #
  14. set testdir [file dirname $argv0]
  15. source $testdir/tester.tcl
  16. source $testdir/lock_common.tcl
  17. set ::testprefix walro
  18. # These tests are only going to work on unix.
  19. #
  20. if {$::tcl_platform(platform) != "unix"} {
  21. finish_test
  22. return
  23. }
  24. # And only if the build is WAL-capable.
  25. #
  26. ifcapable !wal {
  27. finish_test
  28. return
  29. }
  30. do_multiclient_test tn {
  31. # Do not run tests with the connections in the same process.
  32. #
  33. if {$tn==2} continue
  34. # Close all connections and delete the database.
  35. #
  36. code1 { db close }
  37. code2 { db2 close }
  38. code3 { db3 close }
  39. forcedelete test.db
  40. forcedelete walro
  41. foreach c {code1 code2 code3} {
  42. $c {
  43. sqlite3_shutdown
  44. sqlite3_config_uri 1
  45. }
  46. }
  47. file mkdir walro
  48. do_test 1.1.1 {
  49. code2 { sqlite3 db2 test.db }
  50. sql2 {
  51. PRAGMA auto_vacuum = 0;
  52. PRAGMA journal_mode = WAL;
  53. CREATE TABLE t1(x, y);
  54. INSERT INTO t1 VALUES('a', 'b');
  55. }
  56. file exists test.db-shm
  57. } {1}
  58. do_test 1.1.2 {
  59. file attributes test.db-shm -permissions r--r--r--
  60. code1 { sqlite3 db file:test.db?readonly_shm=1 }
  61. } {}
  62. do_test 1.1.3 { sql1 "SELECT * FROM t1" } {a b}
  63. do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
  64. do_test 1.1.5 { sql1 "SELECT * FROM t1" } {a b c d}
  65. # Check that the read-only connection cannot write or checkpoint the db.
  66. #
  67. do_test 1.1.6 {
  68. csql1 "INSERT INTO t1 VALUES('e', 'f')"
  69. } {1 {attempt to write a readonly database}}
  70. do_test 1.1.7 {
  71. csql1 "PRAGMA wal_checkpoint"
  72. } {1 {attempt to write a readonly database}}
  73. do_test 1.1.9 { sql2 "INSERT INTO t1 VALUES('e', 'f')" } {}
  74. do_test 1.1.10 { sql1 "SELECT * FROM t1" } {a b c d e f}
  75. do_test 1.1.11 {
  76. sql2 {
  77. INSERT INTO t1 VALUES('g', 'h');
  78. PRAGMA wal_checkpoint;
  79. }
  80. set {} {}
  81. } {}
  82. do_test 1.1.12 { sql1 "SELECT * FROM t1" } {a b c d e f g h}
  83. do_test 1.1.13 { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}
  84. do_test 1.2.1 {
  85. code2 { db2 close }
  86. code1 { db close }
  87. list [file exists test.db-wal] [file exists test.db-shm]
  88. } {1 1}
  89. do_test 1.2.2 {
  90. code1 { sqlite3 db file:test.db?readonly_shm=1 }
  91. sql1 { SELECT * FROM t1 }
  92. } {a b c d e f g h i j}
  93. do_test 1.2.3 {
  94. code1 { db close }
  95. file attributes test.db-shm -permissions rw-r--r--
  96. hexio_write test.db-shm 0 01020304
  97. file attributes test.db-shm -permissions r--r--r--
  98. code1 { sqlite3 db file:test.db?readonly_shm=1 }
  99. csql1 { SELECT * FROM t1 }
  100. } {1 {attempt to write a readonly database}}
  101. do_test 1.2.4 {
  102. code1 { sqlite3_extended_errcode db }
  103. } {SQLITE_READONLY_RECOVERY}
  104. do_test 1.2.5 {
  105. file attributes test.db-shm -permissions rw-r--r--
  106. code2 { sqlite3 db2 test.db }
  107. sql2 "SELECT * FROM t1"
  108. } {a b c d e f g h i j}
  109. file attributes test.db-shm -permissions r--r--r--
  110. do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}
  111. do_test 1.2.7 {
  112. sql2 {
  113. PRAGMA wal_checkpoint;
  114. INSERT INTO t1 VALUES('k', 'l');
  115. }
  116. set {} {}
  117. } {}
  118. do_test 1.2.8 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j k l}
  119. # Now check that if the readonly_shm option is not supplied, or if it
  120. # is set to zero, it is not possible to connect to the database without
  121. # read-write access to the shm.
  122. do_test 1.3.1 {
  123. code1 { db close }
  124. code1 { sqlite3 db test.db }
  125. csql1 { SELECT * FROM t1 }
  126. } {1 {unable to open database file}}
  127. # Also test that if the -shm file can be opened for read/write access,
  128. # it is not if readonly_shm=1 is present in the URI.
  129. do_test 1.3.2.1 {
  130. code1 { db close }
  131. code2 { db2 close }
  132. file exists test.db-shm
  133. } {0}
  134. do_test 1.3.2.2 {
  135. code1 { sqlite3 db file:test.db?readonly_shm=1 }
  136. csql1 { SELECT * FROM sqlite_master }
  137. } {1 {unable to open database file}}
  138. do_test 1.3.2.3 {
  139. code1 { db close }
  140. close [open test.db-shm w]
  141. file attributes test.db-shm -permissions r--r--r--
  142. code1 { sqlite3 db file:test.db?readonly_shm=1 }
  143. csql1 { SELECT * FROM t1 }
  144. } {1 {attempt to write a readonly database}}
  145. do_test 1.3.2.4 {
  146. code1 { sqlite3_extended_errcode db }
  147. } {SQLITE_READONLY_RECOVERY}
  148. #-----------------------------------------------------------------------
  149. # Test cases 1.4.* check that checkpoints and log wraps don't prevent
  150. # read-only connections from reading the database.
  151. do_test 1.4.1 {
  152. code1 { db close }
  153. forcedelete test.db-shm
  154. file exists test.db-shm
  155. } {0}
  156. # Open one read-only and one read-write connection. Write some data
  157. # and then run a checkpoint using the read-write connection. Then
  158. # check the read-only connection can still read.
  159. do_test 1.4.2 {
  160. code1 { sqlite3 db file:test.db?readonly_shm=1 }
  161. code2 { sqlite3 db2 test.db }
  162. csql2 {
  163. INSERT INTO t1 VALUES(1, 2);
  164. INSERT INTO t1 VALUES(3, 4);
  165. INSERT INTO t1 VALUES(5, 6);
  166. PRAGMA wal_checkpoint;
  167. }
  168. } {0 {0 3 3}}
  169. do_test 1.4.3 {
  170. csql1 { SELECT * FROM t1 }
  171. } {0 {a b c d e f g h i j k l 1 2 3 4 5 6}}
  172. # Using the read-write connection, open a transaction and write lots
  173. # of data - causing a cache spill and a log wrap. Then check that the
  174. # read-only connection can still read the database.
  175. do_test 1.4.4.1 {
  176. csql2 {
  177. PRAGMA cache_size = 10;
  178. BEGIN;
  179. CREATE TABLE t2(x, y);
  180. INSERT INTO t2 VALUES('abc', 'xyz');
  181. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  182. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  183. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  184. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  185. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  186. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  187. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  188. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  189. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  190. }
  191. file size test.db-wal
  192. } {147800}
  193. do_test 1.4.4.2 {
  194. csql1 { SELECT * FROM t1 }
  195. } {0 {a b c d e f g h i j k l 1 2 3 4 5 6}}
  196. do_test 1.4.4.3 {
  197. csql2 COMMIT
  198. csql1 { SELECT count(*) FROM t2 }
  199. } {0 512}
  200. do_test 1.4.5 {
  201. code2 { db2 close }
  202. code1 { db close }
  203. } {}
  204. }
  205. forcedelete test.db
  206. #-----------------------------------------------------------------------
  207. # Test cases 2.* check that a read-only connection may read the
  208. # database file while a checkpoint operation is ongoing.
  209. #
  210. do_multiclient_test tn {
  211. # Do not run tests with the connections in the same process.
  212. #
  213. if {$tn==2} continue
  214. # Close all connections and delete the database.
  215. #
  216. code1 { db close }
  217. code2 { db2 close }
  218. code3 { db3 close }
  219. forcedelete test.db
  220. forcedelete walro
  221. foreach c {code1 code2 code3} {
  222. $c {
  223. sqlite3_shutdown
  224. sqlite3_config_uri 1
  225. }
  226. }
  227. proc tv_hook {x file args} {
  228. if {[file tail $file]=="test.db-wal"} {
  229. do_test 2.1.2 {
  230. code2 { sqlite3 db2 file:test.db?readonly_shm=1 }
  231. csql2 { SELECT count(*) FROM t2 }
  232. } {0 4}
  233. do_test 2.1.3 {
  234. code2 { db2 close }
  235. } {}
  236. }
  237. }
  238. do_test 2.1.1 {
  239. testvfs tv -default 1 -fullshm 1
  240. tv script tv_hook
  241. tv filter {}
  242. code1 { sqlite3 db test.db }
  243. csql1 {
  244. PRAGMA auto_vacuum = 0;
  245. PRAGMA journal_mode = WAL;
  246. BEGIN;
  247. CREATE TABLE t2(x, y);
  248. INSERT INTO t2 VALUES('abc', 'xyz');
  249. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  250. INSERT INTO t2 SELECT x||y, y||x FROM t2;
  251. COMMIT;
  252. }
  253. } {0 wal}
  254. tv filter xSync
  255. set res [csql1 { PRAGMA wal_checkpoint }]
  256. do_test 2.1.4 { set res } {0 {0 2 2}}
  257. do_test 2.1.5 {
  258. code1 { db close }
  259. code1 { tv delete }
  260. } {}
  261. }
  262. finish_test