xref: /sqlite-3.40.0/test/shared.test (revision eecfb3ee)
1aef0bf64Sdanielk1977# 2005 December 30
2aef0bf64Sdanielk1977#
3aef0bf64Sdanielk1977# The author disclaims copyright to this source code.  In place of
4aef0bf64Sdanielk1977# a legal notice, here is a blessing:
5aef0bf64Sdanielk1977#
6aef0bf64Sdanielk1977#    May you do good and not evil.
7aef0bf64Sdanielk1977#    May you find forgiveness for yourself and forgive others.
8aef0bf64Sdanielk1977#    May you share freely, never taking more than you give.
9aef0bf64Sdanielk1977#
10aef0bf64Sdanielk1977#***********************************************************************
11aef0bf64Sdanielk1977#
12*eecfb3eeSdanielk1977# $Id: shared.test,v 1.9 2006/01/10 12:31:41 danielk1977 Exp $
13aef0bf64Sdanielk1977
14aef0bf64Sdanielk1977set testdir [file dirname $argv0]
15aef0bf64Sdanielk1977source $testdir/tester.tcl
16aef0bf64Sdanielk1977db close
17aef0bf64Sdanielk1977
18aef0bf64Sdanielk1977ifcapable !shared_cache {
19aef0bf64Sdanielk1977  finish_test
20aef0bf64Sdanielk1977  return
21aef0bf64Sdanielk1977}
22da184236Sdanielk1977set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
23aef0bf64Sdanielk1977
24aef0bf64Sdanielk1977# Test organization:
25aef0bf64Sdanielk1977#
26aef0bf64Sdanielk1977# shared-1.*: Simple test to verify basic sanity of table level locking when
27aef0bf64Sdanielk1977#             two connections share a pager cache.
28aef0bf64Sdanielk1977# shared-2.*: Test that a read transaction can co-exist with a
29aef0bf64Sdanielk1977#             write-transaction, including a simple test to ensure the
30aef0bf64Sdanielk1977#             external locking protocol is still working.
31da184236Sdanielk1977# shared-3.*: Simple test of read-uncommitted mode.
32de0fe3e4Sdanielk1977# shared-4.*: Check that the schema is locked and unlocked correctly.
33aaf22685Sdanielk1977# shared-5.*: Test that creating/dropping schema items works when databases
34aaf22685Sdanielk1977#             are attached in different orders to different handles.
35c00da105Sdanielk1977# shared-6.*: Locking, UNION ALL queries and sub-queries.
3614db2665Sdanielk1977# shared-7.*: Autovacuum and shared-cache.
37de0fe3e4Sdanielk1977#
38aef0bf64Sdanielk1977
39aef0bf64Sdanielk1977do_test shared-1.1 {
40aef0bf64Sdanielk1977  # Open a second database on the file test.db. It should use the same pager
41aef0bf64Sdanielk1977  # cache and schema as the original connection. Verify that only 1 file is
42aef0bf64Sdanielk1977  # opened.
43aef0bf64Sdanielk1977  sqlite3 db2 test.db
44aef0bf64Sdanielk1977  sqlite3 db  test.db
45aef0bf64Sdanielk1977  set ::sqlite_open_file_count
46aef0bf64Sdanielk1977} {1}
47aef0bf64Sdanielk1977do_test shared-1.2 {
48aef0bf64Sdanielk1977  # Add a table and a single row of data via the first connection.
49aef0bf64Sdanielk1977  # Ensure that the second connection can see them.
50aef0bf64Sdanielk1977  execsql {
51aef0bf64Sdanielk1977    CREATE TABLE abc(a, b, c);
52aef0bf64Sdanielk1977    INSERT INTO abc VALUES(1, 2, 3);
53aef0bf64Sdanielk1977  } db
54aef0bf64Sdanielk1977  execsql {
55aef0bf64Sdanielk1977    SELECT * FROM abc;
56aef0bf64Sdanielk1977  } db2
57aef0bf64Sdanielk1977} {1 2 3}
58aef0bf64Sdanielk1977do_test shared-1.3 {
59aef0bf64Sdanielk1977  # Have the first connection begin a transaction and obtain a read-lock
60aef0bf64Sdanielk1977  # on table abc. This should not prevent the second connection from
61aef0bf64Sdanielk1977  # querying abc.
62aef0bf64Sdanielk1977  execsql {
63aef0bf64Sdanielk1977    BEGIN;
64aef0bf64Sdanielk1977    SELECT * FROM abc;
65aef0bf64Sdanielk1977  }
66aef0bf64Sdanielk1977  execsql {
67aef0bf64Sdanielk1977    SELECT * FROM abc;
68aef0bf64Sdanielk1977  } db2
69aef0bf64Sdanielk1977} {1 2 3}
70aef0bf64Sdanielk1977do_test shared-1.4 {
71aef0bf64Sdanielk1977  # Try to insert a row into abc via connection 2. This should fail because
72aef0bf64Sdanielk1977  # of the read-lock connection 1 is holding on table abc (obtained in the
73aef0bf64Sdanielk1977  # previous test case).
74aef0bf64Sdanielk1977  catchsql {
75aef0bf64Sdanielk1977    INSERT INTO abc VALUES(4, 5, 6);
76aef0bf64Sdanielk1977  } db2
77c00da105Sdanielk1977} {1 {database table is locked: abc}}
78aef0bf64Sdanielk1977do_test shared-1.5 {
79da184236Sdanielk1977  # Using connection 2 (the one without the open transaction), try to create
80da184236Sdanielk1977  # a new table. This should fail because of the open read transaction
81da184236Sdanielk1977  # held by connection 1.
82da184236Sdanielk1977  catchsql {
83da184236Sdanielk1977    CREATE TABLE def(d, e, f);
84da184236Sdanielk1977  } db2
85c00da105Sdanielk1977} {1 {database table is locked: sqlite_master}}
86da184236Sdanielk1977do_test shared-1.6 {
87da184236Sdanielk1977  # Upgrade connection 1's transaction to a write transaction. Create
88da184236Sdanielk1977  # a new table - def - and insert a row into it. Because the connection 1
89da184236Sdanielk1977  # transaction modifies the schema, it should not be possible for
90da184236Sdanielk1977  # connection 2 to access the database at all until the connection 1
91da184236Sdanielk1977  # has finished the transaction.
92aef0bf64Sdanielk1977  execsql {
93aef0bf64Sdanielk1977    CREATE TABLE def(d, e, f);
94aef0bf64Sdanielk1977    INSERT INTO def VALUES('IV', 'V', 'VI');
95aef0bf64Sdanielk1977  }
96aef0bf64Sdanielk1977} {}
97aef0bf64Sdanielk1977do_test shared-1.7 {
98aef0bf64Sdanielk1977  # Read from the sqlite_master table with connection 1 (inside the
99da184236Sdanielk1977  # transaction). Then test that we can not do this with connection 2. This
100da184236Sdanielk1977  # is because of the schema-modified lock established by connection 1
101da184236Sdanielk1977  # in the previous test case.
102aef0bf64Sdanielk1977  execsql {
103aef0bf64Sdanielk1977    SELECT * FROM sqlite_master;
104aef0bf64Sdanielk1977  }
105aef0bf64Sdanielk1977  catchsql {
106aef0bf64Sdanielk1977    SELECT * FROM sqlite_master;
107aef0bf64Sdanielk1977  } db2
108c87d34d0Sdanielk1977} {1 {database schema is locked: main}}
109da184236Sdanielk1977do_test shared-1.8 {
110aef0bf64Sdanielk1977  # Commit the connection 1 transaction.
111aef0bf64Sdanielk1977  execsql {
112aef0bf64Sdanielk1977    COMMIT;
113aef0bf64Sdanielk1977  }
114aef0bf64Sdanielk1977} {}
115aef0bf64Sdanielk1977
116aef0bf64Sdanielk1977do_test shared-2.1 {
117aef0bf64Sdanielk1977  # Open connection db3 to the database. Use a different path to the same
118aef0bf64Sdanielk1977  # file so that db3 does *not* share the same pager cache as db and db2
119aef0bf64Sdanielk1977  # (there should be two open file handles).
120aef0bf64Sdanielk1977  sqlite3 db3 ./test.db
121aef0bf64Sdanielk1977  set ::sqlite_open_file_count
122aef0bf64Sdanielk1977} {2}
123aef0bf64Sdanielk1977do_test shared-2.2 {
124aef0bf64Sdanielk1977  # Start read transactions on db and db2 (the shared pager cache). Ensure
125aef0bf64Sdanielk1977  # db3 cannot write to the database.
126aef0bf64Sdanielk1977  execsql {
127aef0bf64Sdanielk1977    BEGIN;
128aef0bf64Sdanielk1977    SELECT * FROM abc;
129aef0bf64Sdanielk1977  }
130aef0bf64Sdanielk1977  execsql {
131aef0bf64Sdanielk1977    BEGIN;
132aef0bf64Sdanielk1977    SELECT * FROM abc;
133aef0bf64Sdanielk1977  } db2
134aef0bf64Sdanielk1977  catchsql {
135aef0bf64Sdanielk1977    INSERT INTO abc VALUES(1, 2, 3);
136aef0bf64Sdanielk1977  } db2
137c00da105Sdanielk1977} {1 {database table is locked: abc}}
138aef0bf64Sdanielk1977do_test shared-2.3 {
139aef0bf64Sdanielk1977  # Turn db's transaction into a write-transaction. db3 should still be
140aef0bf64Sdanielk1977  # able to read from table def (but will not see the new row). Connection
141aef0bf64Sdanielk1977  # db2 should not be able to read def (because of the write-lock).
142aef0bf64Sdanielk1977
143aef0bf64Sdanielk1977# Todo: The failed "INSERT INTO abc ..." statement in the above test
144aef0bf64Sdanielk1977# has started a write-transaction on db2 (should this be so?). This
145aef0bf64Sdanielk1977# would prevent connection db from starting a write-transaction. So roll the
146aef0bf64Sdanielk1977# db2 transaction back and replace it with a new read transaction.
147aef0bf64Sdanielk1977  execsql {
148aef0bf64Sdanielk1977    ROLLBACK;
149aef0bf64Sdanielk1977    BEGIN;
150aef0bf64Sdanielk1977    SELECT * FROM abc;
151aef0bf64Sdanielk1977  } db2
152aef0bf64Sdanielk1977
153aef0bf64Sdanielk1977  execsql {
154aef0bf64Sdanielk1977    INSERT INTO def VALUES('VII', 'VIII', 'IX');
155aef0bf64Sdanielk1977  }
156aef0bf64Sdanielk1977  concat [
157aef0bf64Sdanielk1977    catchsql { SELECT * FROM def; } db3
158aef0bf64Sdanielk1977  ] [
159aef0bf64Sdanielk1977    catchsql { SELECT * FROM def; } db2
160aef0bf64Sdanielk1977  ]
161c00da105Sdanielk1977} {0 {IV V VI} 1 {database table is locked: def}}
162aef0bf64Sdanielk1977do_test shared-2.4 {
163aef0bf64Sdanielk1977  # Commit the open transaction on db. db2 still holds a read-transaction.
164aef0bf64Sdanielk1977  # This should prevent db3 from writing to the database, but not from
165aef0bf64Sdanielk1977  # reading.
166aef0bf64Sdanielk1977  execsql {
167aef0bf64Sdanielk1977    COMMIT;
168aef0bf64Sdanielk1977  }
169aef0bf64Sdanielk1977  concat [
170aef0bf64Sdanielk1977    catchsql { SELECT * FROM def; } db3
171aef0bf64Sdanielk1977  ] [
172aef0bf64Sdanielk1977    catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3
173aef0bf64Sdanielk1977  ]
174da184236Sdanielk1977} {0 {IV V VI VII VIII IX} 1 {database is locked}}
175aef0bf64Sdanielk1977
176da184236Sdanielk1977catchsql COMMIT db2
177da184236Sdanielk1977
178da184236Sdanielk1977do_test shared-3.1.1 {
179da184236Sdanielk1977  # This test case starts a linear scan of table 'seq' using a
180da184236Sdanielk1977  # read-uncommitted connection. In the middle of the scan, rows are added
181da184236Sdanielk1977  # to the end of the seq table (ahead of the current cursor position).
182da184236Sdanielk1977  # The uncommitted rows should be included in the results of the scan.
183da184236Sdanielk1977  execsql "
184da184236Sdanielk1977    CREATE TABLE seq(i, x);
185da184236Sdanielk1977    INSERT INTO seq VALUES(1, '[string repeat X 500]');
186da184236Sdanielk1977    INSERT INTO seq VALUES(2, '[string repeat X 500]');
187da184236Sdanielk1977  "
188da184236Sdanielk1977  execsql {SELECT * FROM sqlite_master} db2
189da184236Sdanielk1977  execsql {PRAGMA read_uncommitted = 1} db2
190da184236Sdanielk1977
191da184236Sdanielk1977  set ret [list]
192da184236Sdanielk1977  db2 eval {SELECT i FROM seq} {
193da184236Sdanielk1977    if {$i < 4} {
194da184236Sdanielk1977      execsql {
195da184236Sdanielk1977        INSERT INTO seq SELECT i + (SELECT max(i) FROM seq), x FROM seq;
196da184236Sdanielk1977      }
197da184236Sdanielk1977    }
198da184236Sdanielk1977    lappend ret $i
199da184236Sdanielk1977  }
200da184236Sdanielk1977  set ret
201da184236Sdanielk1977} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
202da184236Sdanielk1977do_test shared-3.1.2 {
203da184236Sdanielk1977  # Another linear scan through table seq using a read-uncommitted connection.
204da184236Sdanielk1977  # This time, delete each row as it is read. Should not affect the results of
205da184236Sdanielk1977  # the scan, but the table should be empty after the scan is concluded
206da184236Sdanielk1977  # (test 3.1.3 verifies this).
207da184236Sdanielk1977  set ret [list]
208da184236Sdanielk1977  db2 eval {SELECT i FROM seq} {
209da184236Sdanielk1977    db eval {DELETE FROM seq WHERE i = $i}
210da184236Sdanielk1977    lappend ret $i
211da184236Sdanielk1977  }
212da184236Sdanielk1977  set ret
213da184236Sdanielk1977} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
214da184236Sdanielk1977do_test shared-3.1.3 {
215da184236Sdanielk1977  execsql {
216da184236Sdanielk1977    SELECT * FROM seq;
217da184236Sdanielk1977  }
218da184236Sdanielk1977} {}
219aef0bf64Sdanielk1977
220aef0bf64Sdanielk1977catch {db close}
221aef0bf64Sdanielk1977catch {db2 close}
222aef0bf64Sdanielk1977catch {db3 close}
223aef0bf64Sdanielk1977
224de0fe3e4Sdanielk1977#--------------------------------------------------------------------------
225de0fe3e4Sdanielk1977# Tests shared-4.* test that the schema locking rules are applied
226de0fe3e4Sdanielk1977# correctly. i.e.:
227de0fe3e4Sdanielk1977#
228de0fe3e4Sdanielk1977# 1. All transactions require a read-lock on the schemas of databases they
229de0fe3e4Sdanielk1977#    access.
230de0fe3e4Sdanielk1977# 2. Transactions that modify a database schema require a write-lock on that
231de0fe3e4Sdanielk1977#    schema.
232de0fe3e4Sdanielk1977# 3. It is not possible to compile a statement while another handle has a
233de0fe3e4Sdanielk1977#    write-lock on the schema.
234de0fe3e4Sdanielk1977#
235de0fe3e4Sdanielk1977
236de0fe3e4Sdanielk1977# Open two database handles db and db2. Each has a single attach database
237de0fe3e4Sdanielk1977# (as well as main):
238de0fe3e4Sdanielk1977#
239de0fe3e4Sdanielk1977#     db.main   ->   ./test.db
240de0fe3e4Sdanielk1977#     db.test2  ->   ./test2.db
241de0fe3e4Sdanielk1977#     db2.main  ->   ./test2.db
242de0fe3e4Sdanielk1977#     db2.test  ->   ./test.db
243de0fe3e4Sdanielk1977#
244de0fe3e4Sdanielk1977file delete -force test.db
245de0fe3e4Sdanielk1977file delete -force test2.db
246de0fe3e4Sdanielk1977file delete -force test2.db-journal
247de0fe3e4Sdanielk1977sqlite3 db  test.db
248de0fe3e4Sdanielk1977sqlite3 db2 test2.db
249de0fe3e4Sdanielk1977do_test shared-4.1.1 {
250de0fe3e4Sdanielk1977  set sqlite_open_file_count
251de0fe3e4Sdanielk1977} {2}
252de0fe3e4Sdanielk1977do_test shared-4.1.2 {
253de0fe3e4Sdanielk1977  execsql {ATTACH 'test2.db' AS test2}
254de0fe3e4Sdanielk1977  set sqlite_open_file_count
255de0fe3e4Sdanielk1977} {2}
256de0fe3e4Sdanielk1977do_test shared-4.1.3 {
257de0fe3e4Sdanielk1977  execsql {ATTACH 'test.db' AS test} db2
258de0fe3e4Sdanielk1977  set sqlite_open_file_count
259de0fe3e4Sdanielk1977} {2}
260de0fe3e4Sdanielk1977
261c87d34d0Sdanielk1977# Sanity check: Create a table in ./test.db via handle db, and test that handle
262c87d34d0Sdanielk1977# db2 can "see" the new table immediately. A handle using a seperate pager
263c87d34d0Sdanielk1977# cache would have to reload the database schema before this were possible.
264c87d34d0Sdanielk1977#
265de0fe3e4Sdanielk1977do_test shared-4.2.1 {
266de0fe3e4Sdanielk1977  execsql {
267de0fe3e4Sdanielk1977    CREATE TABLE abc(a, b, c);
268c87d34d0Sdanielk1977    CREATE TABLE def(d, e, f);
269de0fe3e4Sdanielk1977    INSERT INTO abc VALUES('i', 'ii', 'iii');
270c87d34d0Sdanielk1977    INSERT INTO def VALUES('I', 'II', 'III');
271de0fe3e4Sdanielk1977  }
272de0fe3e4Sdanielk1977} {}
273de0fe3e4Sdanielk1977do_test shared-4.2.2 {
274de0fe3e4Sdanielk1977  execsql {
275de0fe3e4Sdanielk1977    SELECT * FROM test.abc;
276de0fe3e4Sdanielk1977  } db2
277de0fe3e4Sdanielk1977} {i ii iii}
278de0fe3e4Sdanielk1977
279c87d34d0Sdanielk1977# Open a read-transaction and read from table abc via handle 2. Check that
280c87d34d0Sdanielk1977# handle 1 can read table abc. Check that handle 1 cannot modify table abc
281c87d34d0Sdanielk1977# or the database schema. Then check that handle 1 can modify table def.
282c87d34d0Sdanielk1977#
283c87d34d0Sdanielk1977do_test shared-4.3.1 {
284c87d34d0Sdanielk1977  execsql {
285c87d34d0Sdanielk1977    BEGIN;
286c87d34d0Sdanielk1977    SELECT * FROM test.abc;
287c87d34d0Sdanielk1977  } db2
288c87d34d0Sdanielk1977} {i ii iii}
289c87d34d0Sdanielk1977do_test shared-4.3.2 {
290c87d34d0Sdanielk1977  catchsql {
291c87d34d0Sdanielk1977    INSERT INTO abc VALUES('iv', 'v', 'vi');
292c87d34d0Sdanielk1977  }
293c00da105Sdanielk1977} {1 {database table is locked: abc}}
294c87d34d0Sdanielk1977do_test shared-4.3.3 {
295c87d34d0Sdanielk1977  catchsql {
296c87d34d0Sdanielk1977    CREATE TABLE ghi(g, h, i);
297c87d34d0Sdanielk1977  }
298c00da105Sdanielk1977} {1 {database table is locked: sqlite_master}}
299c87d34d0Sdanielk1977do_test shared-4.3.3 {
300c87d34d0Sdanielk1977  catchsql {
301c87d34d0Sdanielk1977    INSERT INTO def VALUES('IV', 'V', 'VI');
302c87d34d0Sdanielk1977  }
303c87d34d0Sdanielk1977} {0 {}}
304c87d34d0Sdanielk1977do_test shared-4.3.4 {
305c87d34d0Sdanielk1977  # Cleanup: commit the transaction opened by db2.
306c87d34d0Sdanielk1977  execsql {
307c87d34d0Sdanielk1977    COMMIT
308c87d34d0Sdanielk1977  } db2
309c87d34d0Sdanielk1977} {}
310c87d34d0Sdanielk1977
311c87d34d0Sdanielk1977# Open a write-transaction using handle 1 and modify the database schema.
312c87d34d0Sdanielk1977# Then try to execute a compiled statement to read from the same
313c87d34d0Sdanielk1977# database via handle 2 (fails to get the lock on sqlite_master). Also
314c87d34d0Sdanielk1977# try to compile a read of the same database using handle 2 (also fails).
315c87d34d0Sdanielk1977# Finally, compile a read of the other database using handle 2. This
316c87d34d0Sdanielk1977# should also fail.
317c87d34d0Sdanielk1977#
318c87d34d0Sdanielk1977do_test shared-4.4.1.2 {
319c87d34d0Sdanielk1977  # Sanity check 1: Check that the schema is what we think it is when viewed
320c87d34d0Sdanielk1977  # via handle 1.
321c87d34d0Sdanielk1977  execsql {
322c87d34d0Sdanielk1977    CREATE TABLE test2.ghi(g, h, i);
323c87d34d0Sdanielk1977    SELECT 'test.db:'||name FROM sqlite_master
324c87d34d0Sdanielk1977    UNION ALL
325c87d34d0Sdanielk1977    SELECT 'test2.db:'||name FROM test2.sqlite_master;
326c87d34d0Sdanielk1977  }
327c87d34d0Sdanielk1977} {test.db:abc test.db:def test2.db:ghi}
328c87d34d0Sdanielk1977do_test shared-4.4.1.2 {
329c87d34d0Sdanielk1977  # Sanity check 2: Check that the schema is what we think it is when viewed
330c87d34d0Sdanielk1977  # via handle 2.
331c87d34d0Sdanielk1977  execsql {
332c87d34d0Sdanielk1977    SELECT 'test2.db:'||name FROM sqlite_master
333c87d34d0Sdanielk1977    UNION ALL
334c87d34d0Sdanielk1977    SELECT 'test.db:'||name FROM test.sqlite_master;
335c87d34d0Sdanielk1977  } db2
336c87d34d0Sdanielk1977} {test2.db:ghi test.db:abc test.db:def}
337c87d34d0Sdanielk1977
338c87d34d0Sdanielk1977do_test shared-4.4.2 {
339c87d34d0Sdanielk1977  set ::DB2 [sqlite3_connection_pointer db2]
340c87d34d0Sdanielk1977  set sql {SELECT * FROM abc}
341c87d34d0Sdanielk1977  set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY]
342c87d34d0Sdanielk1977  execsql {
343c87d34d0Sdanielk1977    BEGIN;
344c87d34d0Sdanielk1977    CREATE TABLE jkl(j, k, l);
345c87d34d0Sdanielk1977  }
346c87d34d0Sdanielk1977  sqlite3_step $::STMT1
347c87d34d0Sdanielk1977} {SQLITE_ERROR}
348c87d34d0Sdanielk1977do_test shared-4.4.3 {
349c87d34d0Sdanielk1977  sqlite3_finalize $::STMT1
350c87d34d0Sdanielk1977} {SQLITE_LOCKED}
351c87d34d0Sdanielk1977do_test shared-4.4.4 {
352c87d34d0Sdanielk1977  set rc [catch {
353c87d34d0Sdanielk1977    set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY]
354c87d34d0Sdanielk1977  } msg]
355c87d34d0Sdanielk1977  list $rc $msg
356c87d34d0Sdanielk1977} {1 {(6) database schema is locked: test}}
357c87d34d0Sdanielk1977do_test shared-4.4.5 {
358c87d34d0Sdanielk1977  set rc [catch {
359c87d34d0Sdanielk1977    set ::STMT1 [sqlite3_prepare $::DB2 "SELECT * FROM ghi" -1 DUMMY]
360c87d34d0Sdanielk1977  } msg]
361c87d34d0Sdanielk1977  list $rc $msg
362c87d34d0Sdanielk1977} {1 {(6) database schema is locked: test}}
363c87d34d0Sdanielk1977
364aaf22685Sdanielk1977
365de0fe3e4Sdanielk1977catch {db2 close}
366de0fe3e4Sdanielk1977catch {db close}
367de0fe3e4Sdanielk1977
368aaf22685Sdanielk1977#--------------------------------------------------------------------------
369aaf22685Sdanielk1977# Tests shared-5.*
370aaf22685Sdanielk1977#
371aaf22685Sdanielk1977foreach db [list test.db test1.db test2.db test3.db] {
372aaf22685Sdanielk1977  file delete -force $db ${db}-journal
373aaf22685Sdanielk1977}
374aaf22685Sdanielk1977do_test shared-5.1.1 {
375aaf22685Sdanielk1977  sqlite3 db1 test.db
376aaf22685Sdanielk1977  sqlite3 db2 test.db
377aaf22685Sdanielk1977  execsql {
378aaf22685Sdanielk1977    ATTACH 'test1.db' AS test1;
379aaf22685Sdanielk1977    ATTACH 'test2.db' AS test2;
380aaf22685Sdanielk1977    ATTACH 'test3.db' AS test3;
381aaf22685Sdanielk1977  } db1
382aaf22685Sdanielk1977  execsql {
383aaf22685Sdanielk1977    ATTACH 'test3.db' AS test3;
384aaf22685Sdanielk1977    ATTACH 'test2.db' AS test2;
385aaf22685Sdanielk1977    ATTACH 'test1.db' AS test1;
386aaf22685Sdanielk1977  } db2
387aaf22685Sdanielk1977} {}
388aaf22685Sdanielk1977do_test shared-5.1.2 {
389aaf22685Sdanielk1977  execsql {
390aaf22685Sdanielk1977    CREATE TABLE test1.t1(a, b);
391aaf22685Sdanielk1977    CREATE INDEX test1.i1 ON t1(a, b);
392aaf22685Sdanielk1977    CREATE VIEW test1.v1 AS SELECT * FROM t1;
393aaf22685Sdanielk1977    CREATE TRIGGER test1.trig1 AFTER INSERT ON t1 BEGIN
394aaf22685Sdanielk1977      INSERT INTO t1 VALUES(new.a, new.b);
395aaf22685Sdanielk1977    END;
396aaf22685Sdanielk1977  } db1
397aaf22685Sdanielk1977  execsql {
398aaf22685Sdanielk1977    DROP INDEX i1;
399aaf22685Sdanielk1977    DROP VIEW v1;
400aaf22685Sdanielk1977    DROP TRIGGER trig1;
401aaf22685Sdanielk1977    DROP TABLE t1;
402aaf22685Sdanielk1977  } db2
403aaf22685Sdanielk1977} {}
404aaf22685Sdanielk1977do_test shared-5.1.2 {
405aaf22685Sdanielk1977  execsql {
406aaf22685Sdanielk1977    SELECT * FROM sqlite_master UNION ALL SELECT * FROM test1.sqlite_master
407aaf22685Sdanielk1977  } db1
408aaf22685Sdanielk1977} {}
409aaf22685Sdanielk1977
410c00da105Sdanielk1977#--------------------------------------------------------------------------
411c00da105Sdanielk1977# Tests shared-6.* test that a query obtains all the read-locks it needs
412c00da105Sdanielk1977# before starting execution of the query. This means that there is no chance
413c00da105Sdanielk1977# some rows of data will be returned before a lock fails and SQLITE_LOCK
414c00da105Sdanielk1977# is returned.
415c00da105Sdanielk1977#
416c00da105Sdanielk1977do_test shared-6.1.1 {
417c00da105Sdanielk1977  execsql {
418c00da105Sdanielk1977    CREATE TABLE t1(a, b);
419c00da105Sdanielk1977    CREATE TABLE t2(a, b);
420c00da105Sdanielk1977    INSERT INTO t1 VALUES(1, 2);
421c00da105Sdanielk1977    INSERT INTO t2 VALUES(3, 4);
422c00da105Sdanielk1977  } db1
423c00da105Sdanielk1977  execsql {
424c00da105Sdanielk1977    SELECT * FROM t1 UNION ALL SELECT * FROM t2;
425c00da105Sdanielk1977  } db2
426c00da105Sdanielk1977} {1 2 3 4}
427c00da105Sdanielk1977do_test shared-6.1.2 {
428c00da105Sdanielk1977  # Establish a write lock on table t2 via connection db2. Then make a
429c00da105Sdanielk1977  # UNION all query using connection db1 that first accesses t1, followed
430c00da105Sdanielk1977  # by t2. If the locks are grabbed at the start of the statement (as
431c00da105Sdanielk1977  # they should be), no rows are returned. If (as was previously the case)
432c00da105Sdanielk1977  # they are grabbed as the tables are accessed, the t1 rows will be
433c00da105Sdanielk1977  # returned before the query fails.
434c00da105Sdanielk1977  #
435c00da105Sdanielk1977  execsql {
436c00da105Sdanielk1977    BEGIN;
437c00da105Sdanielk1977    INSERT INTO t2 VALUES(5, 6);
438c00da105Sdanielk1977  } db2
439c00da105Sdanielk1977  set ret [list]
440c00da105Sdanielk1977  catch {
441c00da105Sdanielk1977    db1 eval {SELECT * FROM t1 UNION ALL SELECT * FROM t2} {
442c00da105Sdanielk1977      lappend ret $a $b
443c00da105Sdanielk1977    }
444c00da105Sdanielk1977  }
445c00da105Sdanielk1977  set ret
446c00da105Sdanielk1977} {}
447c00da105Sdanielk1977do_test shared-6.1.3 {
448c00da105Sdanielk1977  execsql {
449c00da105Sdanielk1977    COMMIT;
450c00da105Sdanielk1977    BEGIN;
451c00da105Sdanielk1977    INSERT INTO t1 VALUES(7, 8);
452c00da105Sdanielk1977  } db2
453c00da105Sdanielk1977  set ret [list]
454c00da105Sdanielk1977  catch {
455c00da105Sdanielk1977    db1 eval {
456c00da105Sdanielk1977      SELECT (CASE WHEN a>4 THEN (SELECT a FROM t1) ELSE 0 END) AS d FROM t2;
457c00da105Sdanielk1977    } {
458c00da105Sdanielk1977      lappend ret $d
459c00da105Sdanielk1977    }
460c00da105Sdanielk1977  }
461c00da105Sdanielk1977  set ret
462c00da105Sdanielk1977} {}
463c00da105Sdanielk1977
464aaf22685Sdanielk1977catch {db1 close}
465aaf22685Sdanielk1977catch {db2 close}
466e501b89aSdanielk1977foreach f [list test.db test2.db] {
467e501b89aSdanielk1977  file delete -force $f ${f}-journal
468e501b89aSdanielk1977}
469e501b89aSdanielk1977
470e501b89aSdanielk1977#--------------------------------------------------------------------------
471e501b89aSdanielk1977# Tests shared-7.* test auto-vacuum does not invalidate cursors from
472e501b89aSdanielk1977# other shared-cache users when it reorganizes the database on
473e501b89aSdanielk1977# COMMIT.
474e501b89aSdanielk1977#
475e501b89aSdanielk1977do_test shared-7.1 {
47614db2665Sdanielk1977  # This test case sets up a test database in auto-vacuum mode consisting
47714db2665Sdanielk1977  # of two tables, t1 and t2. Both have a single index. Table t1 is
47814db2665Sdanielk1977  # populated first (so consists of pages toward the start of the db file),
47914db2665Sdanielk1977  # t2 second (pages toward the end of the file).
480e501b89aSdanielk1977  sqlite3 db test.db
481e501b89aSdanielk1977  sqlite3 db2 test.db
482e501b89aSdanielk1977  execsql {
483e501b89aSdanielk1977    PRAGMA auto_vacuum = 1;
484e501b89aSdanielk1977    BEGIN;
485e501b89aSdanielk1977    CREATE TABLE t1(a PRIMARY KEY, b);
486e501b89aSdanielk1977    CREATE TABLE t2(a PRIMARY KEY, b);
487e501b89aSdanielk1977  }
488e501b89aSdanielk1977  for {set i 0} {$i < 100} {incr i} {
489e501b89aSdanielk1977    set a [string repeat "$i " 20]
490e501b89aSdanielk1977    set b [string repeat "$i " 20]
491e501b89aSdanielk1977    db eval {
492e501b89aSdanielk1977      INSERT INTO t1 VALUES($a, $b);
493e501b89aSdanielk1977    }
494e501b89aSdanielk1977    lappend ::contents [list [expr $i+1] $a $b]
495e501b89aSdanielk1977  }
496e501b89aSdanielk1977  execsql {
497e501b89aSdanielk1977    INSERT INTO t2 SELECT * FROM t1;
498e501b89aSdanielk1977    COMMIT;
499e501b89aSdanielk1977  }
500e501b89aSdanielk1977  execsql {
501e501b89aSdanielk1977    PRAGMA auto_vacuum;
502e501b89aSdanielk1977  }
503e501b89aSdanielk1977} {1}
504e501b89aSdanielk1977do_test shared-7.2 {
50514db2665Sdanielk1977  # This test case deletes the contents of table t1 (the one at the start of
50614db2665Sdanielk1977  # the file) while many cursors are open on table t2 and it's index. All of
50714db2665Sdanielk1977  # the non-root pages will be moved from the end to the start of the file
50814db2665Sdanielk1977  # when the DELETE is committed - this test verifies that moving the pages
50914db2665Sdanielk1977  # does not disturb the open cursors.
51014db2665Sdanielk1977  #
51114db2665Sdanielk1977
512e501b89aSdanielk1977  proc lockrow {db tbl oids body} {
513e501b89aSdanielk1977    set ret [list]
514e501b89aSdanielk1977    db eval "SELECT oid AS i, a, b FROM $tbl ORDER BY a" {
515e501b89aSdanielk1977      if {$i==[lindex $oids 0]} {
516e501b89aSdanielk1977        set noids [lrange $oids 1 end]
517e501b89aSdanielk1977        if {[llength $noids]==0} {
518e501b89aSdanielk1977          set subret [eval $body]
519e501b89aSdanielk1977        } else {
520e501b89aSdanielk1977          set subret [lockrow $db $tbl $noids $body]
521e501b89aSdanielk1977        }
522e501b89aSdanielk1977      }
523e501b89aSdanielk1977      lappend ret [list $i $a $b]
524e501b89aSdanielk1977    }
525e501b89aSdanielk1977    return [linsert $subret 0 $ret]
526e501b89aSdanielk1977  }
527e501b89aSdanielk1977  proc locktblrows {db tbl body} {
528e501b89aSdanielk1977    set oids [db eval "SELECT oid FROM $tbl"]
529e501b89aSdanielk1977    lockrow $db $tbl $oids $body
530e501b89aSdanielk1977  }
531e501b89aSdanielk1977
532e501b89aSdanielk1977  set scans [locktblrows db t2 {
533e501b89aSdanielk1977    execsql {
534e501b89aSdanielk1977      DELETE FROM t1;
535e501b89aSdanielk1977    } db2
536e501b89aSdanielk1977  }]
537e501b89aSdanielk1977  set error 0
53814db2665Sdanielk1977
53914db2665Sdanielk1977  # Test that each SELECT query returned the expected contents of t2.
540e501b89aSdanielk1977  foreach s $scans {
541e501b89aSdanielk1977    if {[lsort -integer -index 0 $s]!=$::contents} {
542e501b89aSdanielk1977      set error 1
543e501b89aSdanielk1977    }
544e501b89aSdanielk1977  }
545e501b89aSdanielk1977  set error
546e501b89aSdanielk1977} {0}
547e501b89aSdanielk1977
548e501b89aSdanielk1977catch {db close}
549e501b89aSdanielk1977catch {db2 close}
550aaf22685Sdanielk1977
55114db2665Sdanielk1977#--------------------------------------------------------------------------
55214db2665Sdanielk1977# The following tests try to trick the shared-cache code into assuming
55314db2665Sdanielk1977# the wrong encoding for a database.
55414db2665Sdanielk1977#
55514db2665Sdanielk1977file delete -force test.db test.db-journal
55614db2665Sdanielk1977do_test shared-8.1.1 {
55714db2665Sdanielk1977  sqlite3 db test.db
55814db2665Sdanielk1977  execsql {
55914db2665Sdanielk1977    PRAGMA encoding = 'UTF-16';
56014db2665Sdanielk1977    SELECT * FROM sqlite_master;
56114db2665Sdanielk1977  }
56214db2665Sdanielk1977} {}
56314db2665Sdanielk1977do_test shared-8.1.2 {
56414db2665Sdanielk1977  string range [execsql {PRAGMA encoding;}] 0 end-2
56514db2665Sdanielk1977} {UTF-16}
56614db2665Sdanielk1977do_test shared-8.1.3 {
56714db2665Sdanielk1977  sqlite3 db2 test.db
56814db2665Sdanielk1977  execsql {
56914db2665Sdanielk1977    PRAGMA encoding = 'UTF-8';
57014db2665Sdanielk1977    CREATE TABLE abc(a, b, c);
57114db2665Sdanielk1977  } db2
57214db2665Sdanielk1977} {}
57314db2665Sdanielk1977do_test shared-8.1.4 {
57414db2665Sdanielk1977  execsql {
57514db2665Sdanielk1977    SELECT * FROM sqlite_master;
57614db2665Sdanielk1977  }
57714db2665Sdanielk1977} "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}"
57814db2665Sdanielk1977do_test shared-8.1.5 {
57914db2665Sdanielk1977  db2 close
58014db2665Sdanielk1977  execsql {
58114db2665Sdanielk1977    PRAGMA encoding;
58214db2665Sdanielk1977  }
58314db2665Sdanielk1977} {UTF-8}
58414db2665Sdanielk1977file delete -force test2.db test2.db-journal
58514db2665Sdanielk1977do_test shared-8.2.1 {
58614db2665Sdanielk1977  execsql {
58714db2665Sdanielk1977    ATTACH 'test2.db' AS aux;
58814db2665Sdanielk1977    SELECT * FROM aux.sqlite_master;
58914db2665Sdanielk1977  }
59014db2665Sdanielk1977} {}
59114db2665Sdanielk1977do_test shared-8.2.2 {
59214db2665Sdanielk1977  sqlite3 db2 test2.db
59314db2665Sdanielk1977  execsql {
59414db2665Sdanielk1977    PRAGMA encoding = 'UTF-16';
59514db2665Sdanielk1977    CREATE TABLE def(d, e, f);
59614db2665Sdanielk1977  } db2
59714db2665Sdanielk1977  string range [execsql {PRAGMA encoding;} db2] 0 end-2
59814db2665Sdanielk1977} {UTF-16}
59914db2665Sdanielk1977do_test shared-8.2.3 {
60014db2665Sdanielk1977  catchsql {
60114db2665Sdanielk1977    SELECT * FROM aux.sqlite_master;
60214db2665Sdanielk1977  }
60314db2665Sdanielk1977} {1 {attached databases must use the same text encoding as main database}}
60414db2665Sdanielk1977
60514db2665Sdanielk1977catch {db close}
60614db2665Sdanielk1977catch {db2 close}
607*eecfb3eeSdanielk1977file delete -force test.db test2.db
608*eecfb3eeSdanielk1977
609*eecfb3eeSdanielk1977if 0 {
610*eecfb3eeSdanielk1977
611*eecfb3eeSdanielk1977do_test shared-9.1 {
612*eecfb3eeSdanielk1977  sqlite3 db test.db
613*eecfb3eeSdanielk1977} {}
614*eecfb3eeSdanielk1977do_test shared-9.2 {
615*eecfb3eeSdanielk1977  execsql {CREATE TABLE t1(a);}
616*eecfb3eeSdanielk1977} {}
617*eecfb3eeSdanielk1977
618*eecfb3eeSdanielk1977file delete -force test.db
619*eecfb3eeSdanielk1977sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
620*eecfb3eeSdanielk1977do_test shared-9.3 {
621*eecfb3eeSdanielk1977  execsql {
622*eecfb3eeSdanielk1977    CREATE TABLE t5(a);
623*eecfb3eeSdanielk1977    INSERT INTO t5 VALUES('one');
624*eecfb3eeSdanielk1977  } db
625*eecfb3eeSdanielk1977} {}
626*eecfb3eeSdanielk1977
627*eecfb3eeSdanielk1977}
628*eecfb3eeSdanielk1977
629*eecfb3eeSdanielk1977#---------------------------------------------------------------------------
630*eecfb3eeSdanielk1977# The following tests - shared-9.* - test interactions between TEMP triggers
631*eecfb3eeSdanielk1977# and shared-schemas.
632*eecfb3eeSdanielk1977#
633*eecfb3eeSdanielk1977ifcapable trigger&&tempdb {
634*eecfb3eeSdanielk1977
635*eecfb3eeSdanielk1977do_test shared-9.1 {
636*eecfb3eeSdanielk1977  sqlite3 db test.db
637*eecfb3eeSdanielk1977  sqlite3 db2 test.db
638*eecfb3eeSdanielk1977  execsql {
639*eecfb3eeSdanielk1977    CREATE TABLE abc(a, b, c);
640*eecfb3eeSdanielk1977    CREATE TABLE abc_mirror(a, b, c);
641*eecfb3eeSdanielk1977    CREATE TEMP TRIGGER BEFORE INSERT ON abc BEGIN
642*eecfb3eeSdanielk1977      INSERT INTO abc_mirror(a, b, c) VALUES(new.a, new.b, new.c);
643*eecfb3eeSdanielk1977    END;
644*eecfb3eeSdanielk1977    INSERT INTO abc VALUES(1, 2, 3);
645*eecfb3eeSdanielk1977    SELECT * FROM abc_mirror;
646*eecfb3eeSdanielk1977  }
647*eecfb3eeSdanielk1977} {1 2 3}
648*eecfb3eeSdanielk1977do_test shared-9.2 {
649*eecfb3eeSdanielk1977  execsql {
650*eecfb3eeSdanielk1977    INSERT INTO abc VALUES(4, 5, 6);
651*eecfb3eeSdanielk1977    SELECT * FROM abc_mirror;
652*eecfb3eeSdanielk1977  } db2
653*eecfb3eeSdanielk1977} {1 2 3}
654*eecfb3eeSdanielk1977do_test shared-9.3 {
655*eecfb3eeSdanielk1977  db close
656*eecfb3eeSdanielk1977  db2 close
657*eecfb3eeSdanielk1977} {}
658*eecfb3eeSdanielk1977
659*eecfb3eeSdanielk1977} ; # End shared-9.*
66014db2665Sdanielk1977
661aef0bf64Sdanielk1977finish_test
662aef0bf64Sdanielk1977sqlite3_enable_shared_cache $::enable_shared_cache
663aef0bf64Sdanielk1977
664