xref: /sqlite-3.40.0/test/lock.test (revision ed326d70)
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.28 2004/11/16 15:50:21 danielk1977 Exp $
15
16
17set testdir [file dirname $argv0]
18source $testdir/tester.tcl
19
20# Create an alternative connection to the database
21#
22do_test lock-1.0 {
23  sqlite3 db2 ./test.db
24  set dummy {}
25} {}
26do_test lock-1.1 {
27  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
28} {}
29do_test lock-1.2 {
30  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
31} {}
32do_test lock-1.3 {
33  execsql {CREATE TABLE t1(a int, b int)}
34  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
35} {t1}
36do_test lock-1.5 {
37  catchsql {
38     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
39  } db2
40} {0 t1}
41
42do_test lock-1.6 {
43  execsql {INSERT INTO t1 VALUES(1,2)}
44  execsql {SELECT * FROM t1}
45} {1 2}
46# Update: The schema is now brought up to date by test lock-1.5.
47# do_test lock-1.7.1 {
48#   catchsql {SELECT * FROM t1} db2
49# } {1 {no such table: t1}}
50do_test lock-1.7.2 {
51  catchsql {SELECT * FROM t1} db2
52} {0 {1 2}}
53do_test lock-1.8 {
54  execsql {UPDATE t1 SET a=b, b=a} db2
55  execsql {SELECT * FROM t1} db2
56} {2 1}
57do_test lock-1.9 {
58  execsql {SELECT * FROM t1}
59} {2 1}
60do_test lock-1.10 {
61  execsql {BEGIN TRANSACTION}
62  execsql {UPDATE t1 SET a = 0 WHERE 0}
63  execsql {SELECT * FROM t1}
64} {2 1}
65do_test lock-1.11 {
66  catchsql {SELECT * FROM t1} db2
67} {0 {2 1}}
68do_test lock-1.12 {
69  execsql {ROLLBACK}
70  catchsql {SELECT * FROM t1}
71} {0 {2 1}}
72
73do_test lock-1.13 {
74  execsql {CREATE TABLE t2(x int, y int)}
75  execsql {INSERT INTO t2 VALUES(8,9)}
76  execsql {SELECT * FROM t2}
77} {8 9}
78do_test lock-1.14.1 {
79  catchsql {SELECT * FROM t2} db2
80} {1 {no such table: t2}}
81do_test lock-1.14.2 {
82  catchsql {SELECT * FROM t1} db2
83} {0 {2 1}}
84do_test lock-1.15 {
85  catchsql {SELECT * FROM t2} db2
86} {0 {8 9}}
87
88do_test lock-1.16 {
89  db eval {SELECT * FROM t1} qv {
90    set x [db eval {SELECT * FROM t1}]
91  }
92  set x
93} {2 1}
94do_test lock-1.17 {
95  db eval {SELECT * FROM t1} qv {
96    set x [db eval {SELECT * FROM t2}]
97  }
98  set x
99} {8 9}
100
101# Previously, this test ensured that you cannot UPDATE a table from within the
102# callback of a SELECT on that same table because the SELECT has the table
103# locked. But as of 3.10 you can do this, so the test is removed.
104#
105#do_test lock-1.18 {
106#  db eval {SELECT * FROM t1} qv {
107#    set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
108#    lappend r $msg
109#  }
110#  set r
111#} {1 {database table is locked}}
112
113# But you can UPDATE a different table from the one that is used in
114# the SELECT.
115#
116do_test lock-1.19 {
117  db eval {SELECT * FROM t1} qv {
118    set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
119    lappend r $msg
120  }
121  set r
122} {0 {}}
123do_test lock-1.20 {
124  execsql {SELECT * FROM t2}
125} {9 8}
126
127# It is possible to do a SELECT of the same table within the
128# callback of another SELECT on that same table because two
129# or more read-only cursors can be open at once.
130#
131do_test lock-1.21 {
132  db eval {SELECT * FROM t1} qv {
133    set r [catch {db eval {SELECT a FROM t1}} msg]
134    lappend r $msg
135  }
136  set r
137} {0 2}
138
139# Under UNIX you can do two SELECTs at once with different database
140# connections, because UNIX supports reader/writer locks.  Under windows,
141# this is not possible.
142#
143if {$::tcl_platform(platform)=="unix"} {
144  do_test lock-1.22 {
145    db eval {SELECT * FROM t1} qv {
146      set r [catch {db2 eval {SELECT a FROM t1}} msg]
147      lappend r $msg
148    }
149    set r
150  } {0 2}
151}
152integrity_check lock-1.23
153
154# If one thread has a transaction another thread cannot start
155# a transaction.  -> Not true in version 3.0.  But if one thread
156# as a RESERVED lock another thread cannot acquire one.
157#
158do_test lock-2.1 {
159  execsql {BEGIN TRANSACTION}
160  execsql {UPDATE t1 SET a = 0 WHERE 0}
161  execsql {BEGIN TRANSACTION} db2
162  set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
163  execsql {ROLLBACK} db2
164  lappend r $msg
165} {1 {database is locked}}
166
167# A thread can read when another has a RESERVED lock.
168#
169do_test lock-2.2 {
170  catchsql {SELECT * FROM t2} db2
171} {0 {9 8}}
172
173# If the other thread (the one that does not hold the transaction with
174# a RESERVED lock) tries to get a RESERVED lock, we do not get a busy callback.
175#
176do_test lock-2.3 {
177  proc callback {count} {
178    set ::callback_value $count
179    break
180  }
181  set ::callback_value {}
182  db2 busy callback
183  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
184  lappend r $msg
185  lappend r $::callback_value
186} {1 {database is locked} {}}
187do_test lock-2.4 {
188  proc callback {count} {
189    lappend ::callback_value $count
190    if {$count>4} break
191  }
192  set ::callback_value {}
193  db2 busy callback
194  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
195  lappend r $msg
196  lappend r $::callback_value
197} {1 {database is locked} {}}
198do_test lock-2.5 {
199  proc callback {count} {
200    lappend ::callback_value $count
201    if {$count>4} break
202  }
203  set ::callback_value {}
204  db2 busy callback
205  set r [catch {execsql {SELECT * FROM t1} db2} msg]
206  lappend r $msg
207  lappend r $::callback_value
208} {0 {2 1} {}}
209execsql {ROLLBACK}
210
211# Test the built-in busy timeout handler
212#
213do_test lock-2.8 {
214  db2 timeout 400
215  execsql BEGIN
216  execsql {UPDATE t1 SET a = 0 WHERE 0}
217  # catchsql BEGIN db2
218  catchsql {UPDATE t1 SET a = 0 WHERE 0} db2
219} {1 {database is locked}}
220do_test lock-2.9 {
221  db2 timeout 0
222  execsql COMMIT
223} {}
224integrity_check lock-2.10
225
226# Try to start two transactions in a row
227#
228do_test lock-3.1 {
229  execsql {BEGIN TRANSACTION}
230  set r [catch {execsql {BEGIN TRANSACTION}} msg]
231  execsql {ROLLBACK}
232  lappend r $msg
233} {1 {cannot start a transaction within a transaction}}
234integrity_check lock-3.2
235
236# Make sure the busy handler and error messages work when
237# opening a new pointer to the database while another pointer
238# has the database locked.
239#
240do_test lock-4.1 {
241  db2 close
242  catch {db eval ROLLBACK}
243  db eval BEGIN
244  db eval {UPDATE t1 SET a=0 WHERE 0}
245  sqlite3 db2 ./test.db
246  catchsql {UPDATE t1 SET a=0} db2
247} {1 {database is locked}}
248do_test lock-4.2 {
249  set ::callback_value {}
250  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
251  lappend rc $msg $::callback_value
252} {1 {database is locked} {}}
253do_test lock-4.3 {
254  proc callback {count} {
255    lappend ::callback_value $count
256    if {$count>4} break
257  }
258  db2 busy callback
259  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
260  lappend rc $msg $::callback_value
261} {1 {database is locked} {}}
262execsql {ROLLBACK}
263
264# When one thread is writing, other threads cannot read.  Except if the
265# writing thread is writing to its temporary tables, the other threads
266# can still read.  -> Not so in 3.0.  One thread can read while another
267# holds a RESERVED lock.
268#
269proc tx_exec {sql} {
270  db2 eval $sql
271}
272do_test lock-5.1 {
273  execsql {
274    SELECT * FROM t1
275  }
276} {2 1}
277do_test lock-5.2 {
278  db function tx_exec tx_exec
279  catchsql {
280    INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1');
281  }
282} {0 {}}
283do_test lock-5.3 {
284  execsql {
285    CREATE TEMP TABLE t3(x);
286    SELECT * FROM t3;
287  }
288} {}
289do_test lock-5.4 {
290  catchsql {
291    INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1');
292  }
293} {0 {}}
294do_test lock-5.5 {
295  execsql {
296    SELECT * FROM t3;
297  }
298} {8}
299do_test lock-5.6 {
300  catchsql {
301    UPDATE t1 SET a=tx_exec('SELECT x FROM t2');
302  }
303} {0 {}}
304do_test lock-5.7 {
305  execsql {
306    SELECT * FROM t1;
307  }
308} {9 1 9 8}
309do_test lock-5.8 {
310  catchsql {
311    UPDATE t3 SET x=tx_exec('SELECT x FROM t2');
312  }
313} {0 {}}
314do_test lock-5.9 {
315  execsql {
316    SELECT * FROM t3;
317  }
318} {9}
319
320do_test lock-999.1 {
321  rename db2 {}
322} {}
323
324finish_test
325