OLD | NEW |
| (Empty) |
1 # 2001 September 15 | |
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 | |
12 # focus of this script is database locks. | |
13 # | |
14 # $Id: lock.test,v 1.40 2009/06/16 17:49:36 drh Exp $ | |
15 | |
16 | |
17 set testdir [file dirname $argv0] | |
18 source $testdir/tester.tcl | |
19 | |
20 # Create an alternative connection to the database | |
21 # | |
22 do_test lock-1.0 { | |
23 # Give a complex pathname to stress the path simplification logic in | |
24 # the vxworks driver and in test_async. | |
25 file mkdir tempdir/t1/t2 | |
26 sqlite3 db2 ./tempdir/../tempdir/t1/.//t2/../../..//test.db | |
27 set dummy {} | |
28 } {} | |
29 do_test lock-1.1 { | |
30 execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} | |
31 } {} | |
32 do_test lock-1.2 { | |
33 execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2 | |
34 } {} | |
35 do_test lock-1.3 { | |
36 execsql {CREATE TABLE t1(a int, b int)} | |
37 execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} | |
38 } {t1} | |
39 do_test lock-1.5 { | |
40 catchsql { | |
41 SELECT name FROM sqlite_master WHERE type='table' ORDER BY name | |
42 } db2 | |
43 } {0 t1} | |
44 | |
45 do_test lock-1.6 { | |
46 execsql {INSERT INTO t1 VALUES(1,2)} | |
47 execsql {SELECT * FROM t1} | |
48 } {1 2} | |
49 # Update: The schema is now brought up to date by test lock-1.5. | |
50 # do_test lock-1.7.1 { | |
51 # catchsql {SELECT * FROM t1} db2 | |
52 # } {1 {no such table: t1}} | |
53 do_test lock-1.7.2 { | |
54 catchsql {SELECT * FROM t1} db2 | |
55 } {0 {1 2}} | |
56 do_test lock-1.8 { | |
57 execsql {UPDATE t1 SET a=b, b=a} db2 | |
58 execsql {SELECT * FROM t1} db2 | |
59 } {2 1} | |
60 do_test lock-1.9 { | |
61 execsql {SELECT * FROM t1} | |
62 } {2 1} | |
63 do_test lock-1.10 { | |
64 execsql {BEGIN TRANSACTION} | |
65 execsql {UPDATE t1 SET a = 0 WHERE 0} | |
66 execsql {SELECT * FROM t1} | |
67 } {2 1} | |
68 do_test lock-1.11 { | |
69 catchsql {SELECT * FROM t1} db2 | |
70 } {0 {2 1}} | |
71 do_test lock-1.12 { | |
72 execsql {ROLLBACK} | |
73 catchsql {SELECT * FROM t1} | |
74 } {0 {2 1}} | |
75 | |
76 do_test lock-1.13 { | |
77 execsql {CREATE TABLE t2(x int, y int)} | |
78 execsql {INSERT INTO t2 VALUES(8,9)} | |
79 execsql {SELECT * FROM t2} | |
80 } {8 9} | |
81 do_test lock-1.14.1 { | |
82 catchsql {SELECT * FROM t2} db2 | |
83 } {0 {8 9}} | |
84 do_test lock-1.14.2 { | |
85 catchsql {SELECT * FROM t1} db2 | |
86 } {0 {2 1}} | |
87 do_test lock-1.15 { | |
88 catchsql {SELECT * FROM t2} db2 | |
89 } {0 {8 9}} | |
90 | |
91 do_test lock-1.16 { | |
92 db eval {SELECT * FROM t1} qv { | |
93 set x [db eval {SELECT * FROM t1}] | |
94 } | |
95 set x | |
96 } {2 1} | |
97 do_test lock-1.17 { | |
98 db eval {SELECT * FROM t1} qv { | |
99 set x [db eval {SELECT * FROM t2}] | |
100 } | |
101 set x | |
102 } {8 9} | |
103 | |
104 # You cannot UPDATE a table from within the callback of a SELECT | |
105 # on that same table because the SELECT has the table locked. | |
106 # | |
107 # 2006-08-16: Reads no longer block writes within the same | |
108 # database connection. | |
109 # | |
110 #do_test lock-1.18 { | |
111 # db eval {SELECT * FROM t1} qv { | |
112 # set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg] | |
113 # lappend r $msg | |
114 # } | |
115 # set r | |
116 #} {1 {database table is locked}} | |
117 | |
118 # But you can UPDATE a different table from the one that is used in | |
119 # the SELECT. | |
120 # | |
121 do_test lock-1.19 { | |
122 db eval {SELECT * FROM t1} qv { | |
123 set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg] | |
124 lappend r $msg | |
125 } | |
126 set r | |
127 } {0 {}} | |
128 do_test lock-1.20 { | |
129 execsql {SELECT * FROM t2} | |
130 } {9 8} | |
131 | |
132 # It is possible to do a SELECT of the same table within the | |
133 # callback of another SELECT on that same table because two | |
134 # or more read-only cursors can be open at once. | |
135 # | |
136 do_test lock-1.21 { | |
137 db eval {SELECT * FROM t1} qv { | |
138 set r [catch {db eval {SELECT a FROM t1}} msg] | |
139 lappend r $msg | |
140 } | |
141 set r | |
142 } {0 2} | |
143 | |
144 # Under UNIX you can do two SELECTs at once with different database | |
145 # connections, because UNIX supports reader/writer locks. Under windows, | |
146 # this is not possible. | |
147 # | |
148 if {$::tcl_platform(platform)=="unix"} { | |
149 do_test lock-1.22 { | |
150 db eval {SELECT * FROM t1} qv { | |
151 set r [catch {db2 eval {SELECT a FROM t1}} msg] | |
152 lappend r $msg | |
153 } | |
154 set r | |
155 } {0 2} | |
156 } | |
157 integrity_check lock-1.23 | |
158 | |
159 # If one thread has a transaction another thread cannot start | |
160 # a transaction. -> Not true in version 3.0. But if one thread | |
161 # as a RESERVED lock another thread cannot acquire one. | |
162 # | |
163 do_test lock-2.1 { | |
164 execsql {BEGIN TRANSACTION} | |
165 execsql {UPDATE t1 SET a = 0 WHERE 0} | |
166 execsql {BEGIN TRANSACTION} db2 | |
167 set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg] | |
168 execsql {ROLLBACK} db2 | |
169 lappend r $msg | |
170 } {1 {database is locked}} | |
171 | |
172 # A thread can read when another has a RESERVED lock. | |
173 # | |
174 do_test lock-2.2 { | |
175 catchsql {SELECT * FROM t2} db2 | |
176 } {0 {9 8}} | |
177 | |
178 # If the other thread (the one that does not hold the transaction with | |
179 # a RESERVED lock) tries to get a RESERVED lock, we do get a busy callback | |
180 # as long as we were not orginally holding a READ lock. | |
181 # | |
182 do_test lock-2.3.1 { | |
183 proc callback {count} { | |
184 set ::callback_value $count | |
185 break | |
186 } | |
187 set ::callback_value {} | |
188 db2 busy callback | |
189 # db2 does not hold a lock so we should get a busy callback here | |
190 set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg] | |
191 lappend r $msg | |
192 lappend r $::callback_value | |
193 } {1 {database is locked} 0} | |
194 do_test lock-2.3.2 { | |
195 set ::callback_value {} | |
196 execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2 | |
197 # This time db2 does hold a read lock. No busy callback this time. | |
198 set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg] | |
199 lappend r $msg | |
200 lappend r $::callback_value | |
201 } {1 {database is locked} {}} | |
202 catch {execsql {ROLLBACK} db2} | |
203 do_test lock-2.4.1 { | |
204 proc callback {count} { | |
205 lappend ::callback_value $count | |
206 if {$count>4} break | |
207 } | |
208 set ::callback_value {} | |
209 db2 busy callback | |
210 # We get a busy callback because db2 is not holding a lock | |
211 set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg] | |
212 lappend r $msg | |
213 lappend r $::callback_value | |
214 } {1 {database is locked} {0 1 2 3 4 5}} | |
215 do_test lock-2.4.2 { | |
216 proc callback {count} { | |
217 lappend ::callback_value $count | |
218 if {$count>4} break | |
219 } | |
220 set ::callback_value {} | |
221 db2 busy callback | |
222 execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2 | |
223 # No busy callback this time because we are holding a lock | |
224 set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg] | |
225 lappend r $msg | |
226 lappend r $::callback_value | |
227 } {1 {database is locked} {}} | |
228 catch {execsql {ROLLBACK} db2} | |
229 do_test lock-2.5 { | |
230 proc callback {count} { | |
231 lappend ::callback_value $count | |
232 if {$count>4} break | |
233 } | |
234 set ::callback_value {} | |
235 db2 busy callback | |
236 set r [catch {execsql {SELECT * FROM t1} db2} msg] | |
237 lappend r $msg | |
238 lappend r $::callback_value | |
239 } {0 {2 1} {}} | |
240 execsql {ROLLBACK} | |
241 | |
242 # Test the built-in busy timeout handler | |
243 # | |
244 # EVIDENCE-OF: R-23579-05241 PRAGMA busy_timeout; PRAGMA busy_timeout = | |
245 # milliseconds; Query or change the setting of the busy timeout. | |
246 # | |
247 do_test lock-2.8 { | |
248 db2 timeout 400 | |
249 execsql BEGIN | |
250 execsql {UPDATE t1 SET a = 0 WHERE 0} | |
251 catchsql {BEGIN EXCLUSIVE;} db2 | |
252 } {1 {database is locked}} | |
253 do_test lock-2.8b { | |
254 db2 eval {PRAGMA busy_timeout} | |
255 } {400} | |
256 do_test lock-2.9 { | |
257 db2 timeout 0 | |
258 execsql COMMIT | |
259 } {} | |
260 do_test lock-2.9b { | |
261 db2 eval {PRAGMA busy_timeout} | |
262 } {0} | |
263 integrity_check lock-2.10 | |
264 do_test lock-2.11 { | |
265 db2 eval {PRAGMA busy_timeout(400)} | |
266 execsql BEGIN | |
267 execsql {UPDATE t1 SET a = 0 WHERE 0} | |
268 catchsql {BEGIN EXCLUSIVE;} db2 | |
269 } {1 {database is locked}} | |
270 do_test lock-2.11b { | |
271 db2 eval {PRAGMA busy_timeout} | |
272 } {400} | |
273 do_test lock-2.12 { | |
274 db2 eval {PRAGMA busy_timeout(0)} | |
275 execsql COMMIT | |
276 } {} | |
277 do_test lock-2.12b { | |
278 db2 eval {PRAGMA busy_timeout} | |
279 } {0} | |
280 integrity_check lock-2.13 | |
281 | |
282 # Try to start two transactions in a row | |
283 # | |
284 do_test lock-3.1 { | |
285 execsql {BEGIN TRANSACTION} | |
286 set r [catch {execsql {BEGIN TRANSACTION}} msg] | |
287 execsql {ROLLBACK} | |
288 lappend r $msg | |
289 } {1 {cannot start a transaction within a transaction}} | |
290 integrity_check lock-3.2 | |
291 | |
292 # Make sure the busy handler and error messages work when | |
293 # opening a new pointer to the database while another pointer | |
294 # has the database locked. | |
295 # | |
296 do_test lock-4.1 { | |
297 db2 close | |
298 catch {db eval ROLLBACK} | |
299 db eval BEGIN | |
300 db eval {UPDATE t1 SET a=0 WHERE 0} | |
301 sqlite3 db2 ./test.db | |
302 catchsql {UPDATE t1 SET a=0} db2 | |
303 } {1 {database is locked}} | |
304 do_test lock-4.2 { | |
305 set ::callback_value {} | |
306 set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg] | |
307 lappend rc $msg $::callback_value | |
308 } {1 {database is locked} {}} | |
309 do_test lock-4.3 { | |
310 proc callback {count} { | |
311 lappend ::callback_value $count | |
312 if {$count>4} break | |
313 } | |
314 db2 busy callback | |
315 set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg] | |
316 lappend rc $msg $::callback_value | |
317 } {1 {database is locked} {0 1 2 3 4 5}} | |
318 execsql {ROLLBACK} | |
319 | |
320 # When one thread is writing, other threads cannot read. Except if the | |
321 # writing thread is writing to its temporary tables, the other threads | |
322 # can still read. -> Not so in 3.0. One thread can read while another | |
323 # holds a RESERVED lock. | |
324 # | |
325 proc tx_exec {sql} { | |
326 db2 eval $sql | |
327 } | |
328 do_test lock-5.1 { | |
329 execsql { | |
330 SELECT * FROM t1 | |
331 } | |
332 } {2 1} | |
333 do_test lock-5.2 { | |
334 db function tx_exec tx_exec | |
335 catchsql { | |
336 INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1'); | |
337 } | |
338 } {0 {}} | |
339 | |
340 ifcapable tempdb { | |
341 do_test lock-5.3 { | |
342 execsql { | |
343 CREATE TEMP TABLE t3(x); | |
344 SELECT * FROM t3; | |
345 } | |
346 } {} | |
347 do_test lock-5.4 { | |
348 catchsql { | |
349 INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1'); | |
350 } | |
351 } {0 {}} | |
352 do_test lock-5.5 { | |
353 execsql { | |
354 SELECT * FROM t3; | |
355 } | |
356 } {8} | |
357 do_test lock-5.6 { | |
358 catchsql { | |
359 UPDATE t1 SET a=tx_exec('SELECT x FROM t2'); | |
360 } | |
361 } {0 {}} | |
362 do_test lock-5.7 { | |
363 execsql { | |
364 SELECT * FROM t1; | |
365 } | |
366 } {9 1 9 8} | |
367 do_test lock-5.8 { | |
368 catchsql { | |
369 UPDATE t3 SET x=tx_exec('SELECT x FROM t2'); | |
370 } | |
371 } {0 {}} | |
372 do_test lock-5.9 { | |
373 execsql { | |
374 SELECT * FROM t3; | |
375 } | |
376 } {9} | |
377 } | |
378 | |
379 do_test lock-6.1 { | |
380 execsql { | |
381 CREATE TABLE t4(a PRIMARY KEY, b); | |
382 INSERT INTO t4 VALUES(1, 'one'); | |
383 INSERT INTO t4 VALUES(2, 'two'); | |
384 INSERT INTO t4 VALUES(3, 'three'); | |
385 } | |
386 | |
387 set STMT [sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 TAIL] | |
388 sqlite3_step $STMT | |
389 | |
390 execsql { DELETE FROM t4 } | |
391 execsql { SELECT * FROM sqlite_master } db2 | |
392 execsql { SELECT * FROM t4 } db2 | |
393 } {} | |
394 | |
395 do_test lock-6.2 { | |
396 execsql { | |
397 BEGIN; | |
398 INSERT INTO t4 VALUES(1, 'one'); | |
399 INSERT INTO t4 VALUES(2, 'two'); | |
400 INSERT INTO t4 VALUES(3, 'three'); | |
401 COMMIT; | |
402 } | |
403 | |
404 execsql { SELECT * FROM t4 } db2 | |
405 } {1 one 2 two 3 three} | |
406 | |
407 do_test lock-6.3 { | |
408 execsql { SELECT a FROM t4 ORDER BY a } db2 | |
409 } {1 2 3} | |
410 | |
411 do_test lock-6.4 { | |
412 execsql { PRAGMA integrity_check } db2 | |
413 } {ok} | |
414 | |
415 do_test lock-6.5 { | |
416 sqlite3_finalize $STMT | |
417 } {SQLITE_OK} | |
418 | |
419 # At one point the following set of conditions would cause SQLite to | |
420 # retain a RESERVED or EXCLUSIVE lock after the transaction was committed: | |
421 # | |
422 # * The journal-mode is set to something other than 'delete', and | |
423 # * there exists one or more active read-only statements, and | |
424 # * a transaction that modified zero database pages is committed. | |
425 # | |
426 set temp_status unlocked | |
427 if {$TEMP_STORE>=2} {set temp_status unknown} | |
428 do_test lock-7.1 { | |
429 set STMT [sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 TAIL] | |
430 sqlite3_step $STMT | |
431 } {SQLITE_ROW} | |
432 do_test lock-7.2 { | |
433 execsql { PRAGMA lock_status } | |
434 } [list main shared temp $temp_status] | |
435 do_test lock-7.3 { | |
436 execsql { | |
437 PRAGMA journal_mode = truncate; | |
438 BEGIN; | |
439 UPDATE t4 SET a = 10 WHERE 0; | |
440 COMMIT; | |
441 } | |
442 execsql { PRAGMA lock_status } | |
443 } [list main shared temp $temp_status] | |
444 do_test lock-7.4 { | |
445 sqlite3_finalize $STMT | |
446 } {SQLITE_OK} | |
447 | |
448 do_test lock-999.1 { | |
449 rename db2 {} | |
450 } {} | |
451 | |
452 finish_test | |
OLD | NEW |