xref: /sqlite-3.40.0/test/attach2.test (revision ef5ecb41)
1# 2003 July 1
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#***********************************************************************
11# This file implements regression tests for SQLite library.  The
12# focus of this script is testing the ATTACH and DETACH commands
13# and related functionality.
14#
15# $Id: attach2.test,v 1.15 2004/06/09 21:01:12 drh Exp $
16#
17
18set testdir [file dirname $argv0]
19source $testdir/tester.tcl
20
21
22# Ticket #354
23#
24# Databases test.db and test2.db contain identical schemas.  Make
25# sure we can attach test2.db from test.db.
26#
27do_test attach2-1.1 {
28  db eval {
29    CREATE TABLE t1(a,b);
30    CREATE INDEX x1 ON t1(a);
31  }
32  file delete -force test2.db
33  file delete -force test2.db-journal
34  sqlite db2 test2.db
35  db2 eval {
36    CREATE TABLE t1(a,b);
37    CREATE INDEX x1 ON t1(a);
38  }
39  catchsql {
40    ATTACH 'test2.db' AS t2;
41  }
42} {0 {}}
43
44# Ticket #514
45#
46proc db_list {db} {
47  set list {}
48  foreach {idx name file} [execsql {PRAGMA database_list} $db] {
49    lappend list $idx $name
50  }
51  return $list
52}
53db eval {DETACH t2}
54do_test attach2-2.1 {
55  # lock test2.db then try to attach it.  This is no longer an error because
56  # db2 just RESERVES the database.  It does not obtain a write-lock until
57  # we COMMIT.
58  db2 eval {BEGIN}
59  db2 eval {UPDATE t1 SET a = 0 WHERE 0}
60  catchsql {
61    ATTACH 'test2.db' AS t2;
62  }
63} {0 {}}
64do_test attach2-2.2 {
65  # make sure test2.db did get attached.
66  db_list db
67} {0 main 1 temp 2 t2}
68db2 eval {COMMIT}
69
70do_test attach2-2.5 {
71  # Make sure we can read test2.db from db
72  catchsql {
73    SELECT name FROM t2.sqlite_master;
74  }
75} {0 {t1 x1}}
76do_test attach2-2.6 {
77  # lock test2.db and try to read from it.  This should still work because
78  # the lock is only a RESERVED lock which does not prevent reading.
79  #
80  db2 eval BEGIN
81  db2 eval {UPDATE t1 SET a = 0 WHERE 0}
82  catchsql {
83    SELECT name FROM t2.sqlite_master;
84  }
85} {0 {t1 x1}}
86do_test attach2-2.7 {
87  # but we can still read from test1.db even though test2.db is locked.
88  catchsql {
89    SELECT name FROM main.sqlite_master;
90  }
91} {0 {t1 x1}}
92do_test attach2-2.8 {
93  # start a transaction on test.db even though test2.db is locked.
94  catchsql {
95    BEGIN;
96    INSERT INTO t1 VALUES(8,9);
97  }
98} {0 {}}
99do_test attach2-2.9 {
100  execsql {
101    SELECT * FROM t1
102  }
103} {8 9}
104do_test attach2-2.10 {
105  # now try to write to test2.db.  the write should fail
106  catchsql {
107    INSERT INTO t2.t1 VALUES(1,2);
108  }
109} {1 {database is locked}}
110do_test attach2-2.11 {
111  # when the write failed in the previous test, the transaction should
112  # have rolled back.
113  #
114  # Update for version 3: A transaction is no longer rolled back if a
115  #                       database is found to be busy.
116  execsql {rollback}
117  db2 eval ROLLBACK
118  execsql {
119    SELECT * FROM t1
120  }
121} {}
122do_test attach2-2.12 {
123  catchsql {
124    COMMIT
125  }
126} {1 {cannot commit - no transaction is active}}
127
128# Ticket #574:  Make sure it works using the non-callback API
129#
130do_test attach2-3.1 {
131  db close
132  set DB [sqlite db test.db]
133  set rc [catch {sqlite3_prepare $DB "ATTACH 'test2.db' AS t2" -1 TAIL} VM]
134  if {$rc} {lappend rc $VM}
135  sqlite3_finalize $VM
136  set rc
137} {0}
138do_test attach2-3.2 {
139  set rc [catch {sqlite3_prepare $DB "DETACH t2" -1 TAIL} VM]
140  if {$rc} {lappend rc $VM}
141  sqlite3_finalize $VM
142  set rc
143} {0}
144
145db close
146for {set i 2} {$i<=15} {incr i} {
147  catch {db$i close}
148}
149
150# A procedure to verify the status of locks on a database.
151#
152proc lock_status {testnum db expected_result} {
153  do_test attach2-$testnum [subst {
154    execsql {PRAGMA lock_status} $db
155  }] $expected_result
156}
157set sqlite_os_trace 0
158
159# Tests attach2-4.* test that read-locks work correctly with attached
160# databases.
161do_test attach2-4.1 {
162  sqlite db test.db
163  sqlite db2 test.db
164  execsql {ATTACH 'test2.db' as file2}
165  execsql {ATTACH 'test2.db' as file2} db2
166} {}
167
168lock_status 4.1.1 db {main unlocked temp unlocked file2 unlocked}
169lock_status 4.1.2 db2 {main unlocked temp unlocked file2 unlocked}
170
171do_test attach2-4.2 {
172  # Handle 'db' read-locks test.db
173  execsql {BEGIN}
174  execsql {SELECT * FROM t1}
175  # Lock status:
176  #    db  - shared(main)
177  #    db2 -
178} {}
179
180lock_status 4.2.1 db {main shared temp shared file2 unlocked}
181lock_status 4.2.2 db2 {main unlocked temp unlocked file2 unlocked}
182
183do_test attach2-4.3 {
184  # The read lock held by db does not prevent db2 from reading test.db
185  execsql {SELECT * FROM t1} db2
186} {}
187
188lock_status 4.3.1 db {main shared temp shared file2 unlocked}
189lock_status 4.3.2 db2 {main unlocked temp unlocked file2 unlocked}
190
191do_test attach2-4.4 {
192  # db is holding a read lock on test.db, so we should not be able
193  # to commit a write to test.db from db2
194  catchsql {
195    INSERT INTO t1 VALUES(1, 2)
196  } db2
197} {1 {database is locked}}
198
199lock_status 4.4.1 db {main shared temp shared file2 unlocked}
200lock_status 4.4.2 db2 {main unlocked temp unlocked file2 unlocked}
201
202do_test attach2-4.5 {
203  # Handle 'db2' reserves file2.
204  execsql {BEGIN} db2
205  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
206  # Lock status:
207  #    db  - shared(main)
208  #    db2 - reserved(file2)
209} {}
210
211lock_status 4.5.1 db {main shared temp shared file2 unlocked}
212lock_status 4.5.2 db2 {main unlocked temp reserved file2 reserved}
213
214do_test attach2-4.6.1 {
215  # Reads are allowed against a reserved database.
216  catchsql {
217    SELECT * FROM file2.t1;
218  }
219  # Lock status:
220  #    db  - shared(main), shared(file2)
221  #    db2 - reserved(file2)
222} {0 {}}
223
224lock_status 4.6.1.1 db {main shared temp shared file2 shared}
225lock_status 4.6.1.2 db2 {main unlocked temp reserved file2 reserved}
226
227do_test attach2-4.6.2 {
228  # Writes against a reserved database are not allowed.
229  catchsql {
230    UPDATE file2.t1 SET a=0;
231  }
232} {1 {database is locked}}
233
234lock_status 4.6.2.1 db {main shared temp reserved file2 shared}
235lock_status 4.6.2.2 db2 {main unlocked temp reserved file2 reserved}
236
237do_test attach2-4.7 {
238  # Ensure handle 'db' retains the lock on the main file after
239  # failing to obtain a write-lock on file2.
240  catchsql {
241    INSERT INTO t1 VALUES(1, 2)
242  } db2
243} {0 {}}
244
245lock_status 4.7.1 db {main shared temp reserved file2 shared}
246lock_status 4.7.2 db2 {main reserved temp reserved file2 reserved}
247
248do_test attach2-4.8 {
249  # We should still be able to read test.db from db2
250  execsql {SELECT * FROM t1} db2
251} {1 2}
252
253lock_status 4.8.1 db {main shared temp reserved file2 shared}
254lock_status 4.8.2 db2 {main reserved temp reserved file2 reserved}
255
256do_test attach2-4.9 {
257  # Try to upgrade the handle 'db' lock.
258  catchsql {
259    INSERT INTO t1 VALUES(1, 2)
260  }
261} {1 {database is locked}}
262
263lock_status 4.9.1 db {main shared temp reserved file2 shared}
264lock_status 4.9.2 db2 {main reserved temp reserved file2 reserved}
265
266set sqlite_os_trace 0
267btree_breakpoint
268do_test attach2-4.10 {
269  # We cannot commit db2 while db is holding a read-lock
270  catchsql {COMMIT} db2
271} {1 {database is locked}}
272
273lock_status 4.10.1 db {main shared temp reserved file2 shared}
274lock_status 4.10.2 db2 {main reserved temp reserved file2 reserved}
275
276do_test attach2-4.11 {
277  # db is able to commit.
278  catchsql {COMMIT}
279} {0 {}}
280
281lock_status 4.11.1 db {main unlocked temp unlocked file2 unlocked}
282lock_status 4.11.2 db2 {main reserved temp reserved file2 reserved}
283
284do_test attach2-4.12 {
285  # Now we can commit db2
286  catchsql {COMMIT} db2
287} {0 {}}
288
289lock_status 4.12.1 db {main unlocked temp unlocked file2 unlocked}
290lock_status 4.12.2 db2 {main unlocked temp unlocked file2 unlocked}
291
292do_test attach2-4.13 {
293  execsql {SELECT * FROM file2.t1}
294} {1 2}
295do_test attach2-4.14 {
296  execsql {INSERT INTO t1 VALUES(1, 2)}
297} {}
298do_test attach2-4.15 {
299  execsql {SELECT * FROM t1} db2
300} {1 2 1 2}
301
302db close
303db2 close
304file delete -force test2.db
305
306finish_test
307