blob: bbf48503c4448644e14a36431a1ad8811aa13436 [file] [log] [blame]
danielk1977aef0bf62005-12-30 16:28:01 +00001# 2005 December 30
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#***********************************************************************
danielk1977aef0bf62005-12-30 16:28:01 +000011#
danielk1977191c3e72006-01-19 07:18:14 +000012# $Id: shared.test,v 1.18 2006/01/19 07:18:15 danielk1977 Exp $
danielk1977aef0bf62005-12-30 16:28:01 +000013
14set testdir [file dirname $argv0]
15source $testdir/tester.tcl
16db close
17
18ifcapable !shared_cache {
19 finish_test
20 return
21}
danielk1977a96a7102006-01-16 12:46:41 +000022
danielk1977da184232006-01-05 11:34:32 +000023set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
danielk1977aef0bf62005-12-30 16:28:01 +000024
danielk1977a96a7102006-01-16 12:46:41 +000025foreach av [list 0 1] {
26
danielk1977bab45c62006-01-16 15:14:27 +000027# Open the database connection and execute the auto-vacuum pragma
28file delete -force test.db
29sqlite3 db test.db
30
31ifcapable autovacuum {
32 do_test shared-[expr $av+1].1.0 {
33 execsql "pragma auto_vacuum=$::av"
34 execsql {pragma auto_vacuum}
35 } "$av"
36} else {
37 if {$av} {
38 db close
39 break
40 }
danielk1977a96a7102006-01-16 12:46:41 +000041}
42
danielk1977191c3e72006-01-19 07:18:14 +000043# $av is currently 0 if this loop iteration is to test with auto-vacuum turned
44# off, and 1 if it is turned on. Increment it so that (1 -> no auto-vacuum)
45# and (2 -> auto-vacuum). The sole reason for this is so that it looks nicer
46# when we use this variable as part of test-case names.
47#
danielk1977a96a7102006-01-16 12:46:41 +000048incr av
49
danielk1977aef0bf62005-12-30 16:28:01 +000050# Test organization:
51#
52# shared-1.*: Simple test to verify basic sanity of table level locking when
53# two connections share a pager cache.
54# shared-2.*: Test that a read transaction can co-exist with a
55# write-transaction, including a simple test to ensure the
56# external locking protocol is still working.
danielk1977da184232006-01-05 11:34:32 +000057# shared-3.*: Simple test of read-uncommitted mode.
danielk1977de0fe3e2006-01-06 06:33:12 +000058# shared-4.*: Check that the schema is locked and unlocked correctly.
danielk1977aaf22682006-01-06 15:03:48 +000059# shared-5.*: Test that creating/dropping schema items works when databases
60# are attached in different orders to different handles.
danielk1977c00da102006-01-07 13:21:04 +000061# shared-6.*: Locking, UNION ALL queries and sub-queries.
danielk197714db2662006-01-09 16:12:04 +000062# shared-7.*: Autovacuum and shared-cache.
danielk1977de0fe3e2006-01-06 06:33:12 +000063#
danielk1977aef0bf62005-12-30 16:28:01 +000064
danielk1977a96a7102006-01-16 12:46:41 +000065do_test shared-$av.1.1 {
danielk1977aef0bf62005-12-30 16:28:01 +000066 # Open a second database on the file test.db. It should use the same pager
67 # cache and schema as the original connection. Verify that only 1 file is
68 # opened.
69 sqlite3 db2 test.db
danielk1977aef0bf62005-12-30 16:28:01 +000070 set ::sqlite_open_file_count
71} {1}
danielk1977a96a7102006-01-16 12:46:41 +000072do_test shared-$av.1.2 {
danielk1977aef0bf62005-12-30 16:28:01 +000073 # Add a table and a single row of data via the first connection.
74 # Ensure that the second connection can see them.
75 execsql {
76 CREATE TABLE abc(a, b, c);
77 INSERT INTO abc VALUES(1, 2, 3);
78 } db
79 execsql {
80 SELECT * FROM abc;
81 } db2
82} {1 2 3}
danielk1977a96a7102006-01-16 12:46:41 +000083do_test shared-$av.1.3 {
danielk1977aef0bf62005-12-30 16:28:01 +000084 # Have the first connection begin a transaction and obtain a read-lock
85 # on table abc. This should not prevent the second connection from
86 # querying abc.
87 execsql {
88 BEGIN;
89 SELECT * FROM abc;
90 }
91 execsql {
92 SELECT * FROM abc;
93 } db2
94} {1 2 3}
danielk1977a96a7102006-01-16 12:46:41 +000095do_test shared-$av.1.4 {
danielk1977aef0bf62005-12-30 16:28:01 +000096 # Try to insert a row into abc via connection 2. This should fail because
97 # of the read-lock connection 1 is holding on table abc (obtained in the
98 # previous test case).
99 catchsql {
100 INSERT INTO abc VALUES(4, 5, 6);
101 } db2
danielk1977c00da102006-01-07 13:21:04 +0000102} {1 {database table is locked: abc}}
danielk1977a96a7102006-01-16 12:46:41 +0000103do_test shared-$av.1.5 {
danielk1977da184232006-01-05 11:34:32 +0000104 # Using connection 2 (the one without the open transaction), try to create
105 # a new table. This should fail because of the open read transaction
106 # held by connection 1.
107 catchsql {
108 CREATE TABLE def(d, e, f);
109 } db2
danielk1977c00da102006-01-07 13:21:04 +0000110} {1 {database table is locked: sqlite_master}}
danielk1977a96a7102006-01-16 12:46:41 +0000111do_test shared-$av.1.6 {
danielk1977da184232006-01-05 11:34:32 +0000112 # Upgrade connection 1's transaction to a write transaction. Create
113 # a new table - def - and insert a row into it. Because the connection 1
114 # transaction modifies the schema, it should not be possible for
115 # connection 2 to access the database at all until the connection 1
116 # has finished the transaction.
danielk1977aef0bf62005-12-30 16:28:01 +0000117 execsql {
118 CREATE TABLE def(d, e, f);
danielk1977aef0bf62005-12-30 16:28:01 +0000119 INSERT INTO def VALUES('IV', 'V', 'VI');
120 }
121} {}
danielk1977a96a7102006-01-16 12:46:41 +0000122do_test shared-$av.1.7 {
danielk1977aef0bf62005-12-30 16:28:01 +0000123 # Read from the sqlite_master table with connection 1 (inside the
danielk1977da184232006-01-05 11:34:32 +0000124 # transaction). Then test that we can not do this with connection 2. This
125 # is because of the schema-modified lock established by connection 1
126 # in the previous test case.
danielk1977aef0bf62005-12-30 16:28:01 +0000127 execsql {
128 SELECT * FROM sqlite_master;
129 }
130 catchsql {
danielk1977da184232006-01-05 11:34:32 +0000131 SELECT * FROM sqlite_master;
danielk1977aef0bf62005-12-30 16:28:01 +0000132 } db2
danielk1977c87d34d2006-01-06 13:00:28 +0000133} {1 {database schema is locked: main}}
danielk1977a96a7102006-01-16 12:46:41 +0000134do_test shared-$av.1.8 {
danielk1977aef0bf62005-12-30 16:28:01 +0000135 # Commit the connection 1 transaction.
136 execsql {
137 COMMIT;
138 }
139} {}
140
danielk1977a96a7102006-01-16 12:46:41 +0000141do_test shared-$av.2.1 {
danielk1977aef0bf62005-12-30 16:28:01 +0000142 # Open connection db3 to the database. Use a different path to the same
143 # file so that db3 does *not* share the same pager cache as db and db2
144 # (there should be two open file handles).
145 sqlite3 db3 ./test.db
146 set ::sqlite_open_file_count
147} {2}
danielk1977a96a7102006-01-16 12:46:41 +0000148do_test shared-$av.2.2 {
danielk1977aef0bf62005-12-30 16:28:01 +0000149 # Start read transactions on db and db2 (the shared pager cache). Ensure
150 # db3 cannot write to the database.
151 execsql {
152 BEGIN;
153 SELECT * FROM abc;
154 }
155 execsql {
156 BEGIN;
157 SELECT * FROM abc;
158 } db2
159 catchsql {
160 INSERT INTO abc VALUES(1, 2, 3);
161 } db2
danielk1977c00da102006-01-07 13:21:04 +0000162} {1 {database table is locked: abc}}
danielk1977a96a7102006-01-16 12:46:41 +0000163do_test shared-$av.2.3 {
danielk1977aef0bf62005-12-30 16:28:01 +0000164 # Turn db's transaction into a write-transaction. db3 should still be
165 # able to read from table def (but will not see the new row). Connection
166 # db2 should not be able to read def (because of the write-lock).
167
168# Todo: The failed "INSERT INTO abc ..." statement in the above test
169# has started a write-transaction on db2 (should this be so?). This
170# would prevent connection db from starting a write-transaction. So roll the
171# db2 transaction back and replace it with a new read transaction.
172 execsql {
173 ROLLBACK;
174 BEGIN;
175 SELECT * FROM abc;
176 } db2
177
178 execsql {
179 INSERT INTO def VALUES('VII', 'VIII', 'IX');
180 }
181 concat [
182 catchsql { SELECT * FROM def; } db3
183 ] [
184 catchsql { SELECT * FROM def; } db2
185 ]
danielk1977c00da102006-01-07 13:21:04 +0000186} {0 {IV V VI} 1 {database table is locked: def}}
danielk1977a96a7102006-01-16 12:46:41 +0000187do_test shared-$av.2.4 {
danielk1977aef0bf62005-12-30 16:28:01 +0000188 # Commit the open transaction on db. db2 still holds a read-transaction.
189 # This should prevent db3 from writing to the database, but not from
190 # reading.
191 execsql {
192 COMMIT;
193 }
194 concat [
195 catchsql { SELECT * FROM def; } db3
196 ] [
197 catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3
198 ]
danielk1977da184232006-01-05 11:34:32 +0000199} {0 {IV V VI VII VIII IX} 1 {database is locked}}
danielk1977aef0bf62005-12-30 16:28:01 +0000200
danielk1977da184232006-01-05 11:34:32 +0000201catchsql COMMIT db2
202
danielk1977a96a7102006-01-16 12:46:41 +0000203do_test shared-$av.3.1.1 {
danielk1977da184232006-01-05 11:34:32 +0000204 # This test case starts a linear scan of table 'seq' using a
205 # read-uncommitted connection. In the middle of the scan, rows are added
206 # to the end of the seq table (ahead of the current cursor position).
207 # The uncommitted rows should be included in the results of the scan.
208 execsql "
danielk1977191c3e72006-01-19 07:18:14 +0000209 CREATE TABLE seq(i PRIMARY KEY, x);
danielk1977da184232006-01-05 11:34:32 +0000210 INSERT INTO seq VALUES(1, '[string repeat X 500]');
211 INSERT INTO seq VALUES(2, '[string repeat X 500]');
212 "
213 execsql {SELECT * FROM sqlite_master} db2
214 execsql {PRAGMA read_uncommitted = 1} db2
215
216 set ret [list]
danielk1977191c3e72006-01-19 07:18:14 +0000217 db2 eval {SELECT i FROM seq ORDER BY i} {
danielk1977da184232006-01-05 11:34:32 +0000218 if {$i < 4} {
danielk19771576cd92006-01-14 08:02:28 +0000219 set max [execsql {SELECT max(i) FROM seq}]
220 db eval {
danielk19773bdca9c2006-01-17 09:35:01 +0000221 INSERT INTO seq SELECT i + :max, x FROM seq;
danielk1977da184232006-01-05 11:34:32 +0000222 }
223 }
224 lappend ret $i
225 }
226 set ret
227} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
danielk1977a96a7102006-01-16 12:46:41 +0000228do_test shared-$av.3.1.2 {
danielk1977da184232006-01-05 11:34:32 +0000229 # Another linear scan through table seq using a read-uncommitted connection.
230 # This time, delete each row as it is read. Should not affect the results of
231 # the scan, but the table should be empty after the scan is concluded
232 # (test 3.1.3 verifies this).
233 set ret [list]
234 db2 eval {SELECT i FROM seq} {
danielk19773bdca9c2006-01-17 09:35:01 +0000235 db eval {DELETE FROM seq WHERE i = :i}
danielk1977da184232006-01-05 11:34:32 +0000236 lappend ret $i
237 }
238 set ret
239} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
danielk1977a96a7102006-01-16 12:46:41 +0000240do_test shared-$av.3.1.3 {
danielk1977da184232006-01-05 11:34:32 +0000241 execsql {
242 SELECT * FROM seq;
243 }
244} {}
danielk1977aef0bf62005-12-30 16:28:01 +0000245
246catch {db close}
247catch {db2 close}
248catch {db3 close}
249
danielk1977de0fe3e2006-01-06 06:33:12 +0000250#--------------------------------------------------------------------------
251# Tests shared-4.* test that the schema locking rules are applied
252# correctly. i.e.:
253#
254# 1. All transactions require a read-lock on the schemas of databases they
255# access.
256# 2. Transactions that modify a database schema require a write-lock on that
257# schema.
258# 3. It is not possible to compile a statement while another handle has a
259# write-lock on the schema.
260#
261
262# Open two database handles db and db2. Each has a single attach database
263# (as well as main):
264#
265# db.main -> ./test.db
266# db.test2 -> ./test2.db
267# db2.main -> ./test2.db
268# db2.test -> ./test.db
269#
270file delete -force test.db
271file delete -force test2.db
272file delete -force test2.db-journal
273sqlite3 db test.db
274sqlite3 db2 test2.db
danielk1977a96a7102006-01-16 12:46:41 +0000275do_test shared-$av.4.1.1 {
danielk1977de0fe3e2006-01-06 06:33:12 +0000276 set sqlite_open_file_count
277} {2}
danielk1977a96a7102006-01-16 12:46:41 +0000278do_test shared-$av.4.1.2 {
danielk1977de0fe3e2006-01-06 06:33:12 +0000279 execsql {ATTACH 'test2.db' AS test2}
280 set sqlite_open_file_count
281} {2}
danielk1977a96a7102006-01-16 12:46:41 +0000282do_test shared-$av.4.1.3 {
danielk1977de0fe3e2006-01-06 06:33:12 +0000283 execsql {ATTACH 'test.db' AS test} db2
284 set sqlite_open_file_count
285} {2}
286
danielk1977c87d34d2006-01-06 13:00:28 +0000287# Sanity check: Create a table in ./test.db via handle db, and test that handle
288# db2 can "see" the new table immediately. A handle using a seperate pager
289# cache would have to reload the database schema before this were possible.
290#
danielk1977a96a7102006-01-16 12:46:41 +0000291do_test shared-$av.4.2.1 {
danielk1977de0fe3e2006-01-06 06:33:12 +0000292 execsql {
293 CREATE TABLE abc(a, b, c);
danielk1977c87d34d2006-01-06 13:00:28 +0000294 CREATE TABLE def(d, e, f);
danielk1977de0fe3e2006-01-06 06:33:12 +0000295 INSERT INTO abc VALUES('i', 'ii', 'iii');
danielk1977c87d34d2006-01-06 13:00:28 +0000296 INSERT INTO def VALUES('I', 'II', 'III');
danielk1977de0fe3e2006-01-06 06:33:12 +0000297 }
298} {}
danielk1977a96a7102006-01-16 12:46:41 +0000299do_test shared-$av.4.2.2 {
danielk1977de0fe3e2006-01-06 06:33:12 +0000300 execsql {
301 SELECT * FROM test.abc;
302 } db2
303} {i ii iii}
304
danielk1977c87d34d2006-01-06 13:00:28 +0000305# Open a read-transaction and read from table abc via handle 2. Check that
306# handle 1 can read table abc. Check that handle 1 cannot modify table abc
307# or the database schema. Then check that handle 1 can modify table def.
308#
danielk1977a96a7102006-01-16 12:46:41 +0000309do_test shared-$av.4.3.1 {
danielk1977c87d34d2006-01-06 13:00:28 +0000310 execsql {
311 BEGIN;
312 SELECT * FROM test.abc;
313 } db2
314} {i ii iii}
danielk1977a96a7102006-01-16 12:46:41 +0000315do_test shared-$av.4.3.2 {
danielk1977c87d34d2006-01-06 13:00:28 +0000316 catchsql {
317 INSERT INTO abc VALUES('iv', 'v', 'vi');
318 }
danielk1977c00da102006-01-07 13:21:04 +0000319} {1 {database table is locked: abc}}
danielk1977a96a7102006-01-16 12:46:41 +0000320do_test shared-$av.4.3.3 {
danielk1977c87d34d2006-01-06 13:00:28 +0000321 catchsql {
322 CREATE TABLE ghi(g, h, i);
323 }
danielk1977c00da102006-01-07 13:21:04 +0000324} {1 {database table is locked: sqlite_master}}
danielk1977a96a7102006-01-16 12:46:41 +0000325do_test shared-$av.4.3.3 {
danielk1977c87d34d2006-01-06 13:00:28 +0000326 catchsql {
327 INSERT INTO def VALUES('IV', 'V', 'VI');
328 }
329} {0 {}}
danielk1977a96a7102006-01-16 12:46:41 +0000330do_test shared-$av.4.3.4 {
danielk1977c87d34d2006-01-06 13:00:28 +0000331 # Cleanup: commit the transaction opened by db2.
332 execsql {
333 COMMIT
334 } db2
335} {}
336
337# Open a write-transaction using handle 1 and modify the database schema.
338# Then try to execute a compiled statement to read from the same
339# database via handle 2 (fails to get the lock on sqlite_master). Also
340# try to compile a read of the same database using handle 2 (also fails).
341# Finally, compile a read of the other database using handle 2. This
342# should also fail.
343#
danielk1977ff890792006-01-16 16:24:25 +0000344ifcapable compound {
345 do_test shared-$av.4.4.1.2 {
346 # Sanity check 1: Check that the schema is what we think it is when viewed
347 # via handle 1.
348 execsql {
349 CREATE TABLE test2.ghi(g, h, i);
350 SELECT 'test.db:'||name FROM sqlite_master
351 UNION ALL
352 SELECT 'test2.db:'||name FROM test2.sqlite_master;
353 }
354 } {test.db:abc test.db:def test2.db:ghi}
355 do_test shared-$av.4.4.1.2 {
356 # Sanity check 2: Check that the schema is what we think it is when viewed
357 # via handle 2.
358 execsql {
359 SELECT 'test2.db:'||name FROM sqlite_master
360 UNION ALL
361 SELECT 'test.db:'||name FROM test.sqlite_master;
362 } db2
363 } {test2.db:ghi test.db:abc test.db:def}
364}
danielk1977c87d34d2006-01-06 13:00:28 +0000365
danielk1977a96a7102006-01-16 12:46:41 +0000366do_test shared-$av.4.4.2 {
danielk1977c87d34d2006-01-06 13:00:28 +0000367 set ::DB2 [sqlite3_connection_pointer db2]
368 set sql {SELECT * FROM abc}
369 set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY]
370 execsql {
371 BEGIN;
372 CREATE TABLE jkl(j, k, l);
373 }
374 sqlite3_step $::STMT1
375} {SQLITE_ERROR}
danielk1977a96a7102006-01-16 12:46:41 +0000376do_test shared-$av.4.4.3 {
danielk1977c87d34d2006-01-06 13:00:28 +0000377 sqlite3_finalize $::STMT1
378} {SQLITE_LOCKED}
danielk1977a96a7102006-01-16 12:46:41 +0000379do_test shared-$av.4.4.4 {
danielk1977c87d34d2006-01-06 13:00:28 +0000380 set rc [catch {
381 set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY]
382 } msg]
383 list $rc $msg
384} {1 {(6) database schema is locked: test}}
danielk1977a96a7102006-01-16 12:46:41 +0000385do_test shared-$av.4.4.5 {
danielk1977c87d34d2006-01-06 13:00:28 +0000386 set rc [catch {
387 set ::STMT1 [sqlite3_prepare $::DB2 "SELECT * FROM ghi" -1 DUMMY]
388 } msg]
389 list $rc $msg
390} {1 {(6) database schema is locked: test}}
391
danielk1977aaf22682006-01-06 15:03:48 +0000392
danielk1977de0fe3e2006-01-06 06:33:12 +0000393catch {db2 close}
394catch {db close}
395
danielk1977aaf22682006-01-06 15:03:48 +0000396#--------------------------------------------------------------------------
397# Tests shared-5.*
398#
399foreach db [list test.db test1.db test2.db test3.db] {
400 file delete -force $db ${db}-journal
401}
danielk1977a96a7102006-01-16 12:46:41 +0000402do_test shared-$av.5.1.1 {
danielk1977aaf22682006-01-06 15:03:48 +0000403 sqlite3 db1 test.db
404 sqlite3 db2 test.db
405 execsql {
406 ATTACH 'test1.db' AS test1;
407 ATTACH 'test2.db' AS test2;
408 ATTACH 'test3.db' AS test3;
409 } db1
410 execsql {
411 ATTACH 'test3.db' AS test3;
412 ATTACH 'test2.db' AS test2;
413 ATTACH 'test1.db' AS test1;
414 } db2
415} {}
danielk1977a96a7102006-01-16 12:46:41 +0000416do_test shared-$av.5.1.2 {
danielk1977aaf22682006-01-06 15:03:48 +0000417 execsql {
418 CREATE TABLE test1.t1(a, b);
419 CREATE INDEX test1.i1 ON t1(a, b);
danielk1977aaf22682006-01-06 15:03:48 +0000420 } db1
danielk19773bdca9c2006-01-17 09:35:01 +0000421} {}
422ifcapable view {
423 do_test shared-$av.5.1.3 {
424 execsql {
425 CREATE VIEW test1.v1 AS SELECT * FROM t1;
426 } db1
427 } {}
428}
429ifcapable trigger {
430 do_test shared-$av.5.1.4 {
431 execsql {
432 CREATE TRIGGER test1.trig1 AFTER INSERT ON t1 BEGIN
433 INSERT INTO t1 VALUES(new.a, new.b);
434 END;
435 } db1
436 } {}
437}
438do_test shared-$av.5.1.5 {
danielk1977aaf22682006-01-06 15:03:48 +0000439 execsql {
440 DROP INDEX i1;
danielk19773bdca9c2006-01-17 09:35:01 +0000441 } db2
442} {}
443ifcapable view {
444 do_test shared-$av.5.1.6 {
445 execsql {
446 DROP VIEW v1;
447 } db2
448 } {}
449}
450ifcapable trigger {
451 do_test shared-$av.5.1.7 {
452 execsql {
453 DROP TRIGGER trig1;
454 } db2
455 } {}
456}
457do_test shared-$av.5.1.8 {
458 execsql {
danielk1977aaf22682006-01-06 15:03:48 +0000459 DROP TABLE t1;
460 } db2
461} {}
danielk1977ff890792006-01-16 16:24:25 +0000462ifcapable compound {
danielk19773bdca9c2006-01-17 09:35:01 +0000463 do_test shared-$av.5.1.9 {
danielk1977ff890792006-01-16 16:24:25 +0000464 execsql {
465 SELECT * FROM sqlite_master UNION ALL SELECT * FROM test1.sqlite_master
466 } db1
467 } {}
468}
danielk1977aaf22682006-01-06 15:03:48 +0000469
danielk1977c00da102006-01-07 13:21:04 +0000470#--------------------------------------------------------------------------
471# Tests shared-6.* test that a query obtains all the read-locks it needs
472# before starting execution of the query. This means that there is no chance
473# some rows of data will be returned before a lock fails and SQLITE_LOCK
474# is returned.
475#
danielk1977a96a7102006-01-16 12:46:41 +0000476do_test shared-$av.6.1.1 {
danielk1977c00da102006-01-07 13:21:04 +0000477 execsql {
478 CREATE TABLE t1(a, b);
479 CREATE TABLE t2(a, b);
480 INSERT INTO t1 VALUES(1, 2);
481 INSERT INTO t2 VALUES(3, 4);
482 } db1
danielk1977ff890792006-01-16 16:24:25 +0000483} {}
484ifcapable compound {
485 do_test shared-$av.6.1.2 {
486 execsql {
487 SELECT * FROM t1 UNION ALL SELECT * FROM t2;
488 } db2
489 } {1 2 3 4}
490}
491do_test shared-$av.6.1.3 {
danielk1977c00da102006-01-07 13:21:04 +0000492 # Establish a write lock on table t2 via connection db2. Then make a
493 # UNION all query using connection db1 that first accesses t1, followed
494 # by t2. If the locks are grabbed at the start of the statement (as
495 # they should be), no rows are returned. If (as was previously the case)
496 # they are grabbed as the tables are accessed, the t1 rows will be
497 # returned before the query fails.
498 #
499 execsql {
500 BEGIN;
501 INSERT INTO t2 VALUES(5, 6);
502 } db2
503 set ret [list]
504 catch {
505 db1 eval {SELECT * FROM t1 UNION ALL SELECT * FROM t2} {
506 lappend ret $a $b
507 }
508 }
509 set ret
510} {}
danielk1977ff890792006-01-16 16:24:25 +0000511do_test shared-$av.6.1.4 {
danielk1977c00da102006-01-07 13:21:04 +0000512 execsql {
513 COMMIT;
514 BEGIN;
515 INSERT INTO t1 VALUES(7, 8);
516 } db2
517 set ret [list]
518 catch {
519 db1 eval {
520 SELECT (CASE WHEN a>4 THEN (SELECT a FROM t1) ELSE 0 END) AS d FROM t2;
521 } {
522 lappend ret $d
523 }
524 }
525 set ret
526} {}
527
danielk1977aaf22682006-01-06 15:03:48 +0000528catch {db1 close}
529catch {db2 close}
danielk1977e501b892006-01-09 06:29:47 +0000530foreach f [list test.db test2.db] {
531 file delete -force $f ${f}-journal
532}
533
534#--------------------------------------------------------------------------
535# Tests shared-7.* test auto-vacuum does not invalidate cursors from
536# other shared-cache users when it reorganizes the database on
537# COMMIT.
538#
danielk1977a96a7102006-01-16 12:46:41 +0000539do_test shared-$av.7.1 {
danielk197714db2662006-01-09 16:12:04 +0000540 # This test case sets up a test database in auto-vacuum mode consisting
541 # of two tables, t1 and t2. Both have a single index. Table t1 is
542 # populated first (so consists of pages toward the start of the db file),
543 # t2 second (pages toward the end of the file).
danielk1977e501b892006-01-09 06:29:47 +0000544 sqlite3 db test.db
545 sqlite3 db2 test.db
546 execsql {
danielk1977e501b892006-01-09 06:29:47 +0000547 BEGIN;
548 CREATE TABLE t1(a PRIMARY KEY, b);
549 CREATE TABLE t2(a PRIMARY KEY, b);
550 }
drh7a91dd82006-01-11 01:08:34 +0000551 set ::contents {}
danielk1977e501b892006-01-09 06:29:47 +0000552 for {set i 0} {$i < 100} {incr i} {
553 set a [string repeat "$i " 20]
554 set b [string repeat "$i " 20]
555 db eval {
danielk19773bdca9c2006-01-17 09:35:01 +0000556 INSERT INTO t1 VALUES(:a, :b);
danielk1977e501b892006-01-09 06:29:47 +0000557 }
558 lappend ::contents [list [expr $i+1] $a $b]
559 }
560 execsql {
561 INSERT INTO t2 SELECT * FROM t1;
562 COMMIT;
563 }
danielk1977bab45c62006-01-16 15:14:27 +0000564} {}
danielk1977a96a7102006-01-16 12:46:41 +0000565do_test shared-$av.7.2 {
danielk197714db2662006-01-09 16:12:04 +0000566 # This test case deletes the contents of table t1 (the one at the start of
567 # the file) while many cursors are open on table t2 and it's index. All of
568 # the non-root pages will be moved from the end to the start of the file
569 # when the DELETE is committed - this test verifies that moving the pages
570 # does not disturb the open cursors.
571 #
572
danielk1977e501b892006-01-09 06:29:47 +0000573 proc lockrow {db tbl oids body} {
574 set ret [list]
575 db eval "SELECT oid AS i, a, b FROM $tbl ORDER BY a" {
576 if {$i==[lindex $oids 0]} {
577 set noids [lrange $oids 1 end]
578 if {[llength $noids]==0} {
579 set subret [eval $body]
580 } else {
581 set subret [lockrow $db $tbl $noids $body]
582 }
583 }
584 lappend ret [list $i $a $b]
585 }
586 return [linsert $subret 0 $ret]
587 }
588 proc locktblrows {db tbl body} {
589 set oids [db eval "SELECT oid FROM $tbl"]
590 lockrow $db $tbl $oids $body
591 }
592
593 set scans [locktblrows db t2 {
594 execsql {
595 DELETE FROM t1;
596 } db2
597 }]
598 set error 0
danielk197714db2662006-01-09 16:12:04 +0000599
600 # Test that each SELECT query returned the expected contents of t2.
danielk1977e501b892006-01-09 06:29:47 +0000601 foreach s $scans {
602 if {[lsort -integer -index 0 $s]!=$::contents} {
603 set error 1
604 }
605 }
606 set error
607} {0}
608
609catch {db close}
610catch {db2 close}
drh7a91dd82006-01-11 01:08:34 +0000611unset -nocomplain contents
danielk1977aaf22682006-01-06 15:03:48 +0000612
danielk197714db2662006-01-09 16:12:04 +0000613#--------------------------------------------------------------------------
614# The following tests try to trick the shared-cache code into assuming
615# the wrong encoding for a database.
616#
617file delete -force test.db test.db-journal
danielk19773bdca9c2006-01-17 09:35:01 +0000618ifcapable utf16 {
619 do_test shared-$av.8.1.1 {
620 sqlite3 db test.db
621 execsql {
622 PRAGMA encoding = 'UTF-16';
623 SELECT * FROM sqlite_master;
624 }
625 } {}
626 do_test shared-$av.8.1.2 {
627 string range [execsql {PRAGMA encoding;}] 0 end-2
628 } {UTF-16}
629 do_test shared-$av.8.1.3 {
630 sqlite3 db2 test.db
631 execsql {
632 PRAGMA encoding = 'UTF-8';
633 CREATE TABLE abc(a, b, c);
634 } db2
635 } {}
636 do_test shared-$av.8.1.4 {
637 execsql {
638 SELECT * FROM sqlite_master;
639 }
640 } "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}"
641 do_test shared-$av.8.1.5 {
642 db2 close
643 execsql {
644 PRAGMA encoding;
645 }
646 } {UTF-8}
647 file delete -force test2.db test2.db-journal
648 do_test shared-$av.8.2.1 {
649 execsql {
650 ATTACH 'test2.db' AS aux;
651 SELECT * FROM aux.sqlite_master;
652 }
653 } {}
654 do_test shared-$av.8.2.2 {
655 sqlite3 db2 test2.db
656 execsql {
657 PRAGMA encoding = 'UTF-16';
658 CREATE TABLE def(d, e, f);
659 } db2
660 string range [execsql {PRAGMA encoding;} db2] 0 end-2
661 } {UTF-16}
662 do_test shared-$av.8.2.3 {
663 catchsql {
664 SELECT * FROM aux.sqlite_master;
665 }
666 } {1 {attached databases must use the same text encoding as main database}}
667}
danielk197714db2662006-01-09 16:12:04 +0000668
669catch {db close}
670catch {db2 close}
danielk1977eecfb3e2006-01-10 12:31:39 +0000671file delete -force test.db test2.db
672
danielk1977eecfb3e2006-01-10 12:31:39 +0000673#---------------------------------------------------------------------------
674# The following tests - shared-9.* - test interactions between TEMP triggers
675# and shared-schemas.
676#
677ifcapable trigger&&tempdb {
678
danielk1977a96a7102006-01-16 12:46:41 +0000679do_test shared-$av.9.1 {
danielk1977eecfb3e2006-01-10 12:31:39 +0000680 sqlite3 db test.db
681 sqlite3 db2 test.db
682 execsql {
683 CREATE TABLE abc(a, b, c);
684 CREATE TABLE abc_mirror(a, b, c);
685 CREATE TEMP TRIGGER BEFORE INSERT ON abc BEGIN
686 INSERT INTO abc_mirror(a, b, c) VALUES(new.a, new.b, new.c);
687 END;
688 INSERT INTO abc VALUES(1, 2, 3);
689 SELECT * FROM abc_mirror;
690 }
691} {1 2 3}
danielk1977a96a7102006-01-16 12:46:41 +0000692do_test shared-$av.9.2 {
danielk1977eecfb3e2006-01-10 12:31:39 +0000693 execsql {
694 INSERT INTO abc VALUES(4, 5, 6);
695 SELECT * FROM abc_mirror;
696 } db2
697} {1 2 3}
danielk1977a96a7102006-01-16 12:46:41 +0000698do_test shared-$av.9.3 {
danielk1977eecfb3e2006-01-10 12:31:39 +0000699 db close
700 db2 close
701} {}
702
703} ; # End shared-9.*
danielk197714db2662006-01-09 16:12:04 +0000704
danielk1977b597f742006-01-15 11:39:18 +0000705#---------------------------------------------------------------------------
706# The following tests - shared-10.* - test that the library behaves
707# correctly when a connection to a shared-cache is closed.
708#
danielk1977a96a7102006-01-16 12:46:41 +0000709do_test shared-$av.10.1 {
danielk1977b597f742006-01-15 11:39:18 +0000710 # Create a small sample database with two connections to it (db and db2).
711 file delete -force test.db
712 sqlite3 db test.db
713 sqlite3 db2 test.db
714 execsql {
715 CREATE TABLE ab(a PRIMARY KEY, b);
716 CREATE TABLE de(d PRIMARY KEY, e);
717 INSERT INTO ab VALUES('Chiang Mai', 100000);
718 INSERT INTO ab VALUES('Bangkok', 8000000);
719 INSERT INTO de VALUES('Ubon', 120000);
720 INSERT INTO de VALUES('Khon Kaen', 200000);
721 }
722} {}
danielk1977a96a7102006-01-16 12:46:41 +0000723do_test shared-$av.10.2 {
danielk1977b597f742006-01-15 11:39:18 +0000724 # Open a read-transaction with the first connection, a write-transaction
725 # with the second.
726 execsql {
727 BEGIN;
728 SELECT * FROM ab;
729 }
730 execsql {
731 BEGIN;
732 INSERT INTO de VALUES('Pataya', 30000);
733 } db2
734} {}
danielk1977a96a7102006-01-16 12:46:41 +0000735do_test shared-$av.10.3 {
danielk1977b597f742006-01-15 11:39:18 +0000736 # An external connection should be able to read the database, but not
737 # prepare a write operation.
738 sqlite3 db3 ./test.db
739 execsql {
740 SELECT * FROM ab;
741 } db3
742 catchsql {
743 BEGIN;
744 INSERT INTO de VALUES('Pataya', 30000);
745 } db3
746} {1 {database is locked}}
danielk1977a96a7102006-01-16 12:46:41 +0000747do_test shared-$av.10.4 {
danielk1977b597f742006-01-15 11:39:18 +0000748 # Close the connection with the write-transaction open
749 db2 close
750} {}
danielk1977a96a7102006-01-16 12:46:41 +0000751do_test shared-$av.10.5 {
danielk1977b597f742006-01-15 11:39:18 +0000752 # Test that the db2 transaction has been automatically rolled back.
753 # If it has not the ('Pataya', 30000) entry will still be in the table.
754 execsql {
755 SELECT * FROM de;
756 }
757} {Ubon 120000 {Khon Kaen} 200000}
danielk1977a96a7102006-01-16 12:46:41 +0000758do_test shared-$av.10.5 {
danielk1977b597f742006-01-15 11:39:18 +0000759 # Closing db2 should have dropped the shared-cache back to a read-lock.
760 # So db3 should be able to prepare a write...
761 catchsql {INSERT INTO de VALUES('Pataya', 30000);} db3
762} {0 {}}
danielk1977a96a7102006-01-16 12:46:41 +0000763do_test shared-$av.10.6 {
danielk1977b597f742006-01-15 11:39:18 +0000764 # ... but not commit it.
765 catchsql {COMMIT} db3
766} {1 {database is locked}}
danielk1977a96a7102006-01-16 12:46:41 +0000767do_test shared-$av.10.7 {
danielk1977b597f742006-01-15 11:39:18 +0000768 # Commit the (read-only) db transaction. Check via db3 to make sure the
769 # contents of table "de" are still as they should be.
770 execsql {
771 COMMIT;
772 }
773 execsql {
774 SELECT * FROM de;
775 } db3
776} {Ubon 120000 {Khon Kaen} 200000 Pataya 30000}
danielk1977a96a7102006-01-16 12:46:41 +0000777do_test shared-$av.10.9 {
danielk1977b597f742006-01-15 11:39:18 +0000778 # Commit the external transaction.
779 catchsql {COMMIT} db3
780} {0 {}}
danielk1977a96a7102006-01-16 12:46:41 +0000781integrity_check shared-$av.10.10
782do_test shared-$av.10.11 {
danielk1977b597f742006-01-15 11:39:18 +0000783 db close
784 db3 close
785} {}
786
danielk1977a96a7102006-01-16 12:46:41 +0000787}
788
danielk1977aef0bf62005-12-30 16:28:01 +0000789sqlite3_enable_shared_cache $::enable_shared_cache
danielk1977a96a7102006-01-16 12:46:41 +0000790finish_test