blob: ba3a6667965eec12e19eb243c9c75b98fa74e6e9 [file] [log] [blame]
dan818b11a2015-12-07 14:33:07 +00001# 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#***********************************************************************
dan7d159792015-12-10 18:06:21 +000011# This file implements regression tests for SQLite library. The focus
12# of this file is the sqlite3_snapshot_xxx() APIs.
dan818b11a2015-12-07 14:33:07 +000013#
dan818b11a2015-12-07 14:33:07 +000014
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
drh68d28ea2015-12-11 03:20:39 +000017ifcapable !snapshot {finish_test; return}
dan818b11a2015-12-07 14:33:07 +000018set testprefix snapshot
19
20#-------------------------------------------------------------------------
21# Check some error conditions in snapshot_get(). It is an error if:
22#
dan7116dc62015-12-10 20:03:08 +000023# 1) snapshot_get() is called on a non-WAL database, or
24# 2) there is an open write transaction on the database.
dan818b11a2015-12-07 14:33:07 +000025#
26do_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
32do_test 1.1.1 {
33 execsql { BEGIN; SELECT * FROM t1; }
34 list [catch { sqlite3_snapshot_get db main } msg] $msg
35} {1 SQLITE_ERROR}
36do_execsql_test 1.1.2 COMMIT
37
38do_test 1.2.1 {
39 execsql {
dan7116dc62015-12-10 20:03:08 +000040 PRAGMA journal_mode = WAL;
dan818b11a2015-12-07 14:33:07 +000041 BEGIN;
dan7116dc62015-12-10 20:03:08 +000042 INSERT INTO t1 VALUES(5, 6);
dan818b11a2015-12-07 14:33:07 +000043 INSERT INTO t1 VALUES(7, 8);
44 }
45 list [catch { sqlite3_snapshot_get db main } msg] $msg
46} {1 SQLITE_ERROR}
47do_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#
dan65127cd2015-12-09 20:05:27 +000053do_execsql_test 2.1.0 {
dan818b11a2015-12-07 14:33:07 +000054 BEGIN;
55 SELECT * FROM t1;
56} {1 2 3 4 5 6 7 8}
57
dan65127cd2015-12-09 20:05:27 +000058do_test 2.1.1 {
dan818b11a2015-12-07 14:33:07 +000059 set snapshot [sqlite3_snapshot_get db main]
60 execsql {
61 COMMIT;
62 INSERT INTO t1 VALUES(9, 10);
63 SELECT * FROM t1;
64 }
65} {1 2 3 4 5 6 7 8 9 10}
66
dan65127cd2015-12-09 20:05:27 +000067do_test 2.1.2 {
dan818b11a2015-12-07 14:33:07 +000068 execsql BEGIN
dan3bf83cc2015-12-10 15:45:15 +000069 sqlite3_snapshot_open db main $snapshot
70 execsql {
71 SELECT * FROM t1;
72 }
73} {1 2 3 4 5 6 7 8}
dan818b11a2015-12-07 14:33:07 +000074
dan65127cd2015-12-09 20:05:27 +000075do_test 2.1.3 {
dan818b11a2015-12-07 14:33:07 +000076 sqlite3_snapshot_free $snapshot
77 execsql COMMIT
78} {}
79
dan65127cd2015-12-09 20:05:27 +000080do_test 2.2.0 {
81 sqlite3 db2 test.db
82 execsql {
83 BEGIN;
84 SELECT * FROM t1;
85 } db2
86} {1 2 3 4 5 6 7 8 9 10}
87
88do_test 2.2.1 {
89 set snapshot [sqlite3_snapshot_get db2 main]
90 execsql {
91 INSERT INTO t1 VALUES(11, 12);
92 SELECT * FROM t1;
93 }
94} {1 2 3 4 5 6 7 8 9 10 11 12}
95
dan3bf83cc2015-12-10 15:45:15 +000096do_test 2.2.2 {
dan65127cd2015-12-09 20:05:27 +000097 execsql BEGIN
98 sqlite3_snapshot_open db main $snapshot
99 execsql {
100 SELECT * FROM t1;
101 }
102} {1 2 3 4 5 6 7 8 9 10}
103
dan3bf83cc2015-12-10 15:45:15 +0000104do_test 2.2.3 {
dan65127cd2015-12-09 20:05:27 +0000105 sqlite3_snapshot_free $snapshot
106 execsql COMMIT
107 execsql COMMIT db2
108 db2 close
109} {}
110
dan7116dc62015-12-10 20:03:08 +0000111do_test 2.3.1 {
112 execsql { DELETE FROM t1 WHERE a>6 }
113 set snapshot [sqlite3_snapshot_get db main]
114 execsql {
115 INSERT INTO t1 VALUES('a', 'b');
116 INSERT INTO t1 VALUES('c', 'd');
117 SELECT * FROM t1;
118 }
119} {1 2 3 4 5 6 a b c d}
120do_test 2.3.2 {
121 execsql BEGIN
122 sqlite3_snapshot_open db main $snapshot
123 execsql { SELECT * FROM t1 }
124} {1 2 3 4 5 6}
125
126do_test 2.3.3 {
127 catchsql {
128 INSERT INTO t1 VALUES('x','y')
129 }
130} {1 {database is locked}}
131do_test 2.3.4 {
132 execsql COMMIT
133 sqlite3_snapshot_free $snapshot
134} {}
135
dan818b11a2015-12-07 14:33:07 +0000136#-------------------------------------------------------------------------
137# Check some errors in sqlite3_snapshot_open(). It is an error if:
138#
139# 1) the db is in auto-commit mode,
140# 2) the db has an open (read or write) transaction,
141# 3) the db is not a wal database,
142#
143# Reuse the database created by earlier tests.
144#
145do_execsql_test 3.0.0 {
146 CREATE TABLE t2(x, y);
147 INSERT INTO t2 VALUES('a', 'b');
148 INSERT INTO t2 VALUES('c', 'd');
149 BEGIN;
150 SELECT * FROM t2;
151} {a b c d}
152do_test 3.0.1 {
153 set snapshot [sqlite3_snapshot_get db main]
154 execsql { COMMIT }
155 execsql { INSERT INTO t2 VALUES('e', 'f'); }
156} {}
157
158do_test 3.1 {
159 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
160} {1 SQLITE_ERROR}
161
162do_test 3.2.1 {
163 execsql {
164 BEGIN;
165 SELECT * FROM t2;
166 }
167} {a b c d e f}
168do_test 3.2.2 {
169 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
170} {1 SQLITE_ERROR}
171
172do_test 3.2.3 {
173 execsql {
174 COMMIT;
175 BEGIN;
176 INSERT INTO t2 VALUES('g', 'h');
177 }
178 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
179} {1 SQLITE_ERROR}
180do_execsql_test 3.2.4 COMMIT
181
182do_test 3.3.1 {
183 execsql { PRAGMA journal_mode = DELETE }
184 execsql { BEGIN }
185 list [catch {sqlite3_snapshot_open db main $snapshot } msg] $msg
186} {1 SQLITE_ERROR}
187
188do_test 3.3.2 {
189 sqlite3_snapshot_free $snapshot
190 execsql COMMIT
191} {}
192
193#-------------------------------------------------------------------------
194# Check that SQLITE_BUSY_SNAPSHOT is returned if the specified snapshot
195# no longer exists because the wal file has been checkpointed.
196#
197# 1. Reading a snapshot from the middle of a wal file is not possible
198# after the wal file has been checkpointed.
199#
200# 2. That a snapshot from the end of a wal file can not be read once
201# the wal file has been wrapped.
202#
203do_execsql_test 4.1.0 {
204 PRAGMA journal_mode = wal;
205 CREATE TABLE t3(i, j);
206 INSERT INTO t3 VALUES('o', 't');
207 INSERT INTO t3 VALUES('t', 'f');
208 BEGIN;
209 SELECT * FROM t3;
210} {wal o t t f}
211
212do_test 4.1.1 {
213 set snapshot [sqlite3_snapshot_get db main]
214 execsql COMMIT
215} {}
216do_test 4.1.2 {
217 execsql {
218 INSERT INTO t3 VALUES('f', 's');
219 BEGIN;
220 }
221 sqlite3_snapshot_open db main $snapshot
222 execsql { SELECT * FROM t3 }
223} {o t t f}
224
225do_test 4.1.3 {
226 execsql {
227 COMMIT;
228 PRAGMA wal_checkpoint;
229 BEGIN;
230 }
231 list [catch {sqlite3_snapshot_open db main $snapshot} msg] $msg
232} {1 SQLITE_BUSY_SNAPSHOT}
233do_test 4.1.4 {
234 sqlite3_snapshot_free $snapshot
235 execsql COMMIT
236} {}
237
238do_test 4.2.1 {
239 execsql {
240 INSERT INTO t3 VALUES('s', 'e');
241 INSERT INTO t3 VALUES('n', 't');
242 BEGIN;
243 SELECT * FROM t3;
244 }
245} {o t t f f s s e n t}
246do_test 4.2.2 {
247 set snapshot [sqlite3_snapshot_get db main]
248 execsql {
249 COMMIT;
250 PRAGMA wal_checkpoint;
251 BEGIN;
252 }
253 sqlite3_snapshot_open db main $snapshot
254 execsql { SELECT * FROM t3 }
255} {o t t f f s s e n t}
256do_test 4.2.3 {
257 execsql {
258 COMMIT;
259 INSERT INTO t3 VALUES('e', 't');
260 BEGIN;
261 }
262 list [catch {sqlite3_snapshot_open db main $snapshot} msg] $msg
263} {1 SQLITE_BUSY_SNAPSHOT}
264do_test 4.2.4 {
265 sqlite3_snapshot_free $snapshot
266} {}
267
dana7aeb392015-12-10 19:11:34 +0000268#-------------------------------------------------------------------------
269# Check that SQLITE_BUSY is returned if a checkpoint is running when
270# sqlite3_snapshot_open() is called.
271#
272reset_db
273db close
274testvfs tvfs
275sqlite3 db test.db -vfs tvfs
276
277do_execsql_test 5.1 {
278 PRAGMA journal_mode = wal;
279 CREATE TABLE x1(x, xx, xxx);
280 INSERT INTO x1 VALUES('z', 'zz', 'zzz');
281 BEGIN;
282 SELECT * FROM x1;
283} {wal z zz zzz}
284
285do_test 5.2 {
286 set ::snapshot [sqlite3_snapshot_get db main]
287 sqlite3 db2 test.db -vfs tvfs
288 execsql {
289 INSERT INTO x1 VALUES('a', 'aa', 'aaa');
290 COMMIT;
291 }
292} {}
293
294set t53 0
295proc write_callback {args} {
dana7aeb392015-12-10 19:11:34 +0000296 do_test 5.3.[incr ::t53] {
297 execsql BEGIN
298 list [catch { sqlite3_snapshot_open db main $::snapshot } msg] $msg
299 } {1 SQLITE_BUSY}
300 catchsql COMMIT
301}
302
303tvfs filter xWrite
304tvfs script write_callback
305db2 eval { PRAGMA wal_checkpoint }
306db close
307db2 close
308tvfs delete
309sqlite3_snapshot_free $snapshot
310
dan745c14e2015-12-10 19:44:34 +0000311#-------------------------------------------------------------------------
312# Test that sqlite3_snapshot_get() may be called immediately after
313# "BEGIN; PRAGMA user_version;". And that sqlite3_snapshot_open() may
314# be called after opening the db handle and running the script
315# "PRAGMA user_version; BEGIN".
316reset_db
317do_execsql_test 6.1 {
318 PRAGMA journal_mode = wal;
319 CREATE TABLE x1(x, xx, xxx);
320 INSERT INTO x1 VALUES('z', 'zz', 'zzz');
321 BEGIN;
322 PRAGMA user_version;
323} {wal 0}
324do_test 6.2 {
325 set ::snapshot [sqlite3_snapshot_get db main]
326 execsql {
327 INSERT INTO x1 VALUES('a', 'aa', 'aaa');
328 COMMIT;
329 }
330} {}
331do_test 6.3 {
332 sqlite3 db2 test.db
333 db2 eval "PRAGMA user_version ; BEGIN"
334 sqlite3_snapshot_open db2 main $::snapshot
335 db2 eval { SELECT * FROM x1 }
336} {z zz zzz}
drhd892ac92016-02-27 14:00:07 +0000337do_test 6.4 {
338 db2 close
339 sqlite3 db2 test.db
340 db2 eval "PRAGMA application_id"
341 db2 eval "BEGIN"
342 sqlite3_snapshot_open db2 main $::snapshot
343 db2 eval { SELECT * FROM x1 }
344} {z zz zzz}
345
346# EVIDENCE-OF: R-55491-50411 A snapshot will fail to open if the
347# database connection D has not previously completed at least one read
348# operation against the database file.
349#
350do_test 6.5 {
351 db2 close
352 sqlite3 db2 test.db
353 db2 eval "BEGIN"
354 list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg
355} {1 SQLITE_ERROR}
356
dan745c14e2015-12-10 19:44:34 +0000357sqlite3_snapshot_free $snapshot
358
dan818b11a2015-12-07 14:33:07 +0000359finish_test