xref: /sqlite-3.40.0/test/attach2.test (revision aef0bf64)
13c8bf55aSdrh# 2003 July 1
23c8bf55aSdrh#
33c8bf55aSdrh# The author disclaims copyright to this source code.  In place of
43c8bf55aSdrh# a legal notice, here is a blessing:
53c8bf55aSdrh#
63c8bf55aSdrh#    May you do good and not evil.
73c8bf55aSdrh#    May you find forgiveness for yourself and forgive others.
83c8bf55aSdrh#    May you share freely, never taking more than you give.
93c8bf55aSdrh#
103c8bf55aSdrh#***********************************************************************
113c8bf55aSdrh# This file implements regression tests for SQLite library.  The
123c8bf55aSdrh# focus of this script is testing the ATTACH and DETACH commands
133c8bf55aSdrh# and related functionality.
143c8bf55aSdrh#
15*aef0bf64Sdanielk1977# $Id: attach2.test,v 1.34 2005/12/30 16:28:02 danielk1977 Exp $
163c8bf55aSdrh#
173c8bf55aSdrh
183c8bf55aSdrhset testdir [file dirname $argv0]
193c8bf55aSdrhsource $testdir/tester.tcl
203c8bf55aSdrh
213c8bf55aSdrh# Ticket #354
223c8bf55aSdrh#
232ac3ee97Sdrh# Databases test.db and test2.db contain identical schemas.  Make
242ac3ee97Sdrh# sure we can attach test2.db from test.db.
252ac3ee97Sdrh#
263c8bf55aSdrhdo_test attach2-1.1 {
273c8bf55aSdrh  db eval {
283c8bf55aSdrh    CREATE TABLE t1(a,b);
293c8bf55aSdrh    CREATE INDEX x1 ON t1(a);
303c8bf55aSdrh  }
313c8bf55aSdrh  file delete -force test2.db
32447623d9Sdrh  file delete -force test2.db-journal
33ef4ac8f9Sdrh  sqlite3 db2 test2.db
343c8bf55aSdrh  db2 eval {
353c8bf55aSdrh    CREATE TABLE t1(a,b);
363c8bf55aSdrh    CREATE INDEX x1 ON t1(a);
373c8bf55aSdrh  }
383c8bf55aSdrh  catchsql {
393c8bf55aSdrh    ATTACH 'test2.db' AS t2;
403c8bf55aSdrh  }
413c8bf55aSdrh} {0 {}}
423c8bf55aSdrh
43447623d9Sdrh# Ticket #514
44447623d9Sdrh#
45447623d9Sdrhproc db_list {db} {
46447623d9Sdrh  set list {}
47447623d9Sdrh  foreach {idx name file} [execsql {PRAGMA database_list} $db] {
48447623d9Sdrh    lappend list $idx $name
49447623d9Sdrh  }
50447623d9Sdrh  return $list
51447623d9Sdrh}
52447623d9Sdrhdb eval {DETACH t2}
53447623d9Sdrhdo_test attach2-2.1 {
542ac3ee97Sdrh  # lock test2.db then try to attach it.  This is no longer an error because
552ac3ee97Sdrh  # db2 just RESERVES the database.  It does not obtain a write-lock until
562ac3ee97Sdrh  # we COMMIT.
57447623d9Sdrh  db2 eval {BEGIN}
581d850a72Sdanielk1977  db2 eval {UPDATE t1 SET a = 0 WHERE 0}
59447623d9Sdrh  catchsql {
60447623d9Sdrh    ATTACH 'test2.db' AS t2;
61447623d9Sdrh  }
62447623d9Sdrh} {0 {}}
6327188fb5Sdanielk1977ifcapable schema_pragmas {
642ac3ee97Sdrhdo_test attach2-2.2 {
652ac3ee97Sdrh  # make sure test2.db did get attached.
66447623d9Sdrh  db_list db
672b74d70aSdrh} {0 main 2 t2}
6827188fb5Sdanielk1977} ;# ifcapable schema_pragmas
692ac3ee97Sdrhdb2 eval {COMMIT}
702ac3ee97Sdrh
71447623d9Sdrhdo_test attach2-2.5 {
722ac3ee97Sdrh  # Make sure we can read test2.db from db
73447623d9Sdrh  catchsql {
74447623d9Sdrh    SELECT name FROM t2.sqlite_master;
75447623d9Sdrh  }
76447623d9Sdrh} {0 {t1 x1}}
77447623d9Sdrhdo_test attach2-2.6 {
782ac3ee97Sdrh  # lock test2.db and try to read from it.  This should still work because
792ac3ee97Sdrh  # the lock is only a RESERVED lock which does not prevent reading.
802ac3ee97Sdrh  #
81447623d9Sdrh  db2 eval BEGIN
821d850a72Sdanielk1977  db2 eval {UPDATE t1 SET a = 0 WHERE 0}
83447623d9Sdrh  catchsql {
84447623d9Sdrh    SELECT name FROM t2.sqlite_master;
85447623d9Sdrh  }
862ac3ee97Sdrh} {0 {t1 x1}}
87447623d9Sdrhdo_test attach2-2.7 {
88447623d9Sdrh  # but we can still read from test1.db even though test2.db is locked.
89447623d9Sdrh  catchsql {
90447623d9Sdrh    SELECT name FROM main.sqlite_master;
91447623d9Sdrh  }
92447623d9Sdrh} {0 {t1 x1}}
93447623d9Sdrhdo_test attach2-2.8 {
94447623d9Sdrh  # start a transaction on test.db even though test2.db is locked.
95447623d9Sdrh  catchsql {
96447623d9Sdrh    BEGIN;
97447623d9Sdrh    INSERT INTO t1 VALUES(8,9);
98447623d9Sdrh  }
99447623d9Sdrh} {0 {}}
100447623d9Sdrhdo_test attach2-2.9 {
101447623d9Sdrh  execsql {
102447623d9Sdrh    SELECT * FROM t1
103447623d9Sdrh  }
104447623d9Sdrh} {8 9}
105447623d9Sdrhdo_test attach2-2.10 {
106447623d9Sdrh  # now try to write to test2.db.  the write should fail
107447623d9Sdrh  catchsql {
108447623d9Sdrh    INSERT INTO t2.t1 VALUES(1,2);
109447623d9Sdrh  }
110447623d9Sdrh} {1 {database is locked}}
111447623d9Sdrhdo_test attach2-2.11 {
112447623d9Sdrh  # when the write failed in the previous test, the transaction should
113447623d9Sdrh  # have rolled back.
1141d850a72Sdanielk1977  #
1151d850a72Sdanielk1977  # Update for version 3: A transaction is no longer rolled back if a
1161d850a72Sdanielk1977  #                       database is found to be busy.
1171d850a72Sdanielk1977  execsql {rollback}
1188ef83ffeSdrh  db2 eval ROLLBACK
119447623d9Sdrh  execsql {
120447623d9Sdrh    SELECT * FROM t1
121447623d9Sdrh  }
122447623d9Sdrh} {}
123447623d9Sdrhdo_test attach2-2.12 {
124447623d9Sdrh  catchsql {
125447623d9Sdrh    COMMIT
126447623d9Sdrh  }
127447623d9Sdrh} {1 {cannot commit - no transaction is active}}
128447623d9Sdrh
1292ac3ee97Sdrh# Ticket #574:  Make sure it works using the non-callback API
1300bca3530Sdrh#
1310bca3530Sdrhdo_test attach2-3.1 {
1320bca3530Sdrh  db close
133ef4ac8f9Sdrh  set DB [sqlite3 db test.db]
1344ad1713cSdanielk1977  set rc [catch {sqlite3_prepare $DB "ATTACH 'test2.db' AS t2" -1 TAIL} VM]
1350bca3530Sdrh  if {$rc} {lappend rc $VM}
136f744bb56Sdanielk1977  sqlite3_step $VM
137106bb236Sdanielk1977  sqlite3_finalize $VM
1380bca3530Sdrh  set rc
1390bca3530Sdrh} {0}
1400bca3530Sdrhdo_test attach2-3.2 {
1414ad1713cSdanielk1977  set rc [catch {sqlite3_prepare $DB "DETACH t2" -1 TAIL} VM]
1420bca3530Sdrh  if {$rc} {lappend rc $VM}
143f744bb56Sdanielk1977  sqlite3_step $VM
144106bb236Sdanielk1977  sqlite3_finalize $VM
1450bca3530Sdrh  set rc
1460bca3530Sdrh} {0}
1470bca3530Sdrh
1489cb733c3Sdrhdb close
1493c8bf55aSdrhfor {set i 2} {$i<=15} {incr i} {
1503c8bf55aSdrh  catch {db$i close}
1513c8bf55aSdrh}
152a6abd041Sdrh
153a6abd041Sdrh# A procedure to verify the status of locks on a database.
154a6abd041Sdrh#
155a6abd041Sdrhproc lock_status {testnum db expected_result} {
15653c0f748Sdanielk1977  # If the database was compiled with OMIT_TEMPDB set, then
15753c0f748Sdanielk1977  # the lock_status list will not contain an entry for the temp
15853c0f748Sdanielk1977  # db. But the test code doesn't know this, so it's easiest
159*aef0bf64Sdanielk1977  # to filter it out of the $expected_result list here.
16053c0f748Sdanielk1977  ifcapable !tempdb {
16153c0f748Sdanielk1977    set expected_result [concat \
16253c0f748Sdanielk1977        [lrange $expected_result 0 1] \
16353c0f748Sdanielk1977        [lrange $expected_result 4 end] \
16453c0f748Sdanielk1977    ]
16553c0f748Sdanielk1977  }
166a6abd041Sdrh  do_test attach2-$testnum [subst {
167d5a71b5dSdrh    $db cache flush  ;# The lock_status pragma should not be cached
168a6abd041Sdrh    execsql {PRAGMA lock_status} $db
169a6abd041Sdrh  }] $expected_result
170a6abd041Sdrh}
1712ac3ee97Sdrhset sqlite_os_trace 0
1723a81de11Sdanielk1977
1733a81de11Sdanielk1977# Tests attach2-4.* test that read-locks work correctly with attached
1743a81de11Sdanielk1977# databases.
1753a81de11Sdanielk1977do_test attach2-4.1 {
176ef4ac8f9Sdrh  sqlite3 db test.db
177ef4ac8f9Sdrh  sqlite3 db2 test.db
1783a81de11Sdanielk1977  execsql {ATTACH 'test2.db' as file2}
1793a81de11Sdanielk1977  execsql {ATTACH 'test2.db' as file2} db2
1803a81de11Sdanielk1977} {}
1813a81de11Sdanielk1977
182dc3ff9c3Sdrhlock_status 4.1.1 db {main unlocked temp closed file2 unlocked}
183dc3ff9c3Sdrhlock_status 4.1.2 db2 {main unlocked temp closed file2 unlocked}
184a6abd041Sdrh
1853a81de11Sdanielk1977do_test attach2-4.2 {
1862ac3ee97Sdrh  # Handle 'db' read-locks test.db
1873a81de11Sdanielk1977  execsql {BEGIN}
1883a81de11Sdanielk1977  execsql {SELECT * FROM t1}
189faa57accSdrh  # Lock status:
190faa57accSdrh  #    db  - shared(main)
191faa57accSdrh  #    db2 -
1923a81de11Sdanielk1977} {}
193a6abd041Sdrh
194dc3ff9c3Sdrhlock_status 4.2.1 db {main shared temp closed file2 unlocked}
195dc3ff9c3Sdrhlock_status 4.2.2 db2 {main unlocked temp closed file2 unlocked}
196a6abd041Sdrh
1973a81de11Sdanielk1977do_test attach2-4.3 {
1982ac3ee97Sdrh  # The read lock held by db does not prevent db2 from reading test.db
1993a81de11Sdanielk1977  execsql {SELECT * FROM t1} db2
2003a81de11Sdanielk1977} {}
201a6abd041Sdrh
202dc3ff9c3Sdrhlock_status 4.3.1 db {main shared temp closed file2 unlocked}
203dc3ff9c3Sdrhlock_status 4.3.2 db2 {main unlocked temp closed file2 unlocked}
204a6abd041Sdrh
2053a81de11Sdanielk1977do_test attach2-4.4 {
206faa57accSdrh  # db is holding a read lock on test.db, so we should not be able
2072ac3ee97Sdrh  # to commit a write to test.db from db2
208faa57accSdrh  catchsql {
2093a81de11Sdanielk1977    INSERT INTO t1 VALUES(1, 2)
2103a81de11Sdanielk1977  } db2
2113a81de11Sdanielk1977} {1 {database is locked}}
212a6abd041Sdrh
213dc3ff9c3Sdrhlock_status 4.4.1 db {main shared temp closed file2 unlocked}
21434f4732bSdrhlock_status 4.4.2 db2 {main unlocked temp closed file2 unlocked}
215a6abd041Sdrh
2163a81de11Sdanielk1977do_test attach2-4.5 {
2172ac3ee97Sdrh  # Handle 'db2' reserves file2.
2183a81de11Sdanielk1977  execsql {BEGIN} db2
2193a81de11Sdanielk1977  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
220faa57accSdrh  # Lock status:
221faa57accSdrh  #    db  - shared(main)
222faa57accSdrh  #    db2 - reserved(file2)
2233a81de11Sdanielk1977} {}
224a6abd041Sdrh
225dc3ff9c3Sdrhlock_status 4.5.1 db {main shared temp closed file2 unlocked}
22634f4732bSdrhlock_status 4.5.2 db2 {main unlocked temp closed file2 reserved}
227a6abd041Sdrh
2282ac3ee97Sdrhdo_test attach2-4.6.1 {
2292ac3ee97Sdrh  # Reads are allowed against a reserved database.
2302ac3ee97Sdrh  catchsql {
2313a81de11Sdanielk1977    SELECT * FROM file2.t1;
2323a81de11Sdanielk1977  }
233faa57accSdrh  # Lock status:
234faa57accSdrh  #    db  - shared(main), shared(file2)
235faa57accSdrh  #    db2 - reserved(file2)
2362ac3ee97Sdrh} {0 {}}
237a6abd041Sdrh
238dc3ff9c3Sdrhlock_status 4.6.1.1 db {main shared temp closed file2 shared}
23934f4732bSdrhlock_status 4.6.1.2 db2 {main unlocked temp closed file2 reserved}
240a6abd041Sdrh
2412ac3ee97Sdrhdo_test attach2-4.6.2 {
2422ac3ee97Sdrh  # Writes against a reserved database are not allowed.
2432ac3ee97Sdrh  catchsql {
2442ac3ee97Sdrh    UPDATE file2.t1 SET a=0;
2452ac3ee97Sdrh  }
2463a81de11Sdanielk1977} {1 {database is locked}}
247a6abd041Sdrh
24834f4732bSdrhlock_status 4.6.2.1 db {main shared temp closed file2 shared}
24934f4732bSdrhlock_status 4.6.2.2 db2 {main unlocked temp closed file2 reserved}
250a6abd041Sdrh
2513a81de11Sdanielk1977do_test attach2-4.7 {
2523a81de11Sdanielk1977  # Ensure handle 'db' retains the lock on the main file after
2532ac3ee97Sdrh  # failing to obtain a write-lock on file2.
2542ac3ee97Sdrh  catchsql {
2553a81de11Sdanielk1977    INSERT INTO t1 VALUES(1, 2)
2563a81de11Sdanielk1977  } db2
257a6abd041Sdrh} {0 {}}
258a6abd041Sdrh
25934f4732bSdrhlock_status 4.7.1 db {main shared temp closed file2 shared}
26034f4732bSdrhlock_status 4.7.2 db2 {main reserved temp closed file2 reserved}
261a6abd041Sdrh
2623a81de11Sdanielk1977do_test attach2-4.8 {
263a6abd041Sdrh  # We should still be able to read test.db from db2
2643a81de11Sdanielk1977  execsql {SELECT * FROM t1} db2
265a6abd041Sdrh} {1 2}
266a6abd041Sdrh
26734f4732bSdrhlock_status 4.8.1 db {main shared temp closed file2 shared}
26834f4732bSdrhlock_status 4.8.2 db2 {main reserved temp closed file2 reserved}
269a6abd041Sdrh
2703a81de11Sdanielk1977do_test attach2-4.9 {
2713a81de11Sdanielk1977  # Try to upgrade the handle 'db' lock.
2722ac3ee97Sdrh  catchsql {
2733a81de11Sdanielk1977    INSERT INTO t1 VALUES(1, 2)
2743a81de11Sdanielk1977  }
2753a81de11Sdanielk1977} {1 {database is locked}}
276a6abd041Sdrh
27734f4732bSdrhlock_status 4.9.1 db {main shared temp closed file2 shared}
27834f4732bSdrhlock_status 4.9.2 db2 {main reserved temp closed file2 reserved}
279a6abd041Sdrh
2803a81de11Sdanielk1977do_test attach2-4.10 {
281ff13c7d6Sdrh  # We cannot commit db2 while db is holding a read-lock
282ff13c7d6Sdrh  catchsql {COMMIT} db2
283ff13c7d6Sdrh} {1 {database is locked}}
284a6abd041Sdrh
28534f4732bSdrhlock_status 4.10.1 db {main shared temp closed file2 shared}
28634f4732bSdrhlock_status 4.10.2 db2 {main pending temp closed file2 reserved}
287a6abd041Sdrh
2883cde3bb0Sdrhset sqlite_os_trace 0
2893a81de11Sdanielk1977do_test attach2-4.11 {
290ff13c7d6Sdrh  # db is able to commit.
291ff13c7d6Sdrh  catchsql {COMMIT}
292ff13c7d6Sdrh} {0 {}}
293ff13c7d6Sdrh
29434f4732bSdrhlock_status 4.11.1 db {main unlocked temp closed file2 unlocked}
29534f4732bSdrhlock_status 4.11.2 db2 {main pending temp closed file2 reserved}
296ff13c7d6Sdrh
297ff13c7d6Sdrhdo_test attach2-4.12 {
298ff13c7d6Sdrh  # Now we can commit db2
299ff13c7d6Sdrh  catchsql {COMMIT} db2
300ff13c7d6Sdrh} {0 {}}
301ff13c7d6Sdrh
30234f4732bSdrhlock_status 4.12.1 db {main unlocked temp closed file2 unlocked}
30334f4732bSdrhlock_status 4.12.2 db2 {main unlocked temp closed file2 unlocked}
304ff13c7d6Sdrh
305ff13c7d6Sdrhdo_test attach2-4.13 {
3063a81de11Sdanielk1977  execsql {SELECT * FROM file2.t1}
3073a81de11Sdanielk1977} {1 2}
308ff13c7d6Sdrhdo_test attach2-4.14 {
3093a81de11Sdanielk1977  execsql {INSERT INTO t1 VALUES(1, 2)}
3103a81de11Sdanielk1977} {}
311ff13c7d6Sdrhdo_test attach2-4.15 {
3123a81de11Sdanielk1977  execsql {SELECT * FROM t1} db2
313ff13c7d6Sdrh} {1 2 1 2}
3143a81de11Sdanielk1977
3153a81de11Sdanielk1977db close
3163a81de11Sdanielk1977db2 close
3173c8bf55aSdrhfile delete -force test2.db
3183c8bf55aSdrh
319962398d3Sdanielk1977# These tests - attach2-5.* - check that the master journal file is deleted
320962398d3Sdanielk1977# correctly when a multi-file transaction is committed or rolled back.
321962398d3Sdanielk1977#
322962398d3Sdanielk1977# Update: It's not actually created if a rollback occurs, so that test
323962398d3Sdanielk1977# doesn't really prove too much.
324962398d3Sdanielk1977foreach f [glob test.db*] {file delete -force $f}
325962398d3Sdanielk1977do_test attach2-5.1 {
326ef4ac8f9Sdrh  sqlite3 db test.db
327962398d3Sdanielk1977  execsql {
328962398d3Sdanielk1977    ATTACH 'test.db2' AS aux;
329962398d3Sdanielk1977  }
330962398d3Sdanielk1977} {}
331962398d3Sdanielk1977do_test attach2-5.2 {
332962398d3Sdanielk1977  execsql {
333962398d3Sdanielk1977    BEGIN;
334962398d3Sdanielk1977    CREATE TABLE tbl(a, b, c);
335962398d3Sdanielk1977    CREATE TABLE aux.tbl(a, b, c);
336962398d3Sdanielk1977    COMMIT;
337962398d3Sdanielk1977  }
338962398d3Sdanielk1977} {}
339962398d3Sdanielk1977do_test attach2-5.3 {
34057790b8fSdrh  lsort [glob test.db*]
341962398d3Sdanielk1977} {test.db test.db2}
342962398d3Sdanielk1977do_test attach2-5.4 {
343962398d3Sdanielk1977  execsql {
344962398d3Sdanielk1977    BEGIN;
345962398d3Sdanielk1977    DROP TABLE aux.tbl;
346962398d3Sdanielk1977    DROP TABLE tbl;
347962398d3Sdanielk1977    ROLLBACK;
348962398d3Sdanielk1977  }
349962398d3Sdanielk1977} {}
350962398d3Sdanielk1977do_test attach2-5.5 {
35157790b8fSdrh  lsort [glob test.db*]
352962398d3Sdanielk1977} {test.db test.db2}
353962398d3Sdanielk1977
35492f9a1bbSdanielk1977# Check that a database cannot be ATTACHed or DETACHed during a transaction.
35592f9a1bbSdanielk1977do_test attach2-6.1 {
35692f9a1bbSdanielk1977  execsql {
35792f9a1bbSdanielk1977    BEGIN;
35892f9a1bbSdanielk1977  }
35992f9a1bbSdanielk1977} {}
36092f9a1bbSdanielk1977do_test attach2-6.2 {
36192f9a1bbSdanielk1977  catchsql {
36292f9a1bbSdanielk1977    ATTACH 'test3.db' as aux2;
36392f9a1bbSdanielk1977  }
36492f9a1bbSdanielk1977} {1 {cannot ATTACH database within transaction}}
36592f9a1bbSdanielk1977
36692f9a1bbSdanielk1977do_test attach2-6.3 {
36792f9a1bbSdanielk1977  catchsql {
36892f9a1bbSdanielk1977    DETACH aux;
36992f9a1bbSdanielk1977  }
37092f9a1bbSdanielk1977} {1 {cannot DETACH database within transaction}}
37192f9a1bbSdanielk1977do_test attach2-6.4 {
37292f9a1bbSdanielk1977  execsql {
37392f9a1bbSdanielk1977    COMMIT;
37492f9a1bbSdanielk1977    DETACH aux;
37592f9a1bbSdanielk1977  }
37692f9a1bbSdanielk1977} {}
37792f9a1bbSdanielk1977
378962398d3Sdanielk1977db close
379962398d3Sdanielk1977
3803c8bf55aSdrhfinish_test
381