diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 56 | ||||
-rw-r--r-- | src/delete.c | 46 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/parse.y | 6 | ||||
-rw-r--r-- | src/select.c | 6 | ||||
-rw-r--r-- | src/shell.c | 5 | ||||
-rw-r--r-- | src/sqliteInt.h | 9 | ||||
-rw-r--r-- | src/trigger.c | 10 | ||||
-rw-r--r-- | src/update.c | 43 |
9 files changed, 109 insertions, 77 deletions
diff --git a/src/build.c b/src/build.c index 6db409278..44c482732 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.145 2003/04/15 01:19:48 drh Exp $ +** $Id: build.c,v 1.146 2003/04/17 22:57:53 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -109,7 +109,10 @@ void sqliteExec(Parse *pParse){ /* ** Locate the in-memory structure that describes ** a particular database table given the name -** of that table. Return NULL if not found. +** of that table and (optionally) the name of the database +** containing the table. Return NULL if not found. +** +** See also sqliteLocateTable(). */ Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){ Table *p = 0; @@ -125,7 +128,48 @@ Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){ /* ** Locate the in-memory structure that describes -** a particular index given the name of that index. +** a particular database table given the name +** of that table and (optionally) the name of the database +** containing the table. Return NULL if not found. +** +** If pParse->useDb is not negative, then the table must be +** located in that database. If a different database is specified, +** an error message is generated into pParse->zErrMsg. +*/ +Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){ + sqlite *db; + const char *zUse; + Table *p; + db = pParse->db; + if( pParse->useDb<0 ){ + p = sqliteFindTable(db, zName, zDbase); + }else { + assert( pParse->useDb<db->nDb ); + assert( db->aDb[pParse->useDb].pBt!=0 ); + zUse = db->aDb[pParse->useDb].zName; + if( zDbase && pParse->useDb!=1 && sqliteStrICmp(zDbase, zUse)!=0 ){ + sqliteErrorMsg(pParse,"cannot use database %s in this context", zDbase); + return 0; + } + p = sqliteFindTable(db, zName, zUse); + if( p==0 && pParse->useDb==1 && zDbase==0 ){ + p = sqliteFindTable(db, zName, 0); + } + } + if( p==0 ){ + if( zDbase ){ + sqliteErrorMsg(pParse, "no such table: %s.%s", zDbase, zName); + }else{ + sqliteErrorMsg(pParse, "no such table: %s", zName); + } + } + return p; +} + +/* +** Locate the in-memory structure that describes +** a particular index given the name of that index +** and the name of the database that contains the index. ** Return NULL if not found. */ Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){ @@ -2078,7 +2122,13 @@ void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int tempOnly){ if( (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 1, 0); if( !tempOnly ){ + int i; + sqlite *db = pParse->db; sqliteVdbeAddOp(v, OP_Transaction, 0, 0); + for(i=2; i<db->nDb; i++){ + if( db->aDb[i].pBt==0 ) continue; + sqliteVdbeAddOp(v, OP_Transaction, i, 0); + } sqliteCodeVerifySchema(pParse); } }else if( setCheckpoint ){ diff --git a/src/delete.c b/src/delete.c index c2c6d5b49..9d88de4af 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.51 2003/04/15 19:22:23 drh Exp $ +** $Id: delete.c,v 1.52 2003/04/17 22:57:53 drh Exp $ */ #include "sqliteInt.h" @@ -27,11 +27,7 @@ Table *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){ for(i=0; i<pSrc->nSrc; i++){ const char *zTab = pSrc->a[i].zName; const char *zDb = pSrc->a[i].zDatabase; - pTab = sqliteFindTable(pParse->db, zTab, zDb); - if( pTab==0 ){ - sqliteErrorMsg(pParse, "no such table: %S", pSrc, 0); - break; - } + pTab = sqliteLocateTable(pParse, zTab, zDb); pSrc->a[i].pTab = pTab; } return pTab; @@ -62,8 +58,6 @@ void sqliteDeleteFrom( ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ - char *zTab; /* Name of the table from which we are deleting */ - char *zDb; /* Name of database containing table zTab */ int end, addr; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ @@ -83,37 +77,25 @@ void sqliteDeleteFrom( db = pParse->db; assert( pTabList->nSrc==1 ); - /* Check for the special case of a VIEW with one or more ON DELETE triggers - ** defined - */ - zTab = pTabList->a[0].zName; - zDb = pTabList->a[0].zDatabase; - if( zTab != 0 ){ - pTab = sqliteFindTable(pParse->db, zTab, zDb); - if( pTab ){ - before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, - TK_DELETE, TK_BEFORE, TK_ROW, 0); - after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, - TK_DELETE, TK_AFTER, TK_ROW, 0); - row_triggers_exist = before_triggers || after_triggers; - } - if( row_triggers_exist && pTab->pSelect ){ - /* Just fire VIEW triggers */ - sqliteSrcListDelete(pTabList); - sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0); - return; - } - } - /* Locate the table which we want to delete. This table has to be ** put in an SrcList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect ** an SrcList* parameter instead of just a Table* parameter. */ pTab = sqliteSrcListLookup(pParse, pTabList); - if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ){ - goto delete_from_cleanup; + if( pTab==0 ) goto delete_from_cleanup; + before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, + TK_DELETE, TK_BEFORE, TK_ROW, 0); + after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, + TK_DELETE, TK_AFTER, TK_ROW, 0); + row_triggers_exist = before_triggers || after_triggers; + if( row_triggers_exist && pTab->pSelect ){ + /* Just fire VIEW triggers */ + sqliteSrcListDelete(pTabList); + sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0); + return; } + if( sqliteIsReadOnly(pParse, pTab) ) goto delete_from_cleanup; assert( pTab->pSelect==0 ); /* This table is not a view */ if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0) ){ goto delete_from_cleanup; diff --git a/src/main.c b/src/main.c index c38e3d58d..d2900b101 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.125 2003/04/16 20:24:52 drh Exp $ +** $Id: main.c,v 1.126 2003/04/17 22:57:54 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -69,6 +69,7 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){ sParse.db = pData->db; sParse.initFlag = 1; sParse.iDb = atoi(argv[4]); + sParse.useDb = -1; sParse.newTnum = atoi(argv[2]); sParse.useCallback = 1; sqliteRunParser(&sParse, argv[3], pData->pzErrMsg); @@ -320,6 +321,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ sParse.xCallback = sqliteInitCallback; sParse.pArg = (void*)&initData; sParse.initFlag = 1; + sParse.useDb = -1; sParse.useCallback = 1; if( iDb==0 ){ sqliteRunParser(&sParse, @@ -719,6 +721,7 @@ static int sqliteMain( sParse.db = db; sParse.xCallback = xCallback; sParse.pArg = pArg; + sParse.useDb = -1; sParse.useCallback = ppVm==0; #ifndef SQLITE_OMIT_TRACE if( db->xTrace ) db->xTrace(db->pTraceArg, zSql); diff --git a/src/parse.y b/src/parse.y index 605cc6cd7..c3e14fa68 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.94 2003/03/31 00:30:48 drh Exp $ +** @(#) $Id: parse.y,v 1.95 2003/04/17 22:57:54 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -794,7 +794,9 @@ when_clause(A) ::= WHEN expr(X). { A = X; } %type trigger_cmd_list {TriggerStep *} trigger_cmd_list(A) ::= trigger_cmd(X) SEMI trigger_cmd_list(Y). { - X->pNext = Y ; A = X; } + X->pNext = Y; + A = X; +} trigger_cmd_list(A) ::= . { A = 0; } %type trigger_cmd {TriggerStep *} diff --git a/src/select.c b/src/select.c index 013db3339..3aef002cc 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.131 2003/04/17 12:44:24 drh Exp $ +** $Id: select.c,v 1.132 2003/04/17 22:57:54 drh Exp $ */ #include "sqliteInt.h" @@ -908,10 +908,8 @@ static int fillInColumnList(Parse *pParse, Select *p){ }else{ /* An ordinary table or view name in the FROM clause */ pTabList->a[i].pTab = pTab = - sqliteFindTable(pParse->db, pTabList->a[i].zName, - pTabList->a[i].zDatabase); + sqliteLocateTable(pParse,pTabList->a[i].zName,pTabList->a[i].zDatabase); if( pTab==0 ){ - sqliteErrorMsg(pParse, "no such table: %S", pTabList, i); return 1; } if( pTab->pSelect ){ diff --git a/src/shell.c b/src/shell.c index 00601df47..4873d35df 100644 --- a/src/shell.c +++ b/src/shell.c @@ -12,7 +12,7 @@ ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** -** $Id: shell.c,v 1.69 2003/04/17 02:54:14 drh Exp $ +** $Id: shell.c,v 1.70 2003/04/17 22:57:54 drh Exp $ */ #include <stdlib.h> #include <string.h> @@ -285,7 +285,8 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ } if( p->cnt++>0 ) fprintf(p->out,"\n"); for(i=0; i<nArg; i++){ - fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : p->nullvalue); + fprintf(p->out,"%*s = %s\n", w, azCol[i], + azArg[i] ? azArg[i] : p->nullvalue); } break; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 473492d33..74a8752c4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.174 2003/04/16 02:17:35 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.175 2003/04/17 22:57:54 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -225,8 +225,8 @@ typedef struct Db Db; ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and -** aDb[1] is the database file used to hold temporary tables. But -** additional databases may be attached to the engine. +** aDb[1] is the database file used to hold temporary tables. Additional +** databases may be attached. */ struct Db { char *zName; /* Name of this database */ @@ -825,6 +825,7 @@ struct Parse { ** other than after an OP_Transaction */ u8 iDb; /* Index of database whose schema is being parsed */ u8 useCallback; /* True if callbacks should be used to report results */ + int useDb; /* Restrict references to tables in this database */ int newTnum; /* Table number to use when reparsing CREATE TABLEs */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ @@ -918,6 +919,7 @@ struct Trigger { struct TriggerStep { int op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ int orconf; /* OE_Rollback etc. */ + Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* Valid for SELECT and sometimes INSERT steps (when pExprList == 0) */ @@ -1062,6 +1064,7 @@ void sqliteExprCode(Parse*, Expr*); void sqliteExprIfTrue(Parse*, Expr*, int, int); void sqliteExprIfFalse(Parse*, Expr*, int, int); Table *sqliteFindTable(sqlite*,const char*, const char*); +Table *sqliteLocateTable(Parse*,const char*, const char*); Index *sqliteFindIndex(sqlite*,const char*, const char*); void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); void sqliteCopy(Parse*, SrcList*, Token*, Token*, int); diff --git a/src/trigger.c b/src/trigger.c index 71a784aae..ca6dfa618 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -65,7 +65,7 @@ void sqliteCreateTrigger( if( !tab ){ goto trigger_cleanup; } - if( tab->iDb>=2 ){ + if( tab->iDb>=2 && !pParse->initFlag ){ sqliteErrorMsg(pParse, "triggers may not be added to auxiliary " "database %s", db->aDb[tab->iDb].zName); goto trigger_cleanup; @@ -124,6 +124,11 @@ void sqliteCreateTrigger( sqliteIdListDelete(pColumns); nt->foreach = foreach; nt->step_list = pStepList; + while( pStepList ){ + pStepList->pTrig = nt; + pStepList = pStepList->pNext; + } + pStepList = nt->step_list; /* if we are not initializing, and this trigger is not on a TEMP table, ** build the sqlite_master entry @@ -512,8 +517,10 @@ static int codeTriggerProgram( while( pTriggerStep ){ int saveNTab = pParse->nTab; + int saveUseDb = pParse->useDb; orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; pParse->trigStack->orconf = orconf; + pParse->useDb = pTriggerStep->pTrig->iDb; switch( pTriggerStep->op ){ case TK_SELECT: { Select * ss = sqliteSelectDup(pTriggerStep->pSelect); @@ -554,6 +561,7 @@ static int codeTriggerProgram( assert(0); } pParse->nTab = saveNTab; + pParse->useDb = saveUseDb; pTriggerStep = pTriggerStep->pNext; } diff --git a/src/update.c b/src/update.c index 721dbaa87..53dd62ebf 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.59 2003/04/15 19:22:24 drh Exp $ +** $Id: update.c,v 1.60 2003/04/17 22:57:54 drh Exp $ */ #include "sqliteInt.h" @@ -27,8 +27,6 @@ void sqliteUpdate( int onError /* How to handle constraint errors */ ){ int i, j; /* Loop counters */ - char *zTab; /* Name of the table to be updated */ - char *zDb; /* Name of the database holding zTab */ Table *pTab; /* The table to be updated */ int addr; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ @@ -58,38 +56,25 @@ void sqliteUpdate( db = pParse->db; assert( pTabList->nSrc==1 ); - /* Check for the special case of a VIEW with one or more ON UPDATE triggers - * defined - */ - zTab = pTabList->a[0].zName; - zDb = pTabList->a[0].zDatabase; - if( zTab != 0 ){ - pTab = sqliteFindTable(pParse->db, zTab, zDb); - if( pTab ){ - before_triggers = - sqliteTriggersExist(pParse, pTab->pTrigger, - TK_UPDATE, TK_BEFORE, TK_ROW, pChanges); - after_triggers = - sqliteTriggersExist(pParse, pTab->pTrigger, - TK_UPDATE, TK_AFTER, TK_ROW, pChanges); - row_triggers_exist = before_triggers || after_triggers; - } - - if( row_triggers_exist && pTab->pSelect ){ - /* Just fire VIEW triggers */ - sqliteSrcListDelete(pTabList); - sqliteViewTriggers(pParse, pTab, pWhere, onError, pChanges); - return; - } - } - /* Locate the table which we want to update. This table has to be ** put in an SrcList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect ** an SrcList* parameter instead of just a Table* parameter. */ pTab = sqliteSrcListLookup(pParse, pTabList); - if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ) goto update_cleanup; + if( pTab==0 ) goto update_cleanup; + before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, + TK_UPDATE, TK_BEFORE, TK_ROW, pChanges); + after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, + TK_UPDATE, TK_AFTER, TK_ROW, pChanges); + row_triggers_exist = before_triggers || after_triggers; + if( row_triggers_exist && pTab->pSelect ){ + /* Just fire VIEW triggers */ + sqliteSrcListDelete(pTabList); + sqliteViewTriggers(pParse, pTab, pWhere, onError, pChanges); + return; + } + if( sqliteIsReadOnly(pParse, pTab) ) goto update_cleanup; assert( pTab->pSelect==0 ); /* This table is not a VIEW */ aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); if( aXRef==0 ) goto update_cleanup; |