xref: /illumos-gate/usr/src/lib/libsqlite/test/lock.test (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1*1da57d55SToomas Soome#
2c5c4113dSnw141292# 2001 September 15
3c5c4113dSnw141292#
4c5c4113dSnw141292# The author disclaims copyright to this source code.  In place of
5c5c4113dSnw141292# a legal notice, here is a blessing:
6c5c4113dSnw141292#
7c5c4113dSnw141292#    May you do good and not evil.
8c5c4113dSnw141292#    May you find forgiveness for yourself and forgive others.
9c5c4113dSnw141292#    May you share freely, never taking more than you give.
10c5c4113dSnw141292#
11c5c4113dSnw141292#***********************************************************************
12c5c4113dSnw141292# This file implements regression tests for SQLite library.  The
13c5c4113dSnw141292# focus of this script is database locks.
14c5c4113dSnw141292#
15c5c4113dSnw141292# $Id: lock.test,v 1.20 2004/02/14 16:31:04 drh Exp $
16c5c4113dSnw141292
17c5c4113dSnw141292
18c5c4113dSnw141292set testdir [file dirname $argv0]
19c5c4113dSnw141292source $testdir/tester.tcl
20c5c4113dSnw141292
21c5c4113dSnw141292# Create an alternative connection to the database
22c5c4113dSnw141292#
23c5c4113dSnw141292do_test lock-1.0 {
24c5c4113dSnw141292  sqlite db2 ./test.db
25c5c4113dSnw141292  set dummy {}
26c5c4113dSnw141292} {}
27c5c4113dSnw141292do_test lock-1.1 {
28c5c4113dSnw141292  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
29c5c4113dSnw141292} {}
30c5c4113dSnw141292do_test lock-1.2 {
31c5c4113dSnw141292  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
32c5c4113dSnw141292} {}
33c5c4113dSnw141292do_test lock-1.3 {
34c5c4113dSnw141292  execsql {CREATE TABLE t1(a int, b int)}
35c5c4113dSnw141292  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
36c5c4113dSnw141292} {t1}
37c5c4113dSnw141292#do_test lock-1.4 {
38c5c4113dSnw141292#  catchsql {
39c5c4113dSnw141292#    SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
40c5c4113dSnw141292#  } db2
41c5c4113dSnw141292#} {1 {database schema has changed}}
42c5c4113dSnw141292do_test lock-1.5 {
43c5c4113dSnw141292  catchsql {
44c5c4113dSnw141292     SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
45c5c4113dSnw141292  } db2
46c5c4113dSnw141292} {0 t1}
47c5c4113dSnw141292
48c5c4113dSnw141292do_test lock-1.6 {
49c5c4113dSnw141292  execsql {INSERT INTO t1 VALUES(1,2)}
50c5c4113dSnw141292  execsql {SELECT * FROM t1}
51c5c4113dSnw141292} {1 2}
52c5c4113dSnw141292do_test lock-1.7 {
53c5c4113dSnw141292  execsql {SELECT * FROM t1} db2
54c5c4113dSnw141292} {1 2}
55c5c4113dSnw141292do_test lock-1.8 {
56c5c4113dSnw141292  execsql {UPDATE t1 SET a=b, b=a} db2
57c5c4113dSnw141292  execsql {SELECT * FROM t1} db2
58c5c4113dSnw141292} {2 1}
59c5c4113dSnw141292do_test lock-1.9 {
60c5c4113dSnw141292  execsql {SELECT * FROM t1}
61c5c4113dSnw141292} {2 1}
62c5c4113dSnw141292do_test lock-1.10 {
63c5c4113dSnw141292  execsql {BEGIN TRANSACTION}
64c5c4113dSnw141292  execsql {SELECT * FROM t1}
65c5c4113dSnw141292} {2 1}
66c5c4113dSnw141292do_test lock-1.11 {
67c5c4113dSnw141292  catchsql {SELECT * FROM t1} db2
68c5c4113dSnw141292} {1 {database is locked}}
69c5c4113dSnw141292do_test lock-1.12 {
70c5c4113dSnw141292  execsql {ROLLBACK}
71c5c4113dSnw141292  catchsql {SELECT * FROM t1}
72c5c4113dSnw141292} {0 {2 1}}
73c5c4113dSnw141292
74c5c4113dSnw141292do_test lock-1.13 {
75c5c4113dSnw141292  execsql {CREATE TABLE t2(x int, y int)}
76c5c4113dSnw141292  execsql {INSERT INTO t2 VALUES(8,9)}
77c5c4113dSnw141292  execsql {SELECT * FROM t2}
78c5c4113dSnw141292} {8 9}
79c5c4113dSnw141292do_test lock-1.14.1 {
80c5c4113dSnw141292  catchsql {SELECT * FROM t2} db2
81c5c4113dSnw141292} {1 {no such table: t2}}
82c5c4113dSnw141292do_test lock-1.14.2 {
83c5c4113dSnw141292  catchsql {SELECT * FROM t1} db2
84c5c4113dSnw141292} {0 {2 1}}
85c5c4113dSnw141292do_test lock-1.15 {
86c5c4113dSnw141292  catchsql {SELECT * FROM t2} db2
87c5c4113dSnw141292} {0 {8 9}}
88c5c4113dSnw141292
89c5c4113dSnw141292do_test lock-1.16 {
90c5c4113dSnw141292  db eval {SELECT * FROM t1} qv {
91c5c4113dSnw141292    set x [db eval {SELECT * FROM t1}]
92c5c4113dSnw141292  }
93c5c4113dSnw141292  set x
94c5c4113dSnw141292} {2 1}
95c5c4113dSnw141292do_test lock-1.17 {
96c5c4113dSnw141292  db eval {SELECT * FROM t1} qv {
97c5c4113dSnw141292    set x [db eval {SELECT * FROM t2}]
98c5c4113dSnw141292  }
99c5c4113dSnw141292  set x
100c5c4113dSnw141292} {8 9}
101c5c4113dSnw141292
102c5c4113dSnw141292# You cannot UPDATE a table from within the callback of a SELECT
103c5c4113dSnw141292# on that same table because the SELECT has the table locked.
104c5c4113dSnw141292#
105c5c4113dSnw141292do_test lock-1.18 {
106c5c4113dSnw141292  db eval {SELECT * FROM t1} qv {
107c5c4113dSnw141292    set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
108c5c4113dSnw141292    lappend r $msg
109c5c4113dSnw141292  }
110c5c4113dSnw141292  set r
111c5c4113dSnw141292} {1 {database table is locked}}
112c5c4113dSnw141292
113c5c4113dSnw141292# But you can UPDATE a different table from the one that is used in
114c5c4113dSnw141292# the SELECT.
115c5c4113dSnw141292#
116c5c4113dSnw141292do_test lock-1.19 {
117c5c4113dSnw141292  db eval {SELECT * FROM t1} qv {
118c5c4113dSnw141292    set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
119c5c4113dSnw141292    lappend r $msg
120c5c4113dSnw141292  }
121c5c4113dSnw141292  set r
122c5c4113dSnw141292} {0 {}}
123c5c4113dSnw141292do_test lock-1.20 {
124c5c4113dSnw141292  execsql {SELECT * FROM t2}
125c5c4113dSnw141292} {9 8}
126c5c4113dSnw141292
127c5c4113dSnw141292# It is possible to do a SELECT of the same table within the
128c5c4113dSnw141292# callback of another SELECT on that same table because two
129c5c4113dSnw141292# or more read-only cursors can be open at once.
130c5c4113dSnw141292#
131c5c4113dSnw141292do_test lock-1.21 {
132c5c4113dSnw141292  db eval {SELECT * FROM t1} qv {
133c5c4113dSnw141292    set r [catch {db eval {SELECT a FROM t1}} msg]
134c5c4113dSnw141292    lappend r $msg
135c5c4113dSnw141292  }
136c5c4113dSnw141292  set r
137c5c4113dSnw141292} {0 2}
138c5c4113dSnw141292
139c5c4113dSnw141292# Under UNIX you can do two SELECTs at once with different database
140c5c4113dSnw141292# connections, because UNIX supports reader/writer locks.  Under windows,
141c5c4113dSnw141292# this is not possible.
142c5c4113dSnw141292#
143c5c4113dSnw141292if {$::tcl_platform(platform)=="unix"} {
144c5c4113dSnw141292  do_test lock-1.22 {
145c5c4113dSnw141292    db eval {SELECT * FROM t1} qv {
146c5c4113dSnw141292      set r [catch {db2 eval {SELECT a FROM t1}} msg]
147c5c4113dSnw141292      lappend r $msg
148c5c4113dSnw141292    }
149c5c4113dSnw141292    set r
150c5c4113dSnw141292  } {0 2}
151c5c4113dSnw141292}
152c5c4113dSnw141292integrity_check lock-1.23
153c5c4113dSnw141292
154c5c4113dSnw141292# If one thread has a transaction another thread cannot start
155c5c4113dSnw141292# a transaction.
156c5c4113dSnw141292#
157c5c4113dSnw141292do_test lock-2.1 {
158c5c4113dSnw141292  execsql {BEGIN TRANSACTION}
159c5c4113dSnw141292  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
160c5c4113dSnw141292  lappend r $msg
161c5c4113dSnw141292} {1 {database is locked}}
162c5c4113dSnw141292
163c5c4113dSnw141292# Nor can the other thread do a query.
164c5c4113dSnw141292#
165c5c4113dSnw141292do_test lock-2.2 {
166c5c4113dSnw141292  set r [catch {execsql {SELECT * FROM t2} db2} msg]
167c5c4113dSnw141292  lappend r $msg
168c5c4113dSnw141292} {1 {database is locked}}
169c5c4113dSnw141292
170c5c4113dSnw141292# If the other thread (the one that does not hold the transaction)
171c5c4113dSnw141292# tries to start a transaction, we get a busy callback.
172c5c4113dSnw141292#
173c5c4113dSnw141292do_test lock-2.3 {
174c5c4113dSnw141292  proc callback {args} {
175c5c4113dSnw141292    set ::callback_value $args
176c5c4113dSnw141292    break
177c5c4113dSnw141292  }
178c5c4113dSnw141292  set ::callback_value {}
179c5c4113dSnw141292  db2 busy callback
180c5c4113dSnw141292  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
181c5c4113dSnw141292  lappend r $msg
182c5c4113dSnw141292  lappend r $::callback_value
183c5c4113dSnw141292} {1 {database is locked} {{} 1}}
184c5c4113dSnw141292do_test lock-2.4 {
185c5c4113dSnw141292  proc callback {file count} {
186c5c4113dSnw141292    lappend ::callback_value $count
187c5c4113dSnw141292    if {$count>4} break
188c5c4113dSnw141292  }
189c5c4113dSnw141292  set ::callback_value {}
190c5c4113dSnw141292  db2 busy callback
191c5c4113dSnw141292  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
192c5c4113dSnw141292  lappend r $msg
193c5c4113dSnw141292  lappend r $::callback_value
194c5c4113dSnw141292} {1 {database is locked} {1 2 3 4 5}}
195c5c4113dSnw141292do_test lock-2.5 {
196c5c4113dSnw141292  proc callback {file count} {
197c5c4113dSnw141292    lappend ::callback_value $count
198c5c4113dSnw141292    if {$count>4} break
199c5c4113dSnw141292  }
200c5c4113dSnw141292  set ::callback_value {}
201c5c4113dSnw141292  db2 busy callback
202c5c4113dSnw141292  set r [catch {execsql {SELECT * FROM t1} db2} msg]
203c5c4113dSnw141292  lappend r $msg
204c5c4113dSnw141292  lappend r $::callback_value
205c5c4113dSnw141292} {1 {database is locked} {1 2 3 4 5}}
206c5c4113dSnw141292
207c5c4113dSnw141292# In this test, the 3rd invocation of the busy callback causes
208c5c4113dSnw141292# the first thread to release its transaction.  That allows the
209c5c4113dSnw141292# second thread to continue.
210c5c4113dSnw141292#
211c5c4113dSnw141292do_test lock-2.6 {
212c5c4113dSnw141292  proc callback {file count} {
213c5c4113dSnw141292    lappend ::callback_value $count
214c5c4113dSnw141292    if {$count>2} {
215c5c4113dSnw141292      execsql {ROLLBACK}
216c5c4113dSnw141292    }
217c5c4113dSnw141292  }
218c5c4113dSnw141292  set ::callback_value {}
219c5c4113dSnw141292  db2 busy callback
220c5c4113dSnw141292  set r [catch {execsql {SELECT * FROM t2} db2} msg]
221c5c4113dSnw141292  lappend r $msg
222c5c4113dSnw141292  lappend r $::callback_value
223c5c4113dSnw141292} {0 {9 8} {1 2 3}}
224c5c4113dSnw141292do_test lock-2.7 {
225c5c4113dSnw141292  execsql {BEGIN TRANSACTION}
226c5c4113dSnw141292  proc callback {file count} {
227c5c4113dSnw141292    lappend ::callback_value $count
228c5c4113dSnw141292    if {$count>2} {
229c5c4113dSnw141292      execsql {ROLLBACK}
230c5c4113dSnw141292    }
231c5c4113dSnw141292  }
232c5c4113dSnw141292  set ::callback_value {}
233c5c4113dSnw141292  db2 busy callback
234c5c4113dSnw141292  set r [catch {execsql {BEGIN TRANSACTION} db2} msg]
235c5c4113dSnw141292  execsql {ROLLBACK} db2
236c5c4113dSnw141292  lappend r $msg
237c5c4113dSnw141292  lappend r $::callback_value
238c5c4113dSnw141292} {0 {} {1 2 3}}
239c5c4113dSnw141292
240c5c4113dSnw141292# Test the built-in busy timeout handler
241c5c4113dSnw141292#
242c5c4113dSnw141292do_test lock-2.8 {
243c5c4113dSnw141292  db2 timeout 400
244c5c4113dSnw141292  execsql BEGIN
245c5c4113dSnw141292  catchsql BEGIN db2
246c5c4113dSnw141292} {1 {database is locked}}
247c5c4113dSnw141292do_test lock-2.9 {
248c5c4113dSnw141292  db2 timeout 0
249c5c4113dSnw141292  execsql COMMIT
250c5c4113dSnw141292} {}
251c5c4113dSnw141292integrity_check lock-2.10
252c5c4113dSnw141292
253c5c4113dSnw141292# Try to start two transactions in a row
254c5c4113dSnw141292#
255c5c4113dSnw141292do_test lock-3.1 {
256c5c4113dSnw141292  execsql {BEGIN TRANSACTION}
257c5c4113dSnw141292  set r [catch {execsql {BEGIN TRANSACTION}} msg]
258c5c4113dSnw141292  execsql {ROLLBACK}
259c5c4113dSnw141292  lappend r $msg
260c5c4113dSnw141292} {1 {cannot start a transaction within a transaction}}
261c5c4113dSnw141292integrity_check lock-3.2
262c5c4113dSnw141292
263c5c4113dSnw141292# Make sure the busy handler and error messages work when
264c5c4113dSnw141292# opening a new pointer to the database while another pointer
265c5c4113dSnw141292# has the database locked.
266c5c4113dSnw141292#
267c5c4113dSnw141292do_test lock-4.1 {
268c5c4113dSnw141292  db2 close
269c5c4113dSnw141292  catch {db eval ROLLBACK}
270c5c4113dSnw141292  db eval BEGIN
271c5c4113dSnw141292  sqlite db2 ./test.db
272c5c4113dSnw141292  set rc [catch {db2 eval {SELECT * FROM t1}} msg]
273c5c4113dSnw141292  lappend rc $msg
274c5c4113dSnw141292} {1 {database is locked}}
275c5c4113dSnw141292do_test lock-4.2 {
276c5c4113dSnw141292  set ::callback_value {}
277c5c4113dSnw141292  set rc [catch {db2 eval {SELECT * FROM t1}} msg]
278c5c4113dSnw141292  lappend rc $msg $::callback_value
279c5c4113dSnw141292} {1 {database is locked} {}}
280c5c4113dSnw141292do_test lock-4.3 {
281c5c4113dSnw141292  proc callback {file count} {
282c5c4113dSnw141292    lappend ::callback_value $count
283c5c4113dSnw141292    if {$count>4} break
284c5c4113dSnw141292  }
285c5c4113dSnw141292  db2 busy callback
286c5c4113dSnw141292  set rc [catch {db2 eval {SELECT * FROM t1}} msg]
287c5c4113dSnw141292  lappend rc $msg $::callback_value
288c5c4113dSnw141292} {1 {database is locked} {1 2 3 4 5}}
289c5c4113dSnw141292execsql {ROLLBACK}
290c5c4113dSnw141292
291c5c4113dSnw141292# When one thread is writing, other threads cannot read.  Except if the
292c5c4113dSnw141292# writing thread is writing to its temporary tables, the other threads
293c5c4113dSnw141292# can still read.
294c5c4113dSnw141292#
295c5c4113dSnw141292proc tx_exec {sql} {
296c5c4113dSnw141292  db2 eval $sql
297c5c4113dSnw141292}
298c5c4113dSnw141292do_test lock-5.1 {
299c5c4113dSnw141292  execsql {
300c5c4113dSnw141292    SELECT * FROM t1
301c5c4113dSnw141292  }
302c5c4113dSnw141292} {2 1}
303c5c4113dSnw141292do_test lock-5.2 {
304c5c4113dSnw141292  db function tx_exec tx_exec
305c5c4113dSnw141292  catchsql {
306c5c4113dSnw141292    INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1');
307c5c4113dSnw141292  }
308c5c4113dSnw141292} {1 {database is locked}}
309c5c4113dSnw141292do_test lock-5.3 {
310c5c4113dSnw141292  execsql {
311c5c4113dSnw141292    CREATE TEMP TABLE t3(x);
312c5c4113dSnw141292    SELECT * FROM t3;
313c5c4113dSnw141292  }
314c5c4113dSnw141292} {}
315c5c4113dSnw141292do_test lock-5.4 {
316c5c4113dSnw141292  catchsql {
317c5c4113dSnw141292    INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1');
318c5c4113dSnw141292  }
319c5c4113dSnw141292} {0 {}}
320c5c4113dSnw141292do_test lock-5.5 {
321c5c4113dSnw141292  execsql {
322c5c4113dSnw141292    SELECT * FROM t3;
323c5c4113dSnw141292  }
324c5c4113dSnw141292} {8}
325c5c4113dSnw141292do_test lock-5.6 {
326c5c4113dSnw141292  catchsql {
327c5c4113dSnw141292    UPDATE t1 SET a=tx_exec('SELECT x FROM t2');
328c5c4113dSnw141292  }
329c5c4113dSnw141292} {1 {database is locked}}
330c5c4113dSnw141292do_test lock-5.7 {
331c5c4113dSnw141292  execsql {
332c5c4113dSnw141292    SELECT * FROM t1;
333c5c4113dSnw141292  }
334c5c4113dSnw141292} {2 1}
335c5c4113dSnw141292do_test lock-5.8 {
336c5c4113dSnw141292  catchsql {
337c5c4113dSnw141292    UPDATE t3 SET x=tx_exec('SELECT x FROM t2');
338c5c4113dSnw141292  }
339c5c4113dSnw141292} {0 {}}
340c5c4113dSnw141292do_test lock-5.9 {
341c5c4113dSnw141292  execsql {
342c5c4113dSnw141292    SELECT * FROM t3;
343c5c4113dSnw141292  }
344c5c4113dSnw141292} {9}
345c5c4113dSnw141292
346c5c4113dSnw141292do_test lock-999.1 {
347c5c4113dSnw141292  rename db2 {}
348c5c4113dSnw141292} {}
349c5c4113dSnw141292
350c5c4113dSnw141292finish_test
351