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