xref: /sqlite-3.40.0/test/attach2.test (revision dddca286)
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*dddca286Sdrh# $Id: attach2.test,v 1.35 2006/01/03 00:33:50 drh 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 {
132*dddca286Sdrh  set DB [sqlite3_connection_pointer db]
1334ad1713cSdanielk1977  set rc [catch {sqlite3_prepare $DB "ATTACH 'test2.db' AS t2" -1 TAIL} VM]
1340bca3530Sdrh  if {$rc} {lappend rc $VM}
135f744bb56Sdanielk1977  sqlite3_step $VM
136106bb236Sdanielk1977  sqlite3_finalize $VM
1370bca3530Sdrh  set rc
1380bca3530Sdrh} {0}
1390bca3530Sdrhdo_test attach2-3.2 {
1404ad1713cSdanielk1977  set rc [catch {sqlite3_prepare $DB "DETACH t2" -1 TAIL} VM]
1410bca3530Sdrh  if {$rc} {lappend rc $VM}
142f744bb56Sdanielk1977  sqlite3_step $VM
143106bb236Sdanielk1977  sqlite3_finalize $VM
1440bca3530Sdrh  set rc
1450bca3530Sdrh} {0}
1460bca3530Sdrh
1479cb733c3Sdrhdb close
1483c8bf55aSdrhfor {set i 2} {$i<=15} {incr i} {
1493c8bf55aSdrh  catch {db$i close}
1503c8bf55aSdrh}
151a6abd041Sdrh
152a6abd041Sdrh# A procedure to verify the status of locks on a database.
153a6abd041Sdrh#
154a6abd041Sdrhproc lock_status {testnum db expected_result} {
15553c0f748Sdanielk1977  # If the database was compiled with OMIT_TEMPDB set, then
15653c0f748Sdanielk1977  # the lock_status list will not contain an entry for the temp
15753c0f748Sdanielk1977  # db. But the test code doesn't know this, so it's easiest
158aef0bf64Sdanielk1977  # to filter it out of the $expected_result list here.
15953c0f748Sdanielk1977  ifcapable !tempdb {
16053c0f748Sdanielk1977    set expected_result [concat \
16153c0f748Sdanielk1977        [lrange $expected_result 0 1] \
16253c0f748Sdanielk1977        [lrange $expected_result 4 end] \
16353c0f748Sdanielk1977    ]
16453c0f748Sdanielk1977  }
165a6abd041Sdrh  do_test attach2-$testnum [subst {
166d5a71b5dSdrh    $db cache flush  ;# The lock_status pragma should not be cached
167a6abd041Sdrh    execsql {PRAGMA lock_status} $db
168a6abd041Sdrh  }] $expected_result
169a6abd041Sdrh}
1702ac3ee97Sdrhset sqlite_os_trace 0
1713a81de11Sdanielk1977
1723a81de11Sdanielk1977# Tests attach2-4.* test that read-locks work correctly with attached
1733a81de11Sdanielk1977# databases.
1743a81de11Sdanielk1977do_test attach2-4.1 {
175ef4ac8f9Sdrh  sqlite3 db test.db
176ef4ac8f9Sdrh  sqlite3 db2 test.db
1773a81de11Sdanielk1977  execsql {ATTACH 'test2.db' as file2}
1783a81de11Sdanielk1977  execsql {ATTACH 'test2.db' as file2} db2
1793a81de11Sdanielk1977} {}
1803a81de11Sdanielk1977
181dc3ff9c3Sdrhlock_status 4.1.1 db {main unlocked temp closed file2 unlocked}
182dc3ff9c3Sdrhlock_status 4.1.2 db2 {main unlocked temp closed file2 unlocked}
183a6abd041Sdrh
1843a81de11Sdanielk1977do_test attach2-4.2 {
1852ac3ee97Sdrh  # Handle 'db' read-locks test.db
1863a81de11Sdanielk1977  execsql {BEGIN}
1873a81de11Sdanielk1977  execsql {SELECT * FROM t1}
188faa57accSdrh  # Lock status:
189faa57accSdrh  #    db  - shared(main)
190faa57accSdrh  #    db2 -
1913a81de11Sdanielk1977} {}
192a6abd041Sdrh
193dc3ff9c3Sdrhlock_status 4.2.1 db {main shared temp closed file2 unlocked}
194dc3ff9c3Sdrhlock_status 4.2.2 db2 {main unlocked temp closed file2 unlocked}
195a6abd041Sdrh
1963a81de11Sdanielk1977do_test attach2-4.3 {
1972ac3ee97Sdrh  # The read lock held by db does not prevent db2 from reading test.db
1983a81de11Sdanielk1977  execsql {SELECT * FROM t1} db2
1993a81de11Sdanielk1977} {}
200a6abd041Sdrh
201dc3ff9c3Sdrhlock_status 4.3.1 db {main shared temp closed file2 unlocked}
202dc3ff9c3Sdrhlock_status 4.3.2 db2 {main unlocked temp closed file2 unlocked}
203a6abd041Sdrh
2043a81de11Sdanielk1977do_test attach2-4.4 {
205faa57accSdrh  # db is holding a read lock on test.db, so we should not be able
2062ac3ee97Sdrh  # to commit a write to test.db from db2
207faa57accSdrh  catchsql {
2083a81de11Sdanielk1977    INSERT INTO t1 VALUES(1, 2)
2093a81de11Sdanielk1977  } db2
2103a81de11Sdanielk1977} {1 {database is locked}}
211a6abd041Sdrh
212dc3ff9c3Sdrhlock_status 4.4.1 db {main shared temp closed file2 unlocked}
21334f4732bSdrhlock_status 4.4.2 db2 {main unlocked temp closed file2 unlocked}
214a6abd041Sdrh
2153a81de11Sdanielk1977do_test attach2-4.5 {
2162ac3ee97Sdrh  # Handle 'db2' reserves file2.
2173a81de11Sdanielk1977  execsql {BEGIN} db2
2183a81de11Sdanielk1977  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
219faa57accSdrh  # Lock status:
220faa57accSdrh  #    db  - shared(main)
221faa57accSdrh  #    db2 - reserved(file2)
2223a81de11Sdanielk1977} {}
223a6abd041Sdrh
224dc3ff9c3Sdrhlock_status 4.5.1 db {main shared temp closed file2 unlocked}
22534f4732bSdrhlock_status 4.5.2 db2 {main unlocked temp closed file2 reserved}
226a6abd041Sdrh
2272ac3ee97Sdrhdo_test attach2-4.6.1 {
2282ac3ee97Sdrh  # Reads are allowed against a reserved database.
2292ac3ee97Sdrh  catchsql {
2303a81de11Sdanielk1977    SELECT * FROM file2.t1;
2313a81de11Sdanielk1977  }
232faa57accSdrh  # Lock status:
233faa57accSdrh  #    db  - shared(main), shared(file2)
234faa57accSdrh  #    db2 - reserved(file2)
2352ac3ee97Sdrh} {0 {}}
236a6abd041Sdrh
237dc3ff9c3Sdrhlock_status 4.6.1.1 db {main shared temp closed file2 shared}
23834f4732bSdrhlock_status 4.6.1.2 db2 {main unlocked temp closed file2 reserved}
239a6abd041Sdrh
2402ac3ee97Sdrhdo_test attach2-4.6.2 {
2412ac3ee97Sdrh  # Writes against a reserved database are not allowed.
2422ac3ee97Sdrh  catchsql {
2432ac3ee97Sdrh    UPDATE file2.t1 SET a=0;
2442ac3ee97Sdrh  }
2453a81de11Sdanielk1977} {1 {database is locked}}
246a6abd041Sdrh
24734f4732bSdrhlock_status 4.6.2.1 db {main shared temp closed file2 shared}
24834f4732bSdrhlock_status 4.6.2.2 db2 {main unlocked temp closed file2 reserved}
249a6abd041Sdrh
2503a81de11Sdanielk1977do_test attach2-4.7 {
2513a81de11Sdanielk1977  # Ensure handle 'db' retains the lock on the main file after
2522ac3ee97Sdrh  # failing to obtain a write-lock on file2.
2532ac3ee97Sdrh  catchsql {
2543a81de11Sdanielk1977    INSERT INTO t1 VALUES(1, 2)
2553a81de11Sdanielk1977  } db2
256a6abd041Sdrh} {0 {}}
257a6abd041Sdrh
25834f4732bSdrhlock_status 4.7.1 db {main shared temp closed file2 shared}
25934f4732bSdrhlock_status 4.7.2 db2 {main reserved temp closed file2 reserved}
260a6abd041Sdrh
2613a81de11Sdanielk1977do_test attach2-4.8 {
262a6abd041Sdrh  # We should still be able to read test.db from db2
2633a81de11Sdanielk1977  execsql {SELECT * FROM t1} db2
264a6abd041Sdrh} {1 2}
265a6abd041Sdrh
26634f4732bSdrhlock_status 4.8.1 db {main shared temp closed file2 shared}
26734f4732bSdrhlock_status 4.8.2 db2 {main reserved temp closed file2 reserved}
268a6abd041Sdrh
2693a81de11Sdanielk1977do_test attach2-4.9 {
2703a81de11Sdanielk1977  # Try to upgrade the handle 'db' lock.
2712ac3ee97Sdrh  catchsql {
2723a81de11Sdanielk1977    INSERT INTO t1 VALUES(1, 2)
2733a81de11Sdanielk1977  }
2743a81de11Sdanielk1977} {1 {database is locked}}
275a6abd041Sdrh
27634f4732bSdrhlock_status 4.9.1 db {main shared temp closed file2 shared}
27734f4732bSdrhlock_status 4.9.2 db2 {main reserved temp closed file2 reserved}
278a6abd041Sdrh
2793a81de11Sdanielk1977do_test attach2-4.10 {
280ff13c7d6Sdrh  # We cannot commit db2 while db is holding a read-lock
281ff13c7d6Sdrh  catchsql {COMMIT} db2
282ff13c7d6Sdrh} {1 {database is locked}}
283a6abd041Sdrh
28434f4732bSdrhlock_status 4.10.1 db {main shared temp closed file2 shared}
28534f4732bSdrhlock_status 4.10.2 db2 {main pending temp closed file2 reserved}
286a6abd041Sdrh
2873cde3bb0Sdrhset sqlite_os_trace 0
2883a81de11Sdanielk1977do_test attach2-4.11 {
289ff13c7d6Sdrh  # db is able to commit.
290ff13c7d6Sdrh  catchsql {COMMIT}
291ff13c7d6Sdrh} {0 {}}
292ff13c7d6Sdrh
29334f4732bSdrhlock_status 4.11.1 db {main unlocked temp closed file2 unlocked}
29434f4732bSdrhlock_status 4.11.2 db2 {main pending temp closed file2 reserved}
295ff13c7d6Sdrh
296ff13c7d6Sdrhdo_test attach2-4.12 {
297ff13c7d6Sdrh  # Now we can commit db2
298ff13c7d6Sdrh  catchsql {COMMIT} db2
299ff13c7d6Sdrh} {0 {}}
300ff13c7d6Sdrh
30134f4732bSdrhlock_status 4.12.1 db {main unlocked temp closed file2 unlocked}
30234f4732bSdrhlock_status 4.12.2 db2 {main unlocked temp closed file2 unlocked}
303ff13c7d6Sdrh
304ff13c7d6Sdrhdo_test attach2-4.13 {
3053a81de11Sdanielk1977  execsql {SELECT * FROM file2.t1}
3063a81de11Sdanielk1977} {1 2}
307ff13c7d6Sdrhdo_test attach2-4.14 {
3083a81de11Sdanielk1977  execsql {INSERT INTO t1 VALUES(1, 2)}
3093a81de11Sdanielk1977} {}
310ff13c7d6Sdrhdo_test attach2-4.15 {
3113a81de11Sdanielk1977  execsql {SELECT * FROM t1} db2
312ff13c7d6Sdrh} {1 2 1 2}
3133a81de11Sdanielk1977
3143a81de11Sdanielk1977db close
3153a81de11Sdanielk1977db2 close
3163c8bf55aSdrhfile delete -force test2.db
3173c8bf55aSdrh
318962398d3Sdanielk1977# These tests - attach2-5.* - check that the master journal file is deleted
319962398d3Sdanielk1977# correctly when a multi-file transaction is committed or rolled back.
320962398d3Sdanielk1977#
321962398d3Sdanielk1977# Update: It's not actually created if a rollback occurs, so that test
322962398d3Sdanielk1977# doesn't really prove too much.
323962398d3Sdanielk1977foreach f [glob test.db*] {file delete -force $f}
324962398d3Sdanielk1977do_test attach2-5.1 {
325ef4ac8f9Sdrh  sqlite3 db test.db
326962398d3Sdanielk1977  execsql {
327962398d3Sdanielk1977    ATTACH 'test.db2' AS aux;
328962398d3Sdanielk1977  }
329962398d3Sdanielk1977} {}
330962398d3Sdanielk1977do_test attach2-5.2 {
331962398d3Sdanielk1977  execsql {
332962398d3Sdanielk1977    BEGIN;
333962398d3Sdanielk1977    CREATE TABLE tbl(a, b, c);
334962398d3Sdanielk1977    CREATE TABLE aux.tbl(a, b, c);
335962398d3Sdanielk1977    COMMIT;
336962398d3Sdanielk1977  }
337962398d3Sdanielk1977} {}
338962398d3Sdanielk1977do_test attach2-5.3 {
33957790b8fSdrh  lsort [glob test.db*]
340962398d3Sdanielk1977} {test.db test.db2}
341962398d3Sdanielk1977do_test attach2-5.4 {
342962398d3Sdanielk1977  execsql {
343962398d3Sdanielk1977    BEGIN;
344962398d3Sdanielk1977    DROP TABLE aux.tbl;
345962398d3Sdanielk1977    DROP TABLE tbl;
346962398d3Sdanielk1977    ROLLBACK;
347962398d3Sdanielk1977  }
348962398d3Sdanielk1977} {}
349962398d3Sdanielk1977do_test attach2-5.5 {
35057790b8fSdrh  lsort [glob test.db*]
351962398d3Sdanielk1977} {test.db test.db2}
352962398d3Sdanielk1977
35392f9a1bbSdanielk1977# Check that a database cannot be ATTACHed or DETACHed during a transaction.
35492f9a1bbSdanielk1977do_test attach2-6.1 {
35592f9a1bbSdanielk1977  execsql {
35692f9a1bbSdanielk1977    BEGIN;
35792f9a1bbSdanielk1977  }
35892f9a1bbSdanielk1977} {}
35992f9a1bbSdanielk1977do_test attach2-6.2 {
36092f9a1bbSdanielk1977  catchsql {
36192f9a1bbSdanielk1977    ATTACH 'test3.db' as aux2;
36292f9a1bbSdanielk1977  }
36392f9a1bbSdanielk1977} {1 {cannot ATTACH database within transaction}}
36492f9a1bbSdanielk1977
36592f9a1bbSdanielk1977do_test attach2-6.3 {
36692f9a1bbSdanielk1977  catchsql {
36792f9a1bbSdanielk1977    DETACH aux;
36892f9a1bbSdanielk1977  }
36992f9a1bbSdanielk1977} {1 {cannot DETACH database within transaction}}
37092f9a1bbSdanielk1977do_test attach2-6.4 {
37192f9a1bbSdanielk1977  execsql {
37292f9a1bbSdanielk1977    COMMIT;
37392f9a1bbSdanielk1977    DETACH aux;
37492f9a1bbSdanielk1977  }
37592f9a1bbSdanielk1977} {}
37692f9a1bbSdanielk1977
377962398d3Sdanielk1977db close
378962398d3Sdanielk1977
3793c8bf55aSdrhfinish_test
380