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.47 2007/10/09 08:29:32 danielk1977 Exp $ 16# 17 18set testdir [file dirname $argv0] 19source $testdir/tester.tcl 20 21ifcapable !attach { 22 finish_test 23 return 24} 25 26for {set i 2} {$i<=15} {incr i} { 27 file delete -force test$i.db 28 file delete -force test$i.db-journal 29} 30 31set btree_trace 0 32do_test attach-1.1 { 33 execsql { 34 CREATE TABLE t1(a,b); 35 INSERT INTO t1 VALUES(1,2); 36 INSERT INTO t1 VALUES(3,4); 37 SELECT * FROM t1; 38 } 39} {1 2 3 4} 40do_test attach-1.2 { 41 sqlite3 db2 test2.db 42 execsql { 43 CREATE TABLE t2(x,y); 44 INSERT INTO t2 VALUES(1,'x'); 45 INSERT INTO t2 VALUES(2,'y'); 46 SELECT * FROM t2; 47 } db2 48} {1 x 2 y} 49do_test attach-1.3 { 50 execsql { 51 ATTACH DATABASE 'test2.db' AS two; 52 SELECT * FROM two.t2; 53 } 54} {1 x 2 y} 55do_test attach-1.4 { 56 execsql { 57 SELECT * FROM t2; 58 } 59} {1 x 2 y} 60do_test attach-1.5 { 61btree_breakpoint 62 execsql { 63 DETACH DATABASE two; 64 SELECT * FROM t1; 65 } 66} {1 2 3 4} 67do_test attach-1.6 { 68 catchsql { 69 SELECT * FROM t2; 70 } 71} {1 {no such table: t2}} 72do_test attach-1.7 { 73 catchsql { 74 SELECT * FROM two.t2; 75 } 76} {1 {no such table: two.t2}} 77do_test attach-1.8 { 78 catchsql { 79 ATTACH DATABASE 'test3.db' AS three; 80 } 81} {0 {}} 82do_test attach-1.9 { 83 catchsql { 84 SELECT * FROM three.sqlite_master; 85 } 86} {0 {}} 87do_test attach-1.10 { 88 catchsql { 89 DETACH DATABASE [three]; 90 } 91} {0 {}} 92do_test attach-1.11 { 93 execsql { 94 ATTACH 'test.db' AS db2; 95 ATTACH 'test.db' AS db3; 96 ATTACH 'test.db' AS db4; 97 ATTACH 'test.db' AS db5; 98 ATTACH 'test.db' AS db6; 99 ATTACH 'test.db' AS db7; 100 ATTACH 'test.db' AS db8; 101 ATTACH 'test.db' AS db9; 102 } 103} {} 104proc db_list {db} { 105 set list {} 106 foreach {idx name file} [execsql {PRAGMA database_list} $db] { 107 lappend list $idx $name 108 } 109 return $list 110} 111ifcapable schema_pragmas { 112do_test attach-1.11b { 113 db_list db 114} {0 main 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9} 115} ;# ifcapable schema_pragmas 116do_test attach-1.12 { 117 catchsql { 118 ATTACH 'test.db' as db2; 119 } 120} {1 {database db2 is already in use}} 121do_test attach-1.13 { 122 catchsql { 123 ATTACH 'test.db' as db5; 124 } 125} {1 {database db5 is already in use}} 126do_test attach-1.14 { 127 catchsql { 128 ATTACH 'test.db' as db9; 129 } 130} {1 {database db9 is already in use}} 131do_test attach-1.15 { 132 catchsql { 133 ATTACH 'test.db' as main; 134 } 135} {1 {database main is already in use}} 136ifcapable tempdb { 137 do_test attach-1.16 { 138 catchsql { 139 ATTACH 'test.db' as temp; 140 } 141 } {1 {database temp is already in use}} 142} 143do_test attach-1.17 { 144 catchsql { 145 ATTACH 'test.db' as MAIN; 146 } 147} {1 {database MAIN is already in use}} 148do_test attach-1.18 { 149 catchsql { 150 ATTACH 'test.db' as db10; 151 ATTACH 'test.db' as db11; 152 } 153} {0 {}} 154do_test attach-1.19 { 155 catchsql { 156 ATTACH 'test.db' as db12; 157 } 158} {1 {too many attached databases - max 10}} 159do_test attach-1.20.1 { 160 execsql { 161 DETACH db5; 162 } 163} {} 164ifcapable schema_pragmas { 165do_test attach-1.20.2 { 166 db_list db 167} {0 main 2 db2 3 db3 4 db4 5 db6 6 db7 7 db8 8 db9 9 db10 10 db11} 168} ;# ifcapable schema_pragmas 169integrity_check attach-1.20.3 170ifcapable tempdb { 171 execsql {select * from sqlite_temp_master} 172} 173do_test attach-1.21 { 174 catchsql { 175 ATTACH 'test.db' as db12; 176 } 177} {0 {}} 178do_test attach-1.22 { 179 catchsql { 180 ATTACH 'test.db' as db13; 181 } 182} {1 {too many attached databases - max 10}} 183do_test attach-1.23 { 184 catchsql { 185 DETACH "db14"; 186 } 187} {1 {no such database: db14}} 188do_test attach-1.24 { 189 catchsql { 190 DETACH db12; 191 } 192} {0 {}} 193do_test attach-1.25 { 194 catchsql { 195 DETACH db12; 196 } 197} {1 {no such database: db12}} 198do_test attach-1.26 { 199 catchsql { 200 DETACH main; 201 } 202} {1 {cannot detach database main}} 203 204ifcapable tempdb { 205 do_test attach-1.27 { 206 catchsql { 207 DETACH Temp; 208 } 209 } {1 {cannot detach database Temp}} 210} else { 211 do_test attach-1.27 { 212 catchsql { 213 DETACH Temp; 214 } 215 } {1 {no such database: Temp}} 216} 217 218do_test attach-1.28 { 219 catchsql { 220 DETACH db11; 221 DETACH db10; 222 DETACH db9; 223 DETACH db8; 224 DETACH db7; 225 DETACH db6; 226 DETACH db4; 227 DETACH db3; 228 DETACH db2; 229 } 230} {0 {}} 231ifcapable schema_pragmas { 232 ifcapable tempdb { 233 do_test attach-1.29 { 234 db_list db 235 } {0 main 1 temp} 236 } else { 237 do_test attach-1.29 { 238 db_list db 239 } {0 main} 240 } 241} ;# ifcapable schema_pragmas 242 243ifcapable {trigger} { # Only do the following tests if triggers are enabled 244do_test attach-2.1 { 245 execsql { 246 CREATE TABLE tx(x1,x2,y1,y2); 247 CREATE TRIGGER r1 AFTER UPDATE ON t2 FOR EACH ROW BEGIN 248 INSERT INTO tx(x1,x2,y1,y2) VALUES(OLD.x,NEW.x,OLD.y,NEW.y); 249 END; 250 SELECT * FROM tx; 251 } db2; 252} {} 253do_test attach-2.2 { 254 execsql { 255 UPDATE t2 SET x=x+10; 256 SELECT * FROM tx; 257 } db2; 258} {1 11 x x 2 12 y y} 259do_test attach-2.3 { 260 execsql { 261 CREATE TABLE tx(x1,x2,y1,y2); 262 SELECT * FROM tx; 263 } 264} {} 265do_test attach-2.4 { 266 execsql { 267 ATTACH 'test2.db' AS db2; 268 } 269} {} 270do_test attach-2.5 { 271 execsql { 272 UPDATE db2.t2 SET x=x+10; 273 SELECT * FROM db2.tx; 274 } 275} {1 11 x x 2 12 y y 11 21 x x 12 22 y y} 276do_test attach-2.6 { 277 execsql { 278 SELECT * FROM main.tx; 279 } 280} {} 281do_test attach-2.7 { 282 execsql { 283 SELECT type, name, tbl_name FROM db2.sqlite_master; 284 } 285} {table t2 t2 table tx tx trigger r1 t2} 286 287ifcapable schema_pragmas&&tempdb { 288 do_test attach-2.8 { 289 db_list db 290 } {0 main 1 temp 2 db2} 291} ;# ifcapable schema_pragmas&&tempdb 292ifcapable schema_pragmas&&!tempdb { 293 do_test attach-2.8 { 294 db_list db 295 } {0 main 2 db2} 296} ;# ifcapable schema_pragmas&&!tempdb 297 298do_test attach-2.9 { 299 execsql { 300 CREATE INDEX i2 ON t2(x); 301 SELECT * FROM t2 WHERE x>5; 302 } db2 303} {21 x 22 y} 304do_test attach-2.10 { 305 execsql { 306 SELECT type, name, tbl_name FROM sqlite_master; 307 } db2 308} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} 309#do_test attach-2.11 { 310# catchsql { 311# SELECT * FROM t2 WHERE x>5; 312# } 313#} {1 {database schema has changed}} 314ifcapable schema_pragmas { 315 ifcapable tempdb { 316 do_test attach-2.12 { 317 db_list db 318 } {0 main 1 temp 2 db2} 319 } else { 320 do_test attach-2.12 { 321 db_list db 322 } {0 main 2 db2} 323 } 324} ;# ifcapable schema_pragmas 325do_test attach-2.13 { 326 catchsql { 327 SELECT * FROM t2 WHERE x>5; 328 } 329} {0 {21 x 22 y}} 330do_test attach-2.14 { 331 execsql { 332 SELECT type, name, tbl_name FROM sqlite_master; 333 } 334} {table t1 t1 table tx tx} 335do_test attach-2.15 { 336 execsql { 337 SELECT type, name, tbl_name FROM db2.sqlite_master; 338 } 339} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} 340do_test attach-2.16 { 341 db close 342 sqlite3 db test.db 343 execsql { 344 ATTACH 'test2.db' AS db2; 345 SELECT type, name, tbl_name FROM db2.sqlite_master; 346 } 347} {table t2 t2 table tx tx trigger r1 t2 index i2 t2} 348} ;# End of ifcapable {trigger} 349 350do_test attach-3.1 { 351 db close 352 db2 close 353 sqlite3 db test.db 354 sqlite3 db2 test2.db 355 execsql { 356 SELECT * FROM t1 357 } 358} {1 2 3 4} 359 360# If we are testing a version of the code that lacks trigger support, 361# adjust the database contents so that they are the same if triggers 362# had been enabled. 363ifcapable {!trigger} { 364 db2 eval { 365 DELETE FROM t2; 366 INSERT INTO t2 VALUES(21, 'x'); 367 INSERT INTO t2 VALUES(22, 'y'); 368 CREATE TABLE tx(x1,x2,y1,y2); 369 INSERT INTO tx VALUES(1, 11, 'x', 'x'); 370 INSERT INTO tx VALUES(2, 12, 'y', 'y'); 371 INSERT INTO tx VALUES(11, 21, 'x', 'x'); 372 INSERT INTO tx VALUES(12, 22, 'y', 'y'); 373 CREATE INDEX i2 ON t2(x); 374 } 375} 376 377do_test attach-3.2 { 378 catchsql { 379 SELECT * FROM t2 380 } 381} {1 {no such table: t2}} 382do_test attach-3.3 { 383 catchsql { 384 ATTACH DATABASE 'test2.db' AS db2; 385 SELECT * FROM t2 386 } 387} {0 {21 x 22 y}} 388 389# Even though 'db' has started a transaction, it should not yet have 390# a lock on test2.db so 'db2' should be readable. 391do_test attach-3.4 { 392 execsql BEGIN 393 catchsql { 394 SELECT * FROM t2; 395 } db2; 396} {0 {21 x 22 y}} 397 398# Reading from test2.db from db within a transaction should not 399# prevent test2.db from being read by db2. 400do_test attach-3.5 { 401 execsql {SELECT * FROM t2} 402btree_breakpoint 403 catchsql { 404 SELECT * FROM t2; 405 } db2; 406} {0 {21 x 22 y}} 407 408# Making a change to test2.db through db causes test2.db to get 409# a reserved lock. It should still be accessible through db2. 410do_test attach-3.6 { 411 execsql { 412 UPDATE t2 SET x=x+1 WHERE x=50; 413 } 414 catchsql { 415 SELECT * FROM t2; 416 } db2; 417} {0 {21 x 22 y}} 418 419do_test attach-3.7 { 420 execsql ROLLBACK 421 execsql {SELECT * FROM t2} db2 422} {21 x 22 y} 423 424# Start transactions on both db and db2. Once again, just because 425# we make a change to test2.db using db2, only a RESERVED lock is 426# obtained, so test2.db should still be readable using db. 427# 428do_test attach-3.8 { 429 execsql BEGIN 430 execsql BEGIN db2 431 execsql {UPDATE t2 SET x=0 WHERE 0} db2 432 catchsql {SELECT * FROM t2} 433} {0 {21 x 22 y}} 434 435# It is also still accessible from db2. 436do_test attach-3.9 { 437 catchsql {SELECT * FROM t2} db2 438} {0 {21 x 22 y}} 439 440do_test attach-3.10 { 441 execsql {SELECT * FROM t1} 442} {1 2 3 4} 443 444do_test attach-3.11 { 445 catchsql {UPDATE t1 SET a=a+1} 446} {0 {}} 447do_test attach-3.12 { 448 execsql {SELECT * FROM t1} 449} {2 2 4 4} 450 451# db2 has a RESERVED lock on test2.db, so db cannot write to any tables 452# in test2.db. 453do_test attach-3.13 { 454 catchsql {UPDATE t2 SET x=x+1 WHERE x=50} 455} {1 {database is locked}} 456 457# Change for version 3. Transaction is no longer rolled back 458# for a locked database. 459execsql {ROLLBACK} 460 461# db is able to reread its schema because db2 still only holds a 462# reserved lock. 463do_test attach-3.14 { 464 catchsql {SELECT * FROM t1} 465} {0 {1 2 3 4}} 466do_test attach-3.15 { 467 execsql COMMIT db2 468 execsql {SELECT * FROM t1} 469} {1 2 3 4} 470 471#set btree_trace 1 472 473# Ticket #323 474do_test attach-4.1 { 475 execsql {DETACH db2} 476 db2 close 477 sqlite3 db2 test2.db 478 execsql { 479 CREATE TABLE t3(x,y); 480 CREATE UNIQUE INDEX t3i1 ON t3(x); 481 INSERT INTO t3 VALUES(1,2); 482 SELECT * FROM t3; 483 } db2; 484} {1 2} 485do_test attach-4.2 { 486 execsql { 487 CREATE TABLE t3(a,b); 488 CREATE UNIQUE INDEX t3i1b ON t3(a); 489 INSERT INTO t3 VALUES(9,10); 490 SELECT * FROM t3; 491 } 492} {9 10} 493do_test attach-4.3 { 494 execsql { 495 ATTACH DATABASE 'test2.db' AS db2; 496 SELECT * FROM db2.t3; 497 } 498} {1 2} 499do_test attach-4.4 { 500 execsql { 501 SELECT * FROM main.t3; 502 } 503} {9 10} 504do_test attach-4.5 { 505 execsql { 506 INSERT INTO db2.t3 VALUES(9,10); 507 SELECT * FROM db2.t3; 508 } 509} {1 2 9 10} 510execsql { 511 DETACH db2; 512} 513ifcapable {trigger} { 514 do_test attach-4.6 { 515 execsql { 516 CREATE TABLE t4(x); 517 CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN 518 INSERT INTO t4 VALUES('db2.' || NEW.x); 519 END; 520 INSERT INTO t3 VALUES(6,7); 521 SELECT * FROM t4; 522 } db2 523 } {db2.6} 524 do_test attach-4.7 { 525 execsql { 526 CREATE TABLE t4(y); 527 CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN 528 INSERT INTO t4 VALUES('main.' || NEW.a); 529 END; 530 INSERT INTO main.t3 VALUES(11,12); 531 SELECT * FROM main.t4; 532 } 533 } {main.11} 534} 535ifcapable {!trigger} { 536 # When we do not have trigger support, set up the table like they 537 # would have been had triggers been there. The tests that follow need 538 # this setup. 539 execsql { 540 CREATE TABLE t4(x); 541 INSERT INTO t3 VALUES(6,7); 542 INSERT INTO t4 VALUES('db2.6'); 543 INSERT INTO t4 VALUES('db2.13'); 544 } db2 545 execsql { 546 CREATE TABLE t4(y); 547 INSERT INTO main.t3 VALUES(11,12); 548 INSERT INTO t4 VALUES('main.11'); 549 } 550} 551 552 553# This one is tricky. On the UNION ALL select, we have to make sure 554# the schema for both main and db2 is valid before starting to execute 555# the first query of the UNION ALL. If we wait to test the validity of 556# the schema for main until after the first query has run, that test will 557# fail and the query will abort but we will have already output some 558# results. When the query is retried, the results will be repeated. 559# 560ifcapable compound { 561do_test attach-4.8 { 562 execsql { 563 ATTACH DATABASE 'test2.db' AS db2; 564 INSERT INTO db2.t3 VALUES(13,14); 565 SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4; 566 } 567} {db2.6 db2.13 main.11} 568 569do_test attach-4.9 { 570 ifcapable {!trigger} {execsql {INSERT INTO main.t4 VALUES('main.15')}} 571 execsql { 572 INSERT INTO main.t3 VALUES(15,16); 573 SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4; 574 } 575} {db2.6 db2.13 main.11 main.15} 576} ;# ifcapable compound 577 578ifcapable !compound { 579 ifcapable {!trigger} {execsql {INSERT INTO main.t4 VALUES('main.15')}} 580 execsql { 581 ATTACH DATABASE 'test2.db' AS db2; 582 INSERT INTO db2.t3 VALUES(13,14); 583 INSERT INTO main.t3 VALUES(15,16); 584 } 585} ;# ifcapable !compound 586 587ifcapable view { 588do_test attach-4.10 { 589 execsql { 590 DETACH DATABASE db2; 591 } 592 execsql { 593 CREATE VIEW v3 AS SELECT x*100+y FROM t3; 594 SELECT * FROM v3; 595 } db2 596} {102 910 607 1314} 597do_test attach-4.11 { 598 execsql { 599 CREATE VIEW v3 AS SELECT a*100+b FROM t3; 600 SELECT * FROM v3; 601 } 602} {910 1112 1516} 603do_test attach-4.12 { 604 execsql { 605 ATTACH DATABASE 'test2.db' AS db2; 606 SELECT * FROM db2.v3; 607 } 608} {102 910 607 1314} 609do_test attach-4.13 { 610 execsql { 611 SELECT * FROM main.v3; 612 } 613} {910 1112 1516} 614} ;# ifcapable view 615 616# Tests for the sqliteFix...() routines in attach.c 617# 618ifcapable {trigger} { 619do_test attach-5.1 { 620 db close 621 sqlite3 db test.db 622 db2 close 623 file delete -force test2.db 624 sqlite3 db2 test2.db 625 catchsql { 626 ATTACH DATABASE 'test.db' AS orig; 627 CREATE TRIGGER r1 AFTER INSERT ON orig.t1 BEGIN 628 SELECT 'no-op'; 629 END; 630 } db2 631} {1 {trigger r1 cannot reference objects in database orig}} 632do_test attach-5.2 { 633 catchsql { 634 CREATE TABLE t5(x,y); 635 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 636 SELECT 'no-op'; 637 END; 638 } db2 639} {0 {}} 640do_test attach-5.3 { 641 catchsql { 642 DROP TRIGGER r5; 643 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 644 SELECT 'no-op' FROM orig.t1; 645 END; 646 } db2 647} {1 {trigger r5 cannot reference objects in database orig}} 648ifcapable tempdb { 649 do_test attach-5.4 { 650 catchsql { 651 CREATE TEMP TABLE t6(p,q,r); 652 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 653 SELECT 'no-op' FROM temp.t6; 654 END; 655 } db2 656 } {1 {trigger r5 cannot reference objects in database temp}} 657} 658ifcapable subquery { 659 do_test attach-5.5 { 660 catchsql { 661 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 662 SELECT 'no-op' || (SELECT * FROM temp.t6); 663 END; 664 } db2 665 } {1 {trigger r5 cannot reference objects in database temp}} 666 do_test attach-5.6 { 667 catchsql { 668 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 669 SELECT 'no-op' FROM t1 WHERE x<(SELECT min(x) FROM temp.t6); 670 END; 671 } db2 672 } {1 {trigger r5 cannot reference objects in database temp}} 673 do_test attach-5.7 { 674 catchsql { 675 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 676 SELECT 'no-op' FROM t1 GROUP BY 1 HAVING x<(SELECT min(x) FROM temp.t6); 677 END; 678 } db2 679 } {1 {trigger r5 cannot reference objects in database temp}} 680 do_test attach-5.7 { 681 catchsql { 682 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 683 SELECT max(1,x,(SELECT min(x) FROM temp.t6)) FROM t1; 684 END; 685 } db2 686 } {1 {trigger r5 cannot reference objects in database temp}} 687 do_test attach-5.8 { 688 catchsql { 689 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 690 INSERT INTO t1 VALUES((SELECT min(x) FROM temp.t6),5); 691 END; 692 } db2 693 } {1 {trigger r5 cannot reference objects in database temp}} 694 do_test attach-5.9 { 695 catchsql { 696 CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN 697 DELETE FROM t1 WHERE x<(SELECT min(x) FROM temp.t6); 698 END; 699 } db2 700 } {1 {trigger r5 cannot reference objects in database temp}} 701} ;# endif subquery 702} ;# endif trigger 703 704# Check to make sure we get a sensible error if unable to open 705# the file that we are trying to attach. 706# 707do_test attach-6.1 { 708 catchsql { 709 ATTACH DATABASE 'no-such-file' AS nosuch; 710 } 711} {0 {}} 712if {$tcl_platform(platform)=="unix"} { 713 do_test attach-6.2 { 714 sqlite3 dbx cannot-read 715 dbx eval {CREATE TABLE t1(a,b,c)} 716 dbx close 717 file attributes cannot-read -permission 0000 718 if {[file writable cannot-read]} { 719 puts "\n**** Tests do not work when run as root ****" 720 file delete -force cannot-read 721 exit 1 722 } 723 catchsql { 724 ATTACH DATABASE 'cannot-read' AS noread; 725 } 726 } {1 {unable to open database: cannot-read}} 727 file delete -force cannot-read 728} 729 730# Check the error message if we try to access a database that has 731# not been attached. 732do_test attach-6.3 { 733 catchsql { 734 CREATE TABLE no_such_db.t1(a, b, c); 735 } 736} {1 {unknown database no_such_db}} 737for {set i 2} {$i<=15} {incr i} { 738 catch {db$i close} 739} 740db close 741file delete -force test2.db 742file delete -force no-such-file 743 744ifcapable subquery { 745 do_test attach-7.1 { 746 file delete -force test.db test.db-journal 747 sqlite3 db test.db 748 catchsql { 749 DETACH RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY 750 REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL ) 751 } 752 } {1 {invalid name: "RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY 753 REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL )"}} 754} 755finish_test 756