Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Additional testing of the ATTACH command with bug fixes for the new problems that the tests found. (CVS 998) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
3e8889d7ce5e99fc855526fc1bb62ddb |
User & Date: | drh 2003-06-03 01:47:11.000 |
Context
2003-06-04
| ||
12:23 | Avoid corrupting indices when doing a REPLACE on a table with an INTEGER PRIMARY KEY that also has another index. Ticket #334. (CVS 999) (check-in: e813faae0e user: drh tags: trunk) | |
2003-06-03
| ||
01:47 | Additional testing of the ATTACH command with bug fixes for the new problems that the tests found. (CVS 998) (check-in: 3e8889d7ce user: drh tags: trunk) | |
2003-06-02
| ||
23:14 | The OP_Checkpoint opcode is now a no-op if invoked on a database that already has an active checkpoint journal. Ticket #333. (CVS 997) (check-in: daf7b94017 user: drh tags: trunk) | |
Changes
Changes to src/attach.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** ** $Id: attach.c,v 1.5 2003/06/03 01:47:11 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is called by the parser to process an ATTACH statement: ** ** ATTACH DATABASE filename AS dbname |
︙ | ︙ | |||
144 145 146 147 148 149 150 151 152 153 154 155 156 157 | const Token *pName /* Name of the view, trigger, or index */ ){ sqlite *db; if( iDb<0 || iDb==1 ) return 0; db = pParse->db; assert( db->nDb>iDb ); pFix->zDb = db->aDb[iDb].zName; pFix->zType = zType; pFix->pName = pName; return 1; } /* | > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | const Token *pName /* Name of the view, trigger, or index */ ){ sqlite *db; if( iDb<0 || iDb==1 ) return 0; db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zName; pFix->zType = zType; pFix->pName = pName; return 1; } /* |
︙ | ︙ | |||
178 179 180 181 182 183 184 | if( pList==0 ) return 0; zDb = pFix->zDb; for(i=0; i<pList->nSrc; i++){ if( pList->a[i].zDatabase==0 ){ pList->a[i].zDatabase = sqliteStrDup(zDb); }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){ sqliteErrorMsg(pFix->pParse, | | > | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | if( pList==0 ) return 0; zDb = pFix->zDb; for(i=0; i<pList->nSrc; i++){ if( pList->a[i].zDatabase==0 ){ pList->a[i].zDatabase = sqliteStrDup(zDb); }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){ sqliteErrorMsg(pFix->pParse, "%s %z cannot reference objects in database %s", pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n), pList->a[i].zDatabase); return 1; } if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1; if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1; } return 0; } |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.191 2003/06/03 01:47:11 drh Exp $ */ #include "config.h" #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" |
︙ | ︙ | |||
900 901 902 903 904 905 906 | u8 iTabDb; /* Database containing Trigger.table */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TK_BEFORE, TK_AFTER */ Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, the <column-list> is stored here */ int foreach; /* One of TK_ROW or TK_STATEMENT */ | | | 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 | u8 iTabDb; /* Database containing Trigger.table */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TK_BEFORE, TK_AFTER */ Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, the <column-list> is stored here */ int foreach; /* One of TK_ROW or TK_STATEMENT */ Token nameToken; /* Token containing zName. Use during parsing only */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ }; /* * An instance of struct TriggerStep is used to store a single SQL statement |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | int isTemp /* True if the TEMPORARY keyword is present */ ){ Trigger *nt; Table *tab; char *zName = 0; /* Name of the trigger */ sqlite *db = pParse->db; int iDb; /* When database to store the trigger in */ /* Check that: ** 1. the trigger name does not already exist. ** 2. the table (or view) does exist in the same database as the trigger. ** 3. that we are not trying to create a trigger on the sqlite_master table ** 4. That we are not trying to create an INSTEAD OF trigger on a table. ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view. */ if( sqlite_malloc_failed ) goto trigger_cleanup; assert( pTableName->nSrc==1 ); | > < | > | > > < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | int isTemp /* True if the TEMPORARY keyword is present */ ){ Trigger *nt; Table *tab; char *zName = 0; /* Name of the trigger */ sqlite *db = pParse->db; int iDb; /* When database to store the trigger in */ DbFixer sFix; /* Check that: ** 1. the trigger name does not already exist. ** 2. the table (or view) does exist in the same database as the trigger. ** 3. that we are not trying to create a trigger on the sqlite_master table ** 4. That we are not trying to create an INSTEAD OF trigger on a table. ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view. */ if( sqlite_malloc_failed ) goto trigger_cleanup; assert( pTableName->nSrc==1 ); if( pParse->initFlag && sqliteFixInit(&sFix, pParse, pParse->iDb, "trigger", pName) && sqliteFixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } tab = sqliteSrcListLookup(pParse, pTableName); if( !tab ){ goto trigger_cleanup; } iDb = isTemp ? 1 : tab->iDb; if( iDb>=2 && !pParse->initFlag ){ sqliteErrorMsg(pParse, "triggers may not be added to auxiliary " "database %s", db->aDb[tab->iDb].zName); |
︙ | ︙ | |||
134 135 136 137 138 139 140 | nt->iDb = iDb; nt->iTabDb = tab->iDb; nt->op = op; nt->tr_tm = tr_tm; nt->pWhen = sqliteExprDup(pWhen); nt->pColumns = sqliteIdListDup(pColumns); nt->foreach = foreach; | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | nt->iDb = iDb; nt->iTabDb = tab->iDb; nt->op = op; nt->tr_tm = tr_tm; nt->pWhen = sqliteExprDup(pWhen); nt->pColumns = sqliteIdListDup(pColumns); nt->foreach = foreach; sqliteTokenCopy(&nt->nameToken,pName); assert( pParse->pNewTrigger==0 ); pParse->pNewTrigger = nt; trigger_cleanup: sqliteFree(zName); sqliteSrcListDelete(pTableName); sqliteIdListDelete(pColumns); |
︙ | ︙ | |||
166 167 168 169 170 171 172 | nt = pParse->pNewTrigger; pParse->pNewTrigger = 0; nt->step_list = pStepList; while( pStepList ){ pStepList->pTrig = nt; pStepList = pStepList->pNext; } | | < | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | nt = pParse->pNewTrigger; pParse->pNewTrigger = 0; nt->step_list = pStepList; while( pStepList ){ pStepList->pTrig = nt; pStepList = pStepList->pNext; } if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken) && sqliteFixTriggerStep(&sFix, nt->step_list) ){ goto triggerfinish_cleanup; } /* if we are not initializing, and this trigger is not on a TEMP table, ** build the sqlite_master entry */ if( !pParse->initFlag ){ static VdbeOp insertTrig[] = { { OP_NewRecno, 0, 0, 0 }, |
︙ | ︙ | |||
362 363 364 365 366 367 368 369 370 371 372 373 374 375 | void sqliteDeleteTrigger(Trigger *pTrigger){ if( pTrigger==0 ) return; sqliteDeleteTriggerStep(pTrigger->step_list); sqliteFree(pTrigger->name); sqliteFree(pTrigger->table); sqliteExprDelete(pTrigger->pWhen); sqliteIdListDelete(pTrigger->pColumns); sqliteFree(pTrigger); } /* * This function is called to drop a trigger from the database schema. * * This may be called directly from the parser and therefore identifies | > | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | void sqliteDeleteTrigger(Trigger *pTrigger){ if( pTrigger==0 ) return; sqliteDeleteTriggerStep(pTrigger->step_list); sqliteFree(pTrigger->name); sqliteFree(pTrigger->table); sqliteExprDelete(pTrigger->pWhen); sqliteIdListDelete(pTrigger->pColumns); if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z); sqliteFree(pTrigger); } /* * This function is called to drop a trigger from the database schema. * * This may be called directly from the parser and therefore identifies |
︙ | ︙ |
Changes to test/attach.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # # $Id: attach.test,v 1.7 2003/06/03 01:47:12 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl for {set i 2} {$i<=15} {incr i} { file delete -force test$i.db |
︙ | ︙ | |||
465 466 467 468 469 470 471 | } {102 910 607 1314} do_test attach-4.13 { execsql { SELECT * FROM main.v3; } } {910 1112 1516} | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | } {102 910 607 1314} do_test attach-4.13 { execsql { SELECT * FROM main.v3; } } {910 1112 1516} # Tests for the sqliteFix...() routines in attach.c # do_test attach-5.1 { db close sqlite db test.db file delete -force test2.db sqlite db2 test2.db catchsql { ATTACH DATABASE 'test.db' AS orig; CREATE TRIGGER r1 AFTER INSERT ON orig.t1 BEGIN; SELECT 'no-op'; END; } db2 } {1 {triggers may not be added to auxiliary database orig}} do_test attach-5.2 { catchsql { CREATE TABLE t5(x,y); CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT 'no-op'; END; } db2 } {0 {}} do_test attach-5.3 { catchsql { DROP TRIGGER r5; CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT 'no-op' FROM orig.t1; END; } db2 } {1 {trigger r5 cannot reference objects in database orig}} do_test attach-5.4 { catchsql { CREATE TEMP TABLE t6(p,q,r); CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT 'no-op' FROM temp.t6; END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} do_test attach-5.5 { catchsql { CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT 'no-op' || (SELECT * FROM temp.t6); END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} do_test attach-5.6 { catchsql { CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT 'no-op' FROM t1 WHERE x<(SELECT min(x) FROM temp.t6); END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} do_test attach-5.7 { catchsql { CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT 'no-op' FROM t1 GROUP BY 1 HAVING x<(SELECT min(x) FROM temp.t6); END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} do_test attach-5.7 { catchsql { CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN SELECT max(1,x,(SELECT min(x) FROM temp.t6)) FROM t1; END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} do_test attach-5.8 { catchsql { CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN INSERT INTO t1 VALUES((SELECT min(x) FROM temp.t6),5); END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} do_test attach-5.9 { catchsql { CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN DELETE FROM t1 WHERE x<(SELECT min(x) FROM temp.t6); END; } db2 } {1 {trigger r5 cannot reference objects in database temp}} # Check to make sure we get a sensible error if unable to open # the file that we are trying to attach. # do_test attach-6.1 { catchsql { ATTACH DATABASE 'no-such-file' AS nosuch; } } {1 {cannot attach empty database: nosuch}} file delete -force no-such-file do_test attach-6.2 { sqlite dbx cannot-read dbx eval {CREATE TABLE t1(a,b,c)} dbx close catch {file attributes cannot-read -permission 0000} catch {file attributes cannot-read -readonly 1} catchsql { ATTACH DATABASE 'cannot-read' AS noread; } } {1 {unable to open database: cannot-read}} file delete -force cannot-read for {set i 2} {$i<=15} {incr i} { catch {db$i close} } file delete -force test2.db finish_test |
Changes to test/format3.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the the library is able to correctly # handle file-format 3 (version 2.6.x) databases. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the the library is able to correctly # handle file-format 3 (version 2.6.x) databases. # # $Id: format3.test,v 1.3 2003/06/03 01:47:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a bunch of data to sort against # do_test format3-1.0 { |
︙ | ︙ | |||
713 714 715 716 717 718 719 720 721 | INSERT INTO t7 VALUES(0,0,1); INSERT INTO t7 VALUES(0.0,0,2); INSERT INTO t7 VALUES(0,0.0,3); INSERT INTO t7 VALUES(0.0,0.0,4); SELECT DISTINCT x, y FROM t7 ORDER BY z; } } {0 0} finish_test | > > > > > > > > > > > > > > > > > | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | INSERT INTO t7 VALUES(0,0,1); INSERT INTO t7 VALUES(0.0,0,2); INSERT INTO t7 VALUES(0,0.0,3); INSERT INTO t7 VALUES(0.0,0.0,4); SELECT DISTINCT x, y FROM t7 ORDER BY z; } } {0 0} # Make sure attempts to attach a format 3 database fail. # do_test format3-12.1 { file delete -force test2.db sqlite db2 test2.db catchsql { CREATE TABLE t8(x,y); ATTACH DATABASE 'test.db' AS format3; } db2; } {1 {incompatible file format in auxiliary database: format3}} do_test format3-12.2 { catchsql { ATTACH DATABASE 'test2.db' AS test2; } } {1 {cannot attach auxiliary databases to an older format master database}} db2 close finish_test |
Changes to test/misc1.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for miscellanous features that were # left out of other test files. # | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for miscellanous features that were # left out of other test files. # # $Id: misc1.test,v 1.22 2003/06/03 01:47:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Test the creation and use of tables that have a large number # of columns. # |
︙ | ︙ | |||
514 515 516 517 518 519 520 | do_test misc1-16.6 { execsql { INSERT INTO test VALUES(NULL); SELECT rowid, a FROM test; } } {1 1 5 5 6 6} | > | > > > > > > > > > > > > > > | > > | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | do_test misc1-16.6 { execsql { INSERT INTO test VALUES(NULL); SELECT rowid, a FROM test; } } {1 1 5 5 6 6} # Ticket #333: Temp triggers that modify persistent tables. # do_test misc1-17.1 { execsql { BEGIN; CREATE TABLE RealTable(TestID INTEGER PRIMARY KEY, TestString TEXT); CREATE TEMP TABLE TempTable(TestID INTEGER PRIMARY KEY, TestString TEXT); CREATE TEMP TRIGGER trigTest_1 AFTER UPDATE ON TempTable BEGIN INSERT INTO RealTable(TestString) SELECT new.TestString FROM TempTable LIMIT 1; END; INSERT INTO TempTable(TestString) VALUES ('1'); INSERT INTO TempTable(TestString) VALUES ('2'); UPDATE TempTable SET TestString = TestString + 1 WHERE TestID IN (1, 2); COMMIT; SELECT TestString FROM RealTable ORDER BY 1; } } {2 3} finish_test |