1# 2003 April 4 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: attach.test,v 1.11 2003/07/18 01:25:35 drh Exp $ 16# 17 18set testdir [file dirname $argv0] 19source $testdir/tester.tcl 20 21for {set i 2} {$i<=15} {incr i} { 22 file delete -force test$i.db 23 file delete -force test$i.db-journal 24} 25 26do_test attach-1.1 { 27 execsql { 28 CREATE TABLE t1(a,b); 29 INSERT INTO t1 VALUES(1,2); 30 INSERT INTO t1 VALUES(3,4); 31 SELECT * FROM t1; 32 } 33} {1 2 3 4} 34do_test attach-1.2 { 35 sqlite db2 test2.db 36 execsql { 37 CREATE TABLE t2(x,y); 38 INSERT INTO t2 VALUES(1,'x'); 39 INSERT INTO t2 VALUES(2,'y'); 40 SELECT * FROM t2; 41 } db2 42} {1 x 2 y} 43do_test attach-1.3 { 44 execsql { 45 ATTACH DATABASE 'test2.db' AS two; 46 SELECT * FROM two.t2; 47 } 48} {1 x 2 y} 49do_test attach-1.4 { 50 execsql { 51 SELECT * FROM t2; 52 } 53} {1 x 2 y} 54do_test attach-1.5 { 55 execsql { 56 DETACH DATABASE two; 57 SELECT * FROM t1; 58 } 59} {1 2 3 4} 60do_test attach-1.6 { 61 catchsql { 62 SELECT * FROM t2; 63 } 64} {1 {no such table: t2}} 65do_test attach-1.7 { 66 catchsql { 67 SELECT * FROM two.t2; 68 } 69} {1 {no such table: two.t2}} 70do_test attach-1.8 { 71 catchsql { 72 ATTACH DATABASE 'test3.db' AS three; 73 } 74} {1 {cannot attach empty database: three}} 75do_test attach-1.9 { 76 catchsql { 77 SELECT * FROM three.sqlite_master; 78 } 79} {1 {no such table: three.sqlite_master}} 80do_test attach-1.10 { 81 catchsql { 82 DETACH DATABASE three; 83 } 84} {1 {no such database: three}} 85do_test attach-1.11 { 86 execsql { 87 ATTACH 'test.db' AS db2; 88 ATTACH 'test.db' AS db3; 89 ATTACH 'test.db' AS db4; 90 ATTACH 'test.db' AS db5; 91 ATTACH 'test.db' AS db6; 92 ATTACH 'test.db' AS db7; 93 ATTACH 'test.db' AS db8; 94 ATTACH 'test.db' AS db9; 95 } 96} {} 97proc db_list {db} { 98 set list {} 99 foreach {idx name file} [execsql {PRAGMA database_list} $db] { 100 lappend list $idx $name 101 } 102 return $list 103} 104do_test attach-1.11b { 105 db_list db 106} {0 main 1 temp 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9} 107do_test attach-1.12 { 108 catchsql { 109 ATTACH 'test.db' as db2; 110 } 111} {1 {database db2 is already in use}} 112do_test attach-1.13 { 113 catchsql { 114 ATTACH 'test.db' as db5; 115 } 116} {1 {database db5 is already in use}} 117do_test attach-1.14 { 118 catchsql { 119 ATTACH 'test.db' as db9; 120 } 121} {1 {database db9 is already in use}} 122do_test attach-1.15 { 123 catchsql { 124 ATTACH 'test.db' as main; 125 } 126} {1 {database main is already in use}} 127do_test attach-1.16 { 128 catchsql { 129 ATTACH 'test.db' as temp; 130 } 131} {1 {database temp is already in use}} 132do_test attach-1.17 { 133 catchsql { 134 ATTACH 'test.db' as MAIN; 135 } 136} {1 {database MAIN is already in use}} 137do_test attach-1.18 { 138 catchsql { 139 ATTACH 'test.db' as db10; 140 ATTACH 'test.db' as db11; 141 } 142} {0 {}} 143do_test attach-1.19 { 144 catchsql { 145 ATTACH 'test.db' as db12; 146 } 147} {1 {too many attached databases - max 10}} 148do_test attach-1.20.1 { 149 execsql { 150 DETACH db5; 151 } 152 db_list db 153} {0 main 1 temp 2 db2 3 db3 4 db4 5 db11 6 db6 7 db7 8 db8 9 db9 10 db10} 154integrity_check attach-1.20.2 155do_test attach-1.21 { 156 catchsql { 157 ATTACH 'test.db' as db12; 158 } 159} {0 {}} 160do_test attach-1.22 { 161 catchsql { 162 ATTACH 'test.db' as db13; 163 } 164} {1 {too many attached databases - max 10}} 165do_test attach-1.23 { 166 catchsql { 167 DETACH db14; 168 } 169} {1 {no such database: db14}} 170do_test attach-1.24 { 171 catchsql { 172 DETACH db12; 173 } 174} {0 {}} 175do_test attach-1.25 { 176 catchsql { 177 DETACH db12; 178 } 179} {1 {no such database: db12}} 180do_test attach-1.26 { 181 catchsql { 182 DETACH main; 183 } 184} {1 {cannot detach database main}} 185do_test attach-1.27 { 186 catchsql { 187 DETACH Temp; 188 } 189} {1 {cannot detach database Temp}} 190do_test attach-1.28 { 191 catchsql { 192 DETACH db11; 193 DETACH db10; 194 DETACH db9; 195 DETACH db8; 196 DETACH db7; 197 DETACH db6; 198 DETACH db4; 199 DETACH db3; 200 DETACH db2; 201 } 202} {0 {}} 203do_test attach-1.29 { 204 db_list db 205} {0 main 1 temp} 206 207do_test attach-2.1 { 208 execsql { 209 CREATE TABLE tx(x1,x2,y1,y2); 210 CREATE TRIGGER r1 AFTER UPDATE ON t2 FOR EACH ROW BEGIN 211 INSERT INTO tx(x1,x2,y1,y2) VALUES(OLD.x,NEW.x,OLD.y,NEW.y); 212 END; 213 SELECT * FROM tx; 214 } db2; 215} {} 216do_test attach-2.2 { 217 execsql { 218 UPDATE t2 SET x=x+10; 219 SELECT * FROM tx; 220 } db2; 221} {1 11 x x 2 12 y y} 222do_test attach-2.3 { 223 execsql { 224 CREATE TABLE tx(x1,x2,y1,y2); 225 SELECT * FROM tx; 226 } 227} {} 228do_test attach-2.4 { 229 execsql { 230 ATTACH 'test2.db' AS db2; 231 } 232} {} 233do_test attach-2.5 { 234 execsql { 235 UPDATE db2.t2 SET x=x+10; 236 SELECT * FROM db2.tx; 237 } 238} {1 11 x x 2 12 y y 11 21 x x 12 22 y y} 239do_test attach-2.6 { 240 execsql { 241 SELECT * FROM main.tx; 242 } 243} {} 244do_test attach-2.7 { 245 execsql { 246 SELECT type, name, tbl_name FROM db2.sqlite_master; 247 } 248} {table t2 t2 table tx tx trigger r1 t2} 249do_test attach-2.8 { 250 db_list db 251} {0 main 1 temp 2 db2} 252do_test attach-2.9 { 253 execsql { 254 CREATE INDEX i2 ON t2(x); 255 SELECT * FROM t2 WHERE x>5; 256 } db2 257} {21 x 22 y} 258do_test attach-2.10 { 259 execsql { 260 SELECT type, name, tbl_name FROM sqlite_master; 261 } db2 262} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} 263do_test attach-2.11 { 264 catchsql { 265 SELECT * FROM t2 WHERE x>5; 266 } 267} {1 {database schema has changed}} 268do_test attach-2.12 { 269 db_list db 270} {0 main 1 temp 2 db2} 271do_test attach-2.13 { 272 catchsql { 273 SELECT * FROM t2 WHERE x>5; 274 } 275} {0 {21 x 22 y}} 276do_test attach-2.14 { 277 execsql { 278 SELECT type, name, tbl_name FROM sqlite_master; 279 } 280} {table t1 t1 table tx tx} 281do_test attach-2.15 { 282 execsql { 283 SELECT type, name, tbl_name FROM db2.sqlite_master; 284 } 285} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} 286do_test attach-2.16 { 287 db close 288 sqlite db test.db 289 execsql { 290 ATTACH 'test2.db' AS db2; 291 SELECT type, name, tbl_name FROM db2.sqlite_master; 292 } 293} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} 294 295do_test attach-3.1 { 296 db close 297 db2 close 298 sqlite db test.db 299 sqlite db2 test2.db 300 execsql { 301 SELECT * FROM t1 302 } 303} {1 2 3 4} 304do_test attach-3.2 { 305 catchsql { 306 SELECT * FROM t2 307 } 308} {1 {no such table: t2}} 309do_test attach-3.3 { 310 catchsql { 311 ATTACH DATABASE 'test2.db' AS db2; 312 SELECT * FROM t2 313 } 314} {0 {21 x 22 y}} 315 316# Even though main has a transaction, test2.db should not be locked. 317do_test attach-3.4 { 318 execsql BEGIN 319 catchsql { 320 SELECT * FROM t2; 321 } db2; 322} {0 {21 x 22 y}} 323 324# Reading from db2 should not lock test2.db 325do_test attach-3.5 { 326 execsql {SELECT * FROM t2} 327 catchsql { 328 SELECT * FROM t2; 329 } db2; 330} {0 {21 x 22 y}} 331 332# Making a change to db2 causes test2.ddb to become locked. 333do_test attach-3.6 { 334 execsql { 335 UPDATE t2 SET x=x+1 WHERE x=50; 336 } 337 catchsql { 338 SELECT * FROM t2; 339 } db2; 340} {1 {database is locked}} 341 342do_test attach-3.7 { 343 execsql ROLLBACK 344 execsql {SELECT * FROM t2} db2 345} {21 x 22 y} 346do_test attach-3.8 { 347 execsql BEGIN 348 execsql BEGIN db2 349 catchsql {SELECT * FROM t2} 350} {1 {database is locked}} 351do_test attach-3.9 { 352 catchsql {SELECT * FROM t2} db2 353} {0 {21 x 22 y}} 354do_test attach-3.10 { 355 execsql {SELECT * FROM t1} 356} {1 2 3 4} 357do_test attach-3.11 { 358 catchsql {UPDATE t1 SET a=a+1} 359} {0 {}} 360do_test attach-3.12 { 361 execsql {SELECT * FROM t1} 362} {2 2 4 4} 363do_test attach-3.13 { 364 catchsql {UPDATE t2 SET x=x+1 WHERE x=50} 365} {1 {database is locked}} 366do_test attach-3.14 { 367 # the "database is locked" error on the previous test should have 368 # caused a rollback. 369 execsql {SELECT * FROM t1} 370} {1 2 3 4} 371 372# Ticket #323 373do_test attach-4.1 { 374 execsql {DETACH db2} 375 db2 close 376 sqlite db2 test2.db 377 execsql { 378 CREATE TABLE t3(x,y); 379 CREATE UNIQUE INDEX t3i1 ON t3(x); 380 INSERT INTO t3 VALUES(1,2); 381 SELECT * FROM t3; 382 } db2; 383} {1 2} 384do_test attach-4.2 { 385 execsql { 386 CREATE TABLE t3(a,b); 387 CREATE UNIQUE INDEX t3i1b ON t3(a); 388 INSERT INTO t3 VALUES(9,10); 389 SELECT * FROM t3; 390 } 391} {9 10} 392do_test attach-4.3 { 393 execsql { 394 ATTACH DATABASE 'test2.db' AS db2; 395 SELECT * FROM db2.t3; 396 } 397} {1 2} 398do_test attach-4.4 { 399 execsql { 400 SELECT * FROM main.t3; 401 } 402} {9 10} 403do_test attach-4.5 { 404 execsql { 405 INSERT INTO db2.t3 VALUES(9,10); 406 SELECT * FROM db2.t3; 407 } 408} {1 2 9 10} 409do_test attach-4.6 { 410 execsql { 411 DETACH db2; 412 } 413 execsql { 414 CREATE TABLE t4(x); 415 CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN 416 INSERT INTO t4 VALUES('db2.' || NEW.x); 417 END; 418 INSERT INTO t3 VALUES(6,7); 419 SELECT * FROM t4; 420 } db2 421} {db2.6} 422do_test attach-4.7 { 423 execsql { 424 CREATE TABLE t4(y); 425 CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN 426 INSERT INTO t4 VALUES('main.' || NEW.a); 427 END; 428 INSERT INTO main.t3 VALUES(11,12); 429 SELECT * FROM main.t4; 430 } 431} {main.11} 432do_test attach-4.8 { 433 execsql { 434 ATTACH DATABASE 'test2.db' AS db2; 435 INSERT INTO db2.t3 VALUES(13,14); 436 SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4; 437 } 438} {db2.6 db2.13 main.11} 439do_test attach-4.9 { 440 execsql { 441 INSERT INTO main.t3 VALUES(15,16); 442 SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4; 443 } 444} {db2.6 db2.13 main.11 main.15} 445do_test attach-4.10 { 446 execsql { 447 DETACH DATABASE db2; 448 } 449 execsql { 450 CREATE VIEW v3 AS SELECT x*100+y FROM t3; 451 SELECT * FROM v3; 452 } db2 453} {102 910 607 1314} 454do_test attach-4.11 { 455 execsql { 456 CREATE VIEW v3 AS SELECT a*100+b FROM t3; 457 SELECT * FROM v3; 458 } 459} {910 1112 1516} 460do_test attach-4.12 { 461 execsql { 462 ATTACH DATABASE 'test2.db' AS db2; 463 SELECT * FROM db2.v3; 464 } 465} {102 910 607 1314} 466do_test attach-4.13 { 467 execsql { 468 SELECT * FROM main.v3; 469 } 470} {910 1112 1516} 471 472# Tests for the sqliteFix...() routines in attach.c 473# 474do_test attach-5.1 { 475 db close 476 sqlite db test.db 477 db2 close 478 file delete -force test2.db 479 sqlite db2 test2.db 480 catchsql { 481 ATTACH DATABASE 'test.db' AS orig; 482 CREATE TRIGGER r1 AFTER INSERT ON orig.t1 BEGIN; 483 SELECT 'no-op'; 484 END; 485 } db2 486} {1 {triggers may not be added to auxiliary database orig}} 487do_test attach-5.2 { 488 catchsql { 489 CREATE TABLE t5(x,y); 490 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 491 SELECT 'no-op'; 492 END; 493 } db2 494} {0 {}} 495do_test attach-5.3 { 496 catchsql { 497 DROP TRIGGER r5; 498 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 499 SELECT 'no-op' FROM orig.t1; 500 END; 501 } db2 502} {1 {trigger r5 cannot reference objects in database orig}} 503do_test attach-5.4 { 504 catchsql { 505 CREATE TEMP TABLE t6(p,q,r); 506 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 507 SELECT 'no-op' FROM temp.t6; 508 END; 509 } db2 510} {1 {trigger r5 cannot reference objects in database temp}} 511do_test attach-5.5 { 512 catchsql { 513 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 514 SELECT 'no-op' || (SELECT * FROM temp.t6); 515 END; 516 } db2 517} {1 {trigger r5 cannot reference objects in database temp}} 518do_test attach-5.6 { 519 catchsql { 520 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 521 SELECT 'no-op' FROM t1 WHERE x<(SELECT min(x) FROM temp.t6); 522 END; 523 } db2 524} {1 {trigger r5 cannot reference objects in database temp}} 525do_test attach-5.7 { 526 catchsql { 527 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 528 SELECT 'no-op' FROM t1 GROUP BY 1 HAVING x<(SELECT min(x) FROM temp.t6); 529 END; 530 } db2 531} {1 {trigger r5 cannot reference objects in database temp}} 532do_test attach-5.7 { 533 catchsql { 534 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 535 SELECT max(1,x,(SELECT min(x) FROM temp.t6)) FROM t1; 536 END; 537 } db2 538} {1 {trigger r5 cannot reference objects in database temp}} 539do_test attach-5.8 { 540 catchsql { 541 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 542 INSERT INTO t1 VALUES((SELECT min(x) FROM temp.t6),5); 543 END; 544 } db2 545} {1 {trigger r5 cannot reference objects in database temp}} 546do_test attach-5.9 { 547 catchsql { 548 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 549 DELETE FROM t1 WHERE x<(SELECT min(x) FROM temp.t6); 550 END; 551 } db2 552} {1 {trigger r5 cannot reference objects in database temp}} 553 554# Check to make sure we get a sensible error if unable to open 555# the file that we are trying to attach. 556# 557do_test attach-6.1 { 558 catchsql { 559 ATTACH DATABASE 'no-such-file' AS nosuch; 560 } 561} {1 {cannot attach empty database: nosuch}} 562file delete -force no-such-file 563if {$tcl_platform(platform)=="unix"} { 564 do_test attach-6.2 { 565 sqlite dbx cannot-read 566 dbx eval {CREATE TABLE t1(a,b,c)} 567 dbx close 568 file attributes cannot-read -permission 0000 569 catchsql { 570 ATTACH DATABASE 'cannot-read' AS noread; 571 } 572 } {1 {unable to open database: cannot-read}} 573 file delete -force cannot-read 574} 575 576for {set i 2} {$i<=15} {incr i} { 577 catch {db$i close} 578} 579file delete -force test2.db 580 581 582finish_test 583