diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/test/shared_err.test')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/test/shared_err.test | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/test/shared_err.test b/libraries/sqlite/unix/sqlite-3.5.1/test/shared_err.test new file mode 100644 index 0000000..7c1794a --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/test/shared_err.test | |||
@@ -0,0 +1,463 @@ | |||
1 | # 2005 December 30 | ||
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 | # The focus of the tests in this file are IO errors that occur in a shared | ||
13 | # cache context. What happens to connection B if one connection A encounters | ||
14 | # an IO-error whilst reading or writing the file-system? | ||
15 | # | ||
16 | # $Id: shared_err.test,v 1.17 2007/09/03 16:12:10 drh Exp $ | ||
17 | |||
18 | proc skip {args} {} | ||
19 | |||
20 | |||
21 | set testdir [file dirname $argv0] | ||
22 | source $testdir/tester.tcl | ||
23 | source $testdir/malloc_common.tcl | ||
24 | db close | ||
25 | |||
26 | ifcapable !shared_cache||!subquery { | ||
27 | finish_test | ||
28 | return | ||
29 | } | ||
30 | |||
31 | set ::enable_shared_cache [sqlite3_enable_shared_cache 1] | ||
32 | |||
33 | do_ioerr_test shared_ioerr-1 -tclprep { | ||
34 | sqlite3 db2 test.db | ||
35 | execsql { | ||
36 | PRAGMA read_uncommitted = 1; | ||
37 | CREATE TABLE t1(a,b,c); | ||
38 | BEGIN; | ||
39 | SELECT * FROM sqlite_master; | ||
40 | } db2 | ||
41 | } -sqlbody { | ||
42 | SELECT * FROM sqlite_master; | ||
43 | INSERT INTO t1 VALUES(1,2,3); | ||
44 | BEGIN TRANSACTION; | ||
45 | INSERT INTO t1 VALUES(1,2,3); | ||
46 | INSERT INTO t1 VALUES(4,5,6); | ||
47 | ROLLBACK; | ||
48 | SELECT * FROM t1; | ||
49 | BEGIN TRANSACTION; | ||
50 | INSERT INTO t1 VALUES(1,2,3); | ||
51 | INSERT INTO t1 VALUES(4,5,6); | ||
52 | COMMIT; | ||
53 | SELECT * FROM t1; | ||
54 | DELETE FROM t1 WHERE a<100; | ||
55 | } -cleanup { | ||
56 | do_test shared_ioerr-1.$n.cleanup.1 { | ||
57 | set res [catchsql { | ||
58 | SELECT * FROM t1; | ||
59 | } db2] | ||
60 | set possible_results [list \ | ||
61 | "1 {disk I/O error}" \ | ||
62 | "0 {1 2 3}" \ | ||
63 | "0 {1 2 3 1 2 3 4 5 6}" \ | ||
64 | "0 {1 2 3 1 2 3 4 5 6 1 2 3 4 5 6}" \ | ||
65 | "0 {}" \ | ||
66 | ] | ||
67 | set rc [expr [lsearch -exact $possible_results $res] >= 0] | ||
68 | if {$rc != 1} { | ||
69 | puts "" | ||
70 | puts "Result: $res" | ||
71 | } | ||
72 | set rc | ||
73 | } {1} | ||
74 | db2 close | ||
75 | } | ||
76 | |||
77 | do_ioerr_test shared_ioerr-2 -tclprep { | ||
78 | sqlite3 db2 test.db | ||
79 | execsql { | ||
80 | PRAGMA read_uncommitted = 1; | ||
81 | BEGIN; | ||
82 | CREATE TABLE t1(a, b); | ||
83 | INSERT INTO t1(oid) VALUES(NULL); | ||
84 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
85 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
86 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
87 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
88 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
89 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
90 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
91 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
92 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
93 | INSERT INTO t1(oid) SELECT NULL FROM t1; | ||
94 | UPDATE t1 set a = oid, b = 'abcdefghijklmnopqrstuvwxyz0123456789'; | ||
95 | CREATE INDEX i1 ON t1(a); | ||
96 | COMMIT; | ||
97 | BEGIN; | ||
98 | SELECT * FROM sqlite_master; | ||
99 | } db2 | ||
100 | } -tclbody { | ||
101 | set ::residx 0 | ||
102 | execsql {DELETE FROM t1 WHERE 0 = (a % 2);} | ||
103 | incr ::residx | ||
104 | |||
105 | # When this transaction begins the table contains 512 entries. The | ||
106 | # two statements together add 512+146 more if it succeeds. | ||
107 | # (1024/7==146) | ||
108 | execsql {BEGIN;} | ||
109 | execsql {INSERT INTO t1 SELECT a+1, b FROM t1;} | ||
110 | execsql {INSERT INTO t1 SELECT 'string' || a, b FROM t1 WHERE 0 = (a%7);} | ||
111 | execsql {COMMIT;} | ||
112 | |||
113 | incr ::residx | ||
114 | } -cleanup { | ||
115 | do_test shared_ioerr-2.$n.cleanup.1 { | ||
116 | set res [catchsql { | ||
117 | SELECT max(a), min(a), count(*) FROM (SELECT a FROM t1 order by a); | ||
118 | } db2] | ||
119 | set possible_results [list \ | ||
120 | {0 {1024 1 1024}} \ | ||
121 | {0 {1023 1 512}} \ | ||
122 | {0 {string994 1 1170}} \ | ||
123 | ] | ||
124 | set idx [lsearch -exact $possible_results $res] | ||
125 | set success [expr {$idx==$::residx || $res=="1 {disk I/O error}"}] | ||
126 | if {!$success} { | ||
127 | puts "" | ||
128 | puts "Result: \"$res\" ($::residx)" | ||
129 | } | ||
130 | set success | ||
131 | } {1} | ||
132 | db2 close | ||
133 | } | ||
134 | |||
135 | # This test is designed to provoke an IO error when a cursor position is | ||
136 | # "saved" (because another cursor is going to modify the underlying table). | ||
137 | # | ||
138 | do_ioerr_test shared_ioerr-3 -tclprep { | ||
139 | sqlite3 db2 test.db | ||
140 | execsql { | ||
141 | PRAGMA read_uncommitted = 1; | ||
142 | PRAGMA cache_size = 10; | ||
143 | BEGIN; | ||
144 | CREATE TABLE t1(a, b, UNIQUE(a, b)); | ||
145 | } db2 | ||
146 | for {set i 0} {$i < 200} {incr i} { | ||
147 | set a [string range [string repeat "[format %03d $i]." 5] 0 end-1] | ||
148 | |||
149 | set b [string repeat $i 2000] | ||
150 | execsql {INSERT INTO t1 VALUES($a, $b)} db2 | ||
151 | } | ||
152 | execsql {COMMIT} db2 | ||
153 | set ::DB2 [sqlite3_connection_pointer db2] | ||
154 | set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] | ||
155 | sqlite3_step $::STMT ;# Cursor points at 000.000.000.000 | ||
156 | sqlite3_step $::STMT ;# Cursor points at 001.001.001.001 | ||
157 | |||
158 | } -tclbody { | ||
159 | execsql { | ||
160 | BEGIN; | ||
161 | INSERT INTO t1 VALUES('201.201.201.201.201', NULL); | ||
162 | UPDATE t1 SET a = '202.202.202.202.202' WHERE a LIKE '201%'; | ||
163 | COMMIT; | ||
164 | } | ||
165 | } -cleanup { | ||
166 | set ::steprc [sqlite3_step $::STMT] | ||
167 | set ::column [sqlite3_column_text $::STMT 0] | ||
168 | set ::finalrc [sqlite3_finalize $::STMT] | ||
169 | |||
170 | # There are three possible outcomes here (assuming persistent IO errors): | ||
171 | # | ||
172 | # 1. If the [sqlite3_step] did not require any IO (required pages in | ||
173 | # the cache), then the next row ("002...") may be retrieved | ||
174 | # successfully. | ||
175 | # | ||
176 | # 2. If the [sqlite3_step] does require IO, then [sqlite3_step] returns | ||
177 | # SQLITE_ERROR and [sqlite3_finalize] returns IOERR. | ||
178 | # | ||
179 | # 3. If, after the initial IO error, SQLite tried to rollback the | ||
180 | # active transaction and a second IO error was encountered, then | ||
181 | # statement $::STMT will have been aborted. This means [sqlite3_stmt] | ||
182 | # returns SQLITE_ABORT, and the statement cursor does not move. i.e. | ||
183 | # [sqlite3_column] still returns the current row ("001...") and | ||
184 | # [sqlite3_finalize] returns SQLITE_OK. | ||
185 | # | ||
186 | |||
187 | do_test shared_ioerr-3.$n.cleanup.1 { | ||
188 | expr { | ||
189 | $::steprc eq "SQLITE_ROW" || | ||
190 | $::steprc eq "SQLITE_ERROR" || | ||
191 | $::steprc eq "SQLITE_ABORT" | ||
192 | } | ||
193 | } {1} | ||
194 | do_test shared_ioerr-3.$n.cleanup.2 { | ||
195 | expr { | ||
196 | ($::steprc eq "SQLITE_ROW" && $::column eq "002.002.002.002.002") || | ||
197 | ($::steprc eq "SQLITE_ERROR" && $::column eq "") || | ||
198 | ($::steprc eq "SQLITE_ABORT" && $::column eq "001.001.001.001.001") | ||
199 | } | ||
200 | } {1} | ||
201 | do_test shared_ioerr-3.$n.cleanup.3 { | ||
202 | expr { | ||
203 | ($::steprc eq "SQLITE_ROW" && $::finalrc eq "SQLITE_OK") || | ||
204 | ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_IOERR") || | ||
205 | ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_ABORT") | ||
206 | } | ||
207 | } {1} | ||
208 | |||
209 | # db2 eval {select * from sqlite_master} | ||
210 | db2 close | ||
211 | } | ||
212 | |||
213 | # This is a repeat of the previous test except that this time we | ||
214 | # are doing a reverse-order scan of the table when the cursor is | ||
215 | # "saved". | ||
216 | # | ||
217 | do_ioerr_test shared_ioerr-3rev -tclprep { | ||
218 | sqlite3 db2 test.db | ||
219 | execsql { | ||
220 | PRAGMA read_uncommitted = 1; | ||
221 | PRAGMA cache_size = 10; | ||
222 | BEGIN; | ||
223 | CREATE TABLE t1(a, b, UNIQUE(a, b)); | ||
224 | } db2 | ||
225 | for {set i 0} {$i < 200} {incr i} { | ||
226 | set a [string range [string repeat "[format %03d $i]." 5] 0 end-1] | ||
227 | |||
228 | set b [string repeat $i 2000] | ||
229 | execsql {INSERT INTO t1 VALUES($a, $b)} db2 | ||
230 | } | ||
231 | execsql {COMMIT} db2 | ||
232 | set ::DB2 [sqlite3_connection_pointer db2] | ||
233 | set ::STMT [sqlite3_prepare $::DB2 \ | ||
234 | "SELECT a FROM t1 ORDER BY a DESC" -1 DUMMY] | ||
235 | sqlite3_step $::STMT ;# Cursor points at 199.199.199.199.199 | ||
236 | sqlite3_step $::STMT ;# Cursor points at 198.198.198.198.198 | ||
237 | |||
238 | } -tclbody { | ||
239 | execsql { | ||
240 | BEGIN; | ||
241 | INSERT INTO t1 VALUES('201.201.201.201.201', NULL); | ||
242 | UPDATE t1 SET a = '202.202.202.202.202' WHERE a LIKE '201%'; | ||
243 | COMMIT; | ||
244 | } | ||
245 | } -cleanup { | ||
246 | set ::steprc [sqlite3_step $::STMT] | ||
247 | set ::column [sqlite3_column_text $::STMT 0] | ||
248 | set ::finalrc [sqlite3_finalize $::STMT] | ||
249 | |||
250 | # There are three possible outcomes here (assuming persistent IO errors): | ||
251 | # | ||
252 | # 1. If the [sqlite3_step] did not require any IO (required pages in | ||
253 | # the cache), then the next row ("002...") may be retrieved | ||
254 | # successfully. | ||
255 | # | ||
256 | # 2. If the [sqlite3_step] does require IO, then [sqlite3_step] returns | ||
257 | # SQLITE_ERROR and [sqlite3_finalize] returns IOERR. | ||
258 | # | ||
259 | # 3. If, after the initial IO error, SQLite tried to rollback the | ||
260 | # active transaction and a second IO error was encountered, then | ||
261 | # statement $::STMT will have been aborted. This means [sqlite3_stmt] | ||
262 | # returns SQLITE_ABORT, and the statement cursor does not move. i.e. | ||
263 | # [sqlite3_column] still returns the current row ("001...") and | ||
264 | # [sqlite3_finalize] returns SQLITE_OK. | ||
265 | # | ||
266 | |||
267 | do_test shared_ioerr-3rev.$n.cleanup.1 { | ||
268 | expr { | ||
269 | $::steprc eq "SQLITE_ROW" || | ||
270 | $::steprc eq "SQLITE_ERROR" || | ||
271 | $::steprc eq "SQLITE_ABORT" | ||
272 | } | ||
273 | } {1} | ||
274 | do_test shared_ioerr-3rev.$n.cleanup.2 { | ||
275 | expr { | ||
276 | ($::steprc eq "SQLITE_ROW" && $::column eq "197.197.197.197.197") || | ||
277 | ($::steprc eq "SQLITE_ERROR" && $::column eq "") || | ||
278 | ($::steprc eq "SQLITE_ABORT" && $::column eq "198.198.198.198.198") | ||
279 | } | ||
280 | } {1} | ||
281 | do_test shared_ioerr-3rev.$n.cleanup.3 { | ||
282 | expr { | ||
283 | ($::steprc eq "SQLITE_ROW" && $::finalrc eq "SQLITE_OK") || | ||
284 | ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_IOERR") || | ||
285 | ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_ABORT") | ||
286 | } | ||
287 | } {1} | ||
288 | |||
289 | # db2 eval {select * from sqlite_master} | ||
290 | db2 close | ||
291 | } | ||
292 | |||
293 | # Only run these tests if memory debugging is turned on. | ||
294 | # | ||
295 | ifcapable !memdebug { | ||
296 | puts "Skipping tests shared_err-4 through -9:\ | ||
297 | not compiled with -DSQLITE_MEMDEBUG..." | ||
298 | db close | ||
299 | sqlite3_enable_shared_cache $::enable_shared_cache | ||
300 | finish_test | ||
301 | return | ||
302 | } | ||
303 | |||
304 | # Provoke a malloc() failure when a cursor position is being saved. This | ||
305 | # only happens with index cursors (because they malloc() space to save the | ||
306 | # current key value). It does not happen with tables, because an integer | ||
307 | # key does not require a malloc() to store. | ||
308 | # | ||
309 | # The library should return an SQLITE_NOMEM to the caller. The query that | ||
310 | # owns the cursor (the one for which the position is not saved) should | ||
311 | # continue unaffected. | ||
312 | # | ||
313 | do_malloc_test shared_err-4 -tclprep { | ||
314 | sqlite3 db2 test.db | ||
315 | execsql { | ||
316 | PRAGMA read_uncommitted = 1; | ||
317 | BEGIN; | ||
318 | CREATE TABLE t1(a, b, UNIQUE(a, b)); | ||
319 | } db2 | ||
320 | for {set i 0} {$i < 5} {incr i} { | ||
321 | set a [string repeat $i 10] | ||
322 | set b [string repeat $i 2000] | ||
323 | execsql {INSERT INTO t1 VALUES($a, $b)} db2 | ||
324 | } | ||
325 | execsql {COMMIT} db2 | ||
326 | set ::DB2 [sqlite3_connection_pointer db2] | ||
327 | set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] | ||
328 | sqlite3_step $::STMT ;# Cursor points at 0000000000 | ||
329 | sqlite3_step $::STMT ;# Cursor points at 1111111111 | ||
330 | } -tclbody { | ||
331 | execsql { | ||
332 | INSERT INTO t1 VALUES(6, NULL); | ||
333 | } | ||
334 | } -cleanup { | ||
335 | do_test shared_malloc-4.$::n.cleanup.1 { | ||
336 | set ::rc [sqlite3_step $::STMT] | ||
337 | expr {$::rc=="SQLITE_ROW" || $::rc=="SQLITE_ERROR"} | ||
338 | } {1} | ||
339 | if {$::rc=="SQLITE_ROW"} { | ||
340 | do_test shared_malloc-4.$::n.cleanup.2 { | ||
341 | sqlite3_column_text $::STMT 0 | ||
342 | } {2222222222} | ||
343 | } | ||
344 | do_test shared_malloc-4.$::n.cleanup.3 { | ||
345 | set rc [sqlite3_finalize $::STMT] | ||
346 | expr {$rc=="SQLITE_OK" || $rc=="SQLITE_ABORT" || $rc=="SQLITE_NOMEM"} | ||
347 | } {1} | ||
348 | # db2 eval {select * from sqlite_master} | ||
349 | db2 close | ||
350 | } | ||
351 | |||
352 | do_malloc_test shared_err-5 -tclbody { | ||
353 | db close | ||
354 | sqlite3 dbX test.db | ||
355 | sqlite3 dbY test.db | ||
356 | dbX close | ||
357 | dbY close | ||
358 | } -cleanup { | ||
359 | catch {dbX close} | ||
360 | catch {dbY close} | ||
361 | } | ||
362 | |||
363 | do_malloc_test shared_err-6 -tclbody { | ||
364 | catch {db close} | ||
365 | sqlite3_thread_cleanup | ||
366 | sqlite3_enable_shared_cache 0 | ||
367 | } -cleanup { | ||
368 | sqlite3_enable_shared_cache 1 | ||
369 | } | ||
370 | |||
371 | # As of 3.5.0, sqlite3_enable_shared_cache can be called at | ||
372 | # any time and from any thread | ||
373 | #do_test shared_err-misuse-7.1 { | ||
374 | # sqlite3 db test.db | ||
375 | # catch { | ||
376 | # sqlite3_enable_shared_cache 0 | ||
377 | # } msg | ||
378 | # set msg | ||
379 | #} {library routine called out of sequence} | ||
380 | |||
381 | # Again provoke a malloc() failure when a cursor position is being saved, | ||
382 | # this time during a ROLLBACK operation by some other handle. | ||
383 | # | ||
384 | # The library should return an SQLITE_NOMEM to the caller. The query that | ||
385 | # owns the cursor (the one for which the position is not saved) should | ||
386 | # be aborted. | ||
387 | # | ||
388 | set ::aborted 0 | ||
389 | do_malloc_test shared_err-8 -tclprep { | ||
390 | sqlite3 db2 test.db | ||
391 | execsql { | ||
392 | PRAGMA read_uncommitted = 1; | ||
393 | BEGIN; | ||
394 | CREATE TABLE t1(a, b, UNIQUE(a, b)); | ||
395 | } db2 | ||
396 | for {set i 0} {$i < 2} {incr i} { | ||
397 | set a [string repeat $i 10] | ||
398 | set b [string repeat $i 2000] | ||
399 | execsql {INSERT INTO t1 VALUES($a, $b)} db2 | ||
400 | } | ||
401 | execsql {COMMIT} db2 | ||
402 | set ::DB2 [sqlite3_connection_pointer db2] | ||
403 | set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY] | ||
404 | sqlite3_step $::STMT ;# Cursor points at 0000000000 | ||
405 | sqlite3_step $::STMT ;# Cursor points at 1111111111 | ||
406 | } -tclbody { | ||
407 | execsql { | ||
408 | BEGIN; | ||
409 | INSERT INTO t1 VALUES(6, NULL); | ||
410 | ROLLBACK; | ||
411 | } | ||
412 | } -cleanup { | ||
413 | do_test shared_malloc-8.$::n.cleanup.1 { | ||
414 | lrange [execsql { | ||
415 | SELECT a FROM t1; | ||
416 | } db2] 0 1 | ||
417 | } {0000000000 1111111111} | ||
418 | do_test shared_malloc-8.$::n.cleanup.2 { | ||
419 | set rc1 [sqlite3_step $::STMT] | ||
420 | set rc2 [sqlite3_finalize $::STMT] | ||
421 | if {$rc2=="SQLITE_ABORT"} { | ||
422 | incr ::aborted | ||
423 | } | ||
424 | expr { | ||
425 | ($rc1=="SQLITE_DONE" && $rc2=="SQLITE_OK") || | ||
426 | ($rc1=="SQLITE_ERROR" && $rc2=="SQLITE_ABORT") || | ||
427 | ($rc1=="SQLITE_ERROR" && $rc2=="SQLITE_NOMEM") | ||
428 | } | ||
429 | } {1} | ||
430 | db2 close | ||
431 | } | ||
432 | do_test shared_malloc-8.X { | ||
433 | # Test that one or more queries were aborted due to the malloc() failure. | ||
434 | expr $::aborted>=1 | ||
435 | } {1} | ||
436 | |||
437 | # This test is designed to catch a specific bug that was present during | ||
438 | # development of 3.5.0. If a malloc() failed while setting the page-size, | ||
439 | # a buffer (Pager.pTmpSpace) was being freed. This could cause a seg-fault | ||
440 | # later if another connection tried to use the pager. | ||
441 | # | ||
442 | # This test will crash 3.4.2. | ||
443 | # | ||
444 | do_malloc_test shared_err-9 -tclprep { | ||
445 | sqlite3 db2 test.db | ||
446 | } -sqlbody { | ||
447 | PRAGMA page_size = 4096; | ||
448 | PRAGMA page_size = 1024; | ||
449 | } -cleanup { | ||
450 | db2 eval { | ||
451 | CREATE TABLE abc(a, b, c); | ||
452 | BEGIN; | ||
453 | INSERT INTO abc VALUES(1, 2, 3); | ||
454 | ROLLBACK; | ||
455 | } | ||
456 | db2 close | ||
457 | } | ||
458 | |||
459 | |||
460 | catch {db close} | ||
461 | catch {db2 close} | ||
462 | sqlite3_enable_shared_cache $::enable_shared_cache | ||
463 | finish_test | ||