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