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