OLD | NEW |
| (Empty) |
1 # 2015 December 7 | |
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 # This file implements regression tests for SQLite library. The focus | |
12 # of this file is the sqlite3_snapshot_xxx() APIs. | |
13 # | |
14 | |
15 set testdir [file dirname $argv0] | |
16 source $testdir/tester.tcl | |
17 ifcapable !snapshot {finish_test; return} | |
18 set testprefix snapshot | |
19 | |
20 #------------------------------------------------------------------------- | |
21 # Check some error conditions in snapshot_get(). It is an error if: | |
22 # | |
23 # 1) snapshot_get() is called on a non-WAL database, or | |
24 # 2) there is an open write transaction on the database. | |
25 # | |
26 do_execsql_test 1.0 { | |
27 CREATE TABLE t1(a, b); | |
28 INSERT INTO t1 VALUES(1, 2); | |
29 INSERT INTO t1 VALUES(3, 4); | |
30 } | |
31 | |
32 do_test 1.1.1 { | |
33 execsql { BEGIN; SELECT * FROM t1; } | |
34 list [catch { sqlite3_snapshot_get db main } msg] $msg | |
35 } {1 SQLITE_ERROR} | |
36 do_execsql_test 1.1.2 COMMIT | |
37 | |
38 do_test 1.2.1 { | |
39 execsql { | |
40 PRAGMA journal_mode = WAL; | |
41 BEGIN; | |
42 INSERT INTO t1 VALUES(5, 6); | |
43 INSERT INTO t1 VALUES(7, 8); | |
44 } | |
45 list [catch { sqlite3_snapshot_get db main } msg] $msg | |
46 } {1 SQLITE_ERROR} | |
47 do_execsql_test 1.3.2 COMMIT | |
48 | |
49 #------------------------------------------------------------------------- | |
50 # Check that a simple case works. Reuse the database created by the | |
51 # block of tests above. | |
52 # | |
53 do_execsql_test 2.1.0 { | |
54 BEGIN; | |
55 SELECT * FROM t1; | |
56 } {1 2 3 4 5 6 7 8} | |
57 | |
58 breakpoint | |
59 do_test 2.1.1 { | |
60 set snapshot [sqlite3_snapshot_get db main] | |
61 execsql { | |
62 COMMIT; | |
63 INSERT INTO t1 VALUES(9, 10); | |
64 SELECT * FROM t1; | |
65 } | |
66 } {1 2 3 4 5 6 7 8 9 10} | |
67 | |
68 do_test 2.1.2 { | |
69 execsql BEGIN | |
70 sqlite3_snapshot_open db main $snapshot | |
71 execsql { | |
72 SELECT * FROM t1; | |
73 } | |
74 } {1 2 3 4 5 6 7 8} | |
75 | |
76 do_test 2.1.3 { | |
77 sqlite3_snapshot_free $snapshot | |
78 execsql COMMIT | |
79 } {} | |
80 | |
81 do_test 2.2.0 { | |
82 sqlite3 db2 test.db | |
83 execsql { | |
84 BEGIN; | |
85 SELECT * FROM t1; | |
86 } db2 | |
87 } {1 2 3 4 5 6 7 8 9 10} | |
88 | |
89 do_test 2.2.1 { | |
90 set snapshot [sqlite3_snapshot_get db2 main] | |
91 execsql { | |
92 INSERT INTO t1 VALUES(11, 12); | |
93 SELECT * FROM t1; | |
94 } | |
95 } {1 2 3 4 5 6 7 8 9 10 11 12} | |
96 | |
97 do_test 2.2.2 { | |
98 execsql BEGIN | |
99 sqlite3_snapshot_open db main $snapshot | |
100 execsql { | |
101 SELECT * FROM t1; | |
102 } | |
103 } {1 2 3 4 5 6 7 8 9 10} | |
104 | |
105 do_test 2.2.3 { | |
106 sqlite3_snapshot_free $snapshot | |
107 execsql COMMIT | |
108 execsql COMMIT db2 | |
109 db2 close | |
110 } {} | |
111 | |
112 do_test 2.3.1 { | |
113 execsql { DELETE FROM t1 WHERE a>6 } | |
114 set snapshot [sqlite3_snapshot_get db main] | |
115 execsql { | |
116 INSERT INTO t1 VALUES('a', 'b'); | |
117 INSERT INTO t1 VALUES('c', 'd'); | |
118 SELECT * FROM t1; | |
119 } | |
120 } {1 2 3 4 5 6 a b c d} | |
121 do_test 2.3.2 { | |
122 execsql BEGIN | |
123 sqlite3_snapshot_open db main $snapshot | |
124 execsql { SELECT * FROM t1 } | |
125 } {1 2 3 4 5 6} | |
126 | |
127 do_test 2.3.3 { | |
128 catchsql { | |
129 INSERT INTO t1 VALUES('x','y') | |
130 } | |
131 } {1 {database is locked}} | |
132 do_test 2.3.4 { | |
133 execsql COMMIT | |
134 sqlite3_snapshot_free $snapshot | |
135 } {} | |
136 | |
137 #------------------------------------------------------------------------- | |
138 # Check some errors in sqlite3_snapshot_open(). It is an error if: | |
139 # | |
140 # 1) the db is in auto-commit mode, | |
141 # 2) the db has an open (read or write) transaction, | |
142 # 3) the db is not a wal database, | |
143 # | |
144 # Reuse the database created by earlier tests. | |
145 # | |
146 do_execsql_test 3.0.0 { | |
147 CREATE TABLE t2(x, y); | |
148 INSERT INTO t2 VALUES('a', 'b'); | |
149 INSERT INTO t2 VALUES('c', 'd'); | |
150 BEGIN; | |
151 SELECT * FROM t2; | |
152 } {a b c d} | |
153 do_test 3.0.1 { | |
154 set snapshot [sqlite3_snapshot_get db main] | |
155 execsql { COMMIT } | |
156 execsql { INSERT INTO t2 VALUES('e', 'f'); } | |
157 } {} | |
158 | |
159 do_test 3.1 { | |
160 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg | |
161 } {1 SQLITE_ERROR} | |
162 | |
163 do_test 3.2.1 { | |
164 execsql { | |
165 BEGIN; | |
166 SELECT * FROM t2; | |
167 } | |
168 } {a b c d e f} | |
169 do_test 3.2.2 { | |
170 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg | |
171 } {1 SQLITE_ERROR} | |
172 | |
173 do_test 3.2.3 { | |
174 execsql { | |
175 COMMIT; | |
176 BEGIN; | |
177 INSERT INTO t2 VALUES('g', 'h'); | |
178 } | |
179 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg | |
180 } {1 SQLITE_ERROR} | |
181 do_execsql_test 3.2.4 COMMIT | |
182 | |
183 do_test 3.3.1 { | |
184 execsql { PRAGMA journal_mode = DELETE } | |
185 execsql { BEGIN } | |
186 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg | |
187 } {1 SQLITE_ERROR} | |
188 | |
189 do_test 3.3.2 { | |
190 sqlite3_snapshot_free $snapshot | |
191 execsql COMMIT | |
192 } {} | |
193 | |
194 #------------------------------------------------------------------------- | |
195 # Check that SQLITE_BUSY_SNAPSHOT is returned if the specified snapshot | |
196 # no longer exists because the wal file has been checkpointed. | |
197 # | |
198 # 1. Reading a snapshot from the middle of a wal file is not possible | |
199 # after the wal file has been checkpointed. | |
200 # | |
201 # 2. That a snapshot from the end of a wal file can not be read once | |
202 # the wal file has been wrapped. | |
203 # | |
204 do_execsql_test 4.1.0 { | |
205 PRAGMA journal_mode = wal; | |
206 CREATE TABLE t3(i, j); | |
207 INSERT INTO t3 VALUES('o', 't'); | |
208 INSERT INTO t3 VALUES('t', 'f'); | |
209 BEGIN; | |
210 SELECT * FROM t3; | |
211 } {wal o t t f} | |
212 | |
213 do_test 4.1.1 { | |
214 set snapshot [sqlite3_snapshot_get db main] | |
215 execsql COMMIT | |
216 } {} | |
217 do_test 4.1.2 { | |
218 execsql { | |
219 INSERT INTO t3 VALUES('f', 's'); | |
220 BEGIN; | |
221 } | |
222 sqlite3_snapshot_open db main $snapshot | |
223 execsql { SELECT * FROM t3 } | |
224 } {o t t f} | |
225 | |
226 do_test 4.1.3 { | |
227 execsql { | |
228 COMMIT; | |
229 PRAGMA wal_checkpoint; | |
230 BEGIN; | |
231 } | |
232 list [catch {sqlite3_snapshot_open db main $snapshot} msg] $msg | |
233 } {1 SQLITE_BUSY_SNAPSHOT} | |
234 do_test 4.1.4 { | |
235 sqlite3_snapshot_free $snapshot | |
236 execsql COMMIT | |
237 } {} | |
238 | |
239 do_test 4.2.1 { | |
240 execsql { | |
241 INSERT INTO t3 VALUES('s', 'e'); | |
242 INSERT INTO t3 VALUES('n', 't'); | |
243 BEGIN; | |
244 SELECT * FROM t3; | |
245 } | |
246 } {o t t f f s s e n t} | |
247 do_test 4.2.2 { | |
248 set snapshot [sqlite3_snapshot_get db main] | |
249 execsql { | |
250 COMMIT; | |
251 PRAGMA wal_checkpoint; | |
252 BEGIN; | |
253 } | |
254 sqlite3_snapshot_open db main $snapshot | |
255 execsql { SELECT * FROM t3 } | |
256 } {o t t f f s s e n t} | |
257 do_test 4.2.3 { | |
258 execsql { | |
259 COMMIT; | |
260 INSERT INTO t3 VALUES('e', 't'); | |
261 BEGIN; | |
262 } | |
263 list [catch {sqlite3_snapshot_open db main $snapshot} msg] $msg | |
264 } {1 SQLITE_BUSY_SNAPSHOT} | |
265 do_test 4.2.4 { | |
266 sqlite3_snapshot_free $snapshot | |
267 } {} | |
268 | |
269 #------------------------------------------------------------------------- | |
270 # Check that SQLITE_BUSY is returned if a checkpoint is running when | |
271 # sqlite3_snapshot_open() is called. | |
272 # | |
273 reset_db | |
274 db close | |
275 testvfs tvfs | |
276 sqlite3 db test.db -vfs tvfs | |
277 | |
278 do_execsql_test 5.1 { | |
279 PRAGMA journal_mode = wal; | |
280 CREATE TABLE x1(x, xx, xxx); | |
281 INSERT INTO x1 VALUES('z', 'zz', 'zzz'); | |
282 BEGIN; | |
283 SELECT * FROM x1; | |
284 } {wal z zz zzz} | |
285 | |
286 do_test 5.2 { | |
287 set ::snapshot [sqlite3_snapshot_get db main] | |
288 sqlite3 db2 test.db -vfs tvfs | |
289 execsql { | |
290 INSERT INTO x1 VALUES('a', 'aa', 'aaa'); | |
291 COMMIT; | |
292 } | |
293 } {} | |
294 | |
295 set t53 0 | |
296 proc write_callback {args} { | |
297 do_test 5.3.[incr ::t53] { | |
298 execsql BEGIN | |
299 list [catch { sqlite3_snapshot_open db main $::snapshot } msg] $msg | |
300 } {1 SQLITE_BUSY} | |
301 catchsql COMMIT | |
302 } | |
303 | |
304 tvfs filter xWrite | |
305 tvfs script write_callback | |
306 db2 eval { PRAGMA wal_checkpoint } | |
307 db close | |
308 db2 close | |
309 tvfs delete | |
310 sqlite3_snapshot_free $snapshot | |
311 | |
312 #------------------------------------------------------------------------- | |
313 # Test that sqlite3_snapshot_get() may be called immediately after | |
314 # "BEGIN; PRAGMA user_version;". And that sqlite3_snapshot_open() may | |
315 # be called after opening the db handle and running the script | |
316 # "PRAGMA user_version; BEGIN". | |
317 reset_db | |
318 do_execsql_test 6.1 { | |
319 PRAGMA journal_mode = wal; | |
320 CREATE TABLE x1(x, xx, xxx); | |
321 INSERT INTO x1 VALUES('z', 'zz', 'zzz'); | |
322 BEGIN; | |
323 PRAGMA user_version; | |
324 } {wal 0} | |
325 do_test 6.2 { | |
326 set ::snapshot [sqlite3_snapshot_get db main] | |
327 execsql { | |
328 INSERT INTO x1 VALUES('a', 'aa', 'aaa'); | |
329 COMMIT; | |
330 } | |
331 } {} | |
332 do_test 6.3 { | |
333 sqlite3 db2 test.db | |
334 db2 eval "PRAGMA user_version ; BEGIN" | |
335 sqlite3_snapshot_open db2 main $::snapshot | |
336 db2 eval { SELECT * FROM x1 } | |
337 } {z zz zzz} | |
338 sqlite3_snapshot_free $snapshot | |
339 | |
340 finish_test | |
OLD | NEW |