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