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 do_test lock-2.8 { | |
245 db2 timeout 400 | |
246 execsql BEGIN | |
247 execsql {UPDATE t1 SET a = 0 WHERE 0} | |
248 catchsql {BEGIN EXCLUSIVE;} db2 | |
249 } {1 {database is locked}} | |
250 do_test lock-2.8b { | |
251 db2 eval {PRAGMA busy_timeout} | |
252 } {400} | |
253 do_test lock-2.9 { | |
254 db2 timeout 0 | |
255 execsql COMMIT | |
256 } {} | |
257 do_test lock-2.9b { | |
258 db2 eval {PRAGMA busy_timeout} | |
259 } {0} | |
260 integrity_check lock-2.10 | |
261 do_test lock-2.11 { | |
262 db2 eval {PRAGMA busy_timeout(400)} | |
263 execsql BEGIN | |
264 execsql {UPDATE t1 SET a = 0 WHERE 0} | |
265 catchsql {BEGIN EXCLUSIVE;} db2 | |
266 } {1 {database is locked}} | |
267 do_test lock-2.11b { | |
268 db2 eval {PRAGMA busy_timeout} | |
269 } {400} | |
270 do_test lock-2.12 { | |
271 db2 eval {PRAGMA busy_timeout(0)} | |
272 execsql COMMIT | |
273 } {} | |
274 do_test lock-2.12b { | |
275 db2 eval {PRAGMA busy_timeout} | |
276 } {0} | |
277 integrity_check lock-2.13 | |
278 | |
279 # Try to start two transactions in a row | |
280 # | |
281 do_test lock-3.1 { | |
282 execsql {BEGIN TRANSACTION} | |
283 set r [catch {execsql {BEGIN TRANSACTION}} msg] | |
284 execsql {ROLLBACK} | |
285 lappend r $msg | |
286 } {1 {cannot start a transaction within a transaction}} | |
287 integrity_check lock-3.2 | |
288 | |
289 # Make sure the busy handler and error messages work when | |
290 # opening a new pointer to the database while another pointer | |
291 # has the database locked. | |
292 # | |
293 do_test lock-4.1 { | |
294 db2 close | |
295 catch {db eval ROLLBACK} | |
296 db eval BEGIN | |
297 db eval {UPDATE t1 SET a=0 WHERE 0} | |
298 sqlite3 db2 ./test.db | |
299 catchsql {UPDATE t1 SET a=0} db2 | |
300 } {1 {database is locked}} | |
301 do_test lock-4.2 { | |
302 set ::callback_value {} | |
303 set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg] | |
304 lappend rc $msg $::callback_value | |
305 } {1 {database is locked} {}} | |
306 do_test lock-4.3 { | |
307 proc callback {count} { | |
308 lappend ::callback_value $count | |
309 if {$count>4} break | |
310 } | |
311 db2 busy callback | |
312 set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg] | |
313 lappend rc $msg $::callback_value | |
314 } {1 {database is locked} {0 1 2 3 4 5}} | |
315 execsql {ROLLBACK} | |
316 | |
317 # When one thread is writing, other threads cannot read. Except if the | |
318 # writing thread is writing to its temporary tables, the other threads | |
319 # can still read. -> Not so in 3.0. One thread can read while another | |
320 # holds a RESERVED lock. | |
321 # | |
322 proc tx_exec {sql} { | |
323 db2 eval $sql | |
324 } | |
325 do_test lock-5.1 { | |
326 execsql { | |
327 SELECT * FROM t1 | |
328 } | |
329 } {2 1} | |
330 do_test lock-5.2 { | |
331 db function tx_exec tx_exec | |
332 catchsql { | |
333 INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1'); | |
334 } | |
335 } {0 {}} | |
336 | |
337 ifcapable tempdb { | |
338 do_test lock-5.3 { | |
339 execsql { | |
340 CREATE TEMP TABLE t3(x); | |
341 SELECT * FROM t3; | |
342 } | |
343 } {} | |
344 do_test lock-5.4 { | |
345 catchsql { | |
346 INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1'); | |
347 } | |
348 } {0 {}} | |
349 do_test lock-5.5 { | |
350 execsql { | |
351 SELECT * FROM t3; | |
352 } | |
353 } {8} | |
354 do_test lock-5.6 { | |
355 catchsql { | |
356 UPDATE t1 SET a=tx_exec('SELECT x FROM t2'); | |
357 } | |
358 } {0 {}} | |
359 do_test lock-5.7 { | |
360 execsql { | |
361 SELECT * FROM t1; | |
362 } | |
363 } {9 1 9 8} | |
364 do_test lock-5.8 { | |
365 catchsql { | |
366 UPDATE t3 SET x=tx_exec('SELECT x FROM t2'); | |
367 } | |
368 } {0 {}} | |
369 do_test lock-5.9 { | |
370 execsql { | |
371 SELECT * FROM t3; | |
372 } | |
373 } {9} | |
374 } | |
375 | |
376 do_test lock-6.1 { | |
377 execsql { | |
378 CREATE TABLE t4(a PRIMARY KEY, b); | |
379 INSERT INTO t4 VALUES(1, 'one'); | |
380 INSERT INTO t4 VALUES(2, 'two'); | |
381 INSERT INTO t4 VALUES(3, 'three'); | |
382 } | |
383 | |
384 set STMT [sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 TAIL] | |
385 sqlite3_step $STMT | |
386 | |
387 execsql { DELETE FROM t4 } | |
388 execsql { SELECT * FROM sqlite_master } db2 | |
389 execsql { SELECT * FROM t4 } db2 | |
390 } {} | |
391 | |
392 do_test lock-6.2 { | |
393 execsql { | |
394 BEGIN; | |
395 INSERT INTO t4 VALUES(1, 'one'); | |
396 INSERT INTO t4 VALUES(2, 'two'); | |
397 INSERT INTO t4 VALUES(3, 'three'); | |
398 COMMIT; | |
399 } | |
400 | |
401 execsql { SELECT * FROM t4 } db2 | |
402 } {1 one 2 two 3 three} | |
403 | |
404 do_test lock-6.3 { | |
405 execsql { SELECT a FROM t4 ORDER BY a } db2 | |
406 } {1 2 3} | |
407 | |
408 do_test lock-6.4 { | |
409 execsql { PRAGMA integrity_check } db2 | |
410 } {ok} | |
411 | |
412 do_test lock-6.5 { | |
413 sqlite3_finalize $STMT | |
414 } {SQLITE_OK} | |
415 | |
416 # At one point the following set of conditions would cause SQLite to | |
417 # retain a RESERVED or EXCLUSIVE lock after the transaction was committed: | |
418 # | |
419 # * The journal-mode is set to something other than 'delete', and | |
420 # * there exists one or more active read-only statements, and | |
421 # * a transaction that modified zero database pages is committed. | |
422 # | |
423 set temp_status unlocked | |
424 if {$TEMP_STORE>=2} {set temp_status unknown} | |
425 do_test lock-7.1 { | |
426 set STMT [sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 TAIL] | |
427 sqlite3_step $STMT | |
428 } {SQLITE_ROW} | |
429 do_test lock-7.2 { | |
430 execsql { PRAGMA lock_status } | |
431 } [list main shared temp $temp_status] | |
432 do_test lock-7.3 { | |
433 execsql { | |
434 PRAGMA journal_mode = truncate; | |
435 BEGIN; | |
436 UPDATE t4 SET a = 10 WHERE 0; | |
437 COMMIT; | |
438 } | |
439 execsql { PRAGMA lock_status } | |
440 } [list main shared temp $temp_status] | |
441 do_test lock-7.4 { | |
442 sqlite3_finalize $STMT | |
443 } {SQLITE_OK} | |
444 | |
445 do_test lock-999.1 { | |
446 rename db2 {} | |
447 } {} | |
448 | |
449 finish_test | |
OLD | NEW |