diff options
author | drh <drh@noemail.net> | 2003-03-20 01:16:58 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2003-03-20 01:16:58 +0000 |
commit | 113088ec685755a8abc94ddadc7d0e57dba9c914 (patch) | |
tree | 10f7dfca4a91abe824f641dafcacf41483cf476c /src | |
parent | 001bbcbb8fa5a55e9950445c6287a1fc0496e83e (diff) | |
download | sqlite-113088ec685755a8abc94ddadc7d0e57dba9c914.tar.gz sqlite-113088ec685755a8abc94ddadc7d0e57dba9c914.zip |
Record the database name in addition to the table name for DELETE, INSERT,
and UPDATE statements. (CVS 879)
FossilOrigin-Name: a5d8fc95ee58dc3205a0bbbcadaa3b9c902a941b
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 62 | ||||
-rw-r--r-- | src/delete.c | 42 | ||||
-rw-r--r-- | src/expr.c | 8 | ||||
-rw-r--r-- | src/insert.c | 13 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/parse.y | 43 | ||||
-rw-r--r-- | src/sqliteInt.h | 14 | ||||
-rw-r--r-- | src/tokenize.c | 5 | ||||
-rw-r--r-- | src/trigger.c | 22 | ||||
-rw-r--r-- | src/update.c | 46 | ||||
-rw-r--r-- | src/vdbe.c | 14 |
11 files changed, 153 insertions, 122 deletions
diff --git a/src/build.c b/src/build.c index 0c763d07a..ba6da93c3 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.132 2003/03/19 03:14:01 drh Exp $ +** $Id: build.c,v 1.133 2003/03/20 01:16:58 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1805,25 +1805,63 @@ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){ ** need be. A new entry is created in the SrcList even if pToken is NULL. ** ** A new SrcList is returned, or NULL if malloc() fails. +** +** If pDatabase is not null, it means that the table has an optional +** database name prefix. Like this: "database.table". The pDatabase +** points to the table name and the pTable points to the database name. +** The SrcList.a[].zName field is filled with the table name which might +** come from pTable (if pDatabase is NULL) or from pDatabase. +** SrcList.a[].zDatabase is filled with the database name from pTable, +** or with NULL if no database is specified. +** +** In other words, if call like this: +** +** sqliteSrcListAppend(A,B,0); +** +** Then B is a table name and the database name is unspecified. If called +** like this: +** +** sqliteSrcListAppend(A,B,C); +** +** Then C is the table name and B is the database name. */ -SrcList *sqliteSrcListAppend(SrcList *pList, Token *pToken){ +SrcList *sqliteSrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ if( pList==0 ){ - pList = sqliteMalloc( sizeof(IdList) ); + pList = sqliteMalloc( sizeof(SrcList) ); if( pList==0 ) return 0; } - if( (pList->nSrc & 7)==0 ){ - struct SrcList_item *a; - a = sqliteRealloc(pList->a, (pList->nSrc+8)*sizeof(pList->a[0]) ); - if( a==0 ){ + if( (pList->nSrc & 7)==1 ){ + SrcList *pNew; + pNew = sqliteRealloc(pList, + sizeof(*pList) + (pList->nSrc+8)*sizeof(pList->a[0]) ); + if( pNew==0 ){ sqliteSrcListDelete(pList); return 0; } - pList->a = a; + pList = pNew; } memset(&pList->a[pList->nSrc], 0, sizeof(pList->a[0])); - if( pToken ){ + if( pDatabase && pDatabase->z==0 ){ + pDatabase = 0; + } + if( pDatabase && pTable ){ + Token *pTemp = pDatabase; + pDatabase = pTable; + pTable = pTemp; + } + if( pTable ){ char **pz = &pList->a[pList->nSrc].zName; - sqliteSetNString(pz, pToken->z, pToken->n, 0); + sqliteSetNString(pz, pTable->z, pTable->n, 0); + if( *pz==0 ){ + sqliteSrcListDelete(pList); + return 0; + }else{ + sqliteDequote(*pz); + } + } + if( pDatabase ){ + char **pz = &pList->a[pList->nSrc].zDatabase; + sqliteSetNString(pz, pDatabase->z, pDatabase->n, 0); if( *pz==0 ){ sqliteSrcListDelete(pList); return 0; @@ -1879,6 +1917,7 @@ void sqliteSrcListDelete(SrcList *pList){ int i; if( pList==0 ) return; for(i=0; i<pList->nSrc; i++){ + sqliteFree(pList->a[i].zDatabase); sqliteFree(pList->a[i].zName); sqliteFree(pList->a[i].zAlias); if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){ @@ -1888,7 +1927,6 @@ void sqliteSrcListDelete(SrcList *pList){ sqliteExprDelete(pList->a[i].pOn); sqliteIdListDelete(pList->a[i].pUsing); } - sqliteFree(pList->a); sqliteFree(pList); } @@ -2079,7 +2117,7 @@ void sqliteCodeVerifySchema(Parse *pParse){ sqlite *db = pParse->db; Vdbe *v = sqliteGetVdbe(pParse); for(i=0; i<db->nDb; i++){ - if( db->aDb[i].zName==0 || db->aDb[i].pBt==0 ) continue; + if( i==1 || db->aDb[i].pBt==0 ) continue; sqliteVdbeAddOp(v, OP_VerifyCookie, 0, db->aDb[i].schema_cookie); } pParse->schemaVerified = 1; diff --git a/src/delete.c b/src/delete.c index 62bcf9ca1..c55c6f37e 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.46 2003/03/19 03:14:01 drh Exp $ +** $Id: delete.c,v 1.47 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" @@ -42,41 +42,16 @@ Table *sqliteTableNameToTable(Parse *pParse, const char *zTab){ } /* -** Given a table name, check to make sure the table exists, is writable -** and is not a view. If everything is OK, construct an SrcList holding -** the table and return a pointer to the SrcList. The calling function -** is responsible for freeing the SrcList when it has finished with it. -** If there is an error, leave a message on pParse->zErrMsg and return -** NULL. -*/ -SrcList *sqliteTableTokenToSrcList(Parse *pParse, Token *pTableName){ - Table *pTab; - SrcList *pTabList; - - pTabList = sqliteSrcListAppend(0, pTableName); - if( pTabList==0 ) return 0; - assert( pTabList->nSrc==1 ); - pTab = sqliteTableNameToTable(pParse, pTabList->a[0].zName); - if( pTab==0 ){ - sqliteSrcListDelete(pTabList); - return 0; - } - pTabList->a[0].pTab = pTab; - return pTabList; -} - -/* ** Process a DELETE FROM statement. */ void sqliteDeleteFrom( Parse *pParse, /* The parser context */ - Token *pTableName, /* The table from which we should delete things */ + SrcList *pTabList, /* The table from which we should delete things */ Expr *pWhere /* The WHERE clause. May be null */ ){ 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 */ - SrcList *pTabList; /* A fake FROM clause holding just pTab */ int end, addr; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ @@ -92,11 +67,12 @@ void sqliteDeleteFrom( goto delete_from_cleanup; } db = pParse->db; + assert( pTabList->nSrc==1 ); /* Check for the special case of a VIEW with one or more ON DELETE triggers ** defined */ - zTab = sqliteTableNameFromToken(pTableName); + zTab = pTabList->a[0].zName; if( zTab != 0 ){ pTab = sqliteFindTable(pParse->db, zTab); if( pTab ){ @@ -106,9 +82,9 @@ void sqliteDeleteFrom( sqliteTriggersExist(pParse, pTab->pTrigger, TK_DELETE, TK_AFTER, TK_ROW, 0); } - sqliteFree(zTab); if( row_triggers_exist && pTab->pSelect ){ /* Just fire VIEW triggers */ + sqliteSrcListDelete(pTabList); sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0); return; } @@ -119,10 +95,10 @@ void sqliteDeleteFrom( ** will be calling are designed to work with multiple tables and expect ** an SrcList* parameter instead of just a Table* parameter. */ - pTabList = sqliteTableTokenToSrcList(pParse, pTableName); - if( pTabList==0 ) goto delete_from_cleanup; - assert( pTabList->nSrc==1 ); - pTab = pTabList->a[0].pTab; + pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab); + if( pTab==0 ){ + 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/expr.c b/src/expr.c index 8ee9802d5..47a7dd1a8 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.88 2003/01/31 17:16:37 drh Exp $ +** $Id: expr.c,v 1.89 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -184,12 +184,12 @@ ExprList *sqliteExprListDup(ExprList *p){ SrcList *sqliteSrcListDup(SrcList *p){ SrcList *pNew; int i; + int nByte; if( p==0 ) return 0; - pNew = sqliteMalloc( sizeof(*pNew) ); + nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); + pNew = sqliteMalloc( nByte ); if( pNew==0 ) return 0; pNew->nSrc = p->nSrc; - pNew->a = sqliteMalloc( p->nSrc*sizeof(p->a[0]) ); - if( pNew->a==0 && p->nSrc != 0 ) return 0; for(i=0; i<p->nSrc; i++){ pNew->a[i].zName = sqliteStrDup(p->a[i].zName); pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias); diff --git a/src/insert.c b/src/insert.c index 5b96f48a1..5ed66168c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.73 2003/03/19 03:14:01 drh Exp $ +** $Id: insert.c,v 1.74 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" @@ -85,14 +85,14 @@ */ void sqliteInsert( Parse *pParse, /* Parser context */ - Token *pTableName, /* Name of table into which we are inserting */ + SrcList *pTabList, /* Name of table into which we are inserting */ ExprList *pList, /* List of values to be inserted */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pColumn, /* Column names corresponding to IDLIST. */ int onError /* How to handle constraint errors */ ){ Table *pTab; /* The table to insert into */ - char *zTab = 0; /* Name of the table into which we are inserting */ + char *zTab; /* Name of the table into which we are inserting */ int i, j, idx; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ @@ -117,7 +117,8 @@ void sqliteInsert( /* Locate the table into which we will be inserting new information. */ - zTab = sqliteTableNameFromToken(pTableName); + assert( pTabList->nSrc==1 ); + zTab = pTabList->a[0].zName; if( zTab==0 ) goto insert_cleanup; pTab = sqliteFindTable(pParse->db, zTab); if( pTab==0 ){ @@ -145,8 +146,6 @@ void sqliteInsert( pParse->nErr++; goto insert_cleanup; } - sqliteFree(zTab); - zTab = 0; if( pTab==0 ) goto insert_cleanup; @@ -521,9 +520,9 @@ void sqliteInsert( } insert_cleanup: + sqliteSrcListDelete(pTabList); if( pList ) sqliteExprListDelete(pList); if( pSelect ) sqliteSelectDelete(pSelect); - if ( zTab ) sqliteFree(zTab); sqliteIdListDelete(pColumn); } diff --git a/src/main.c b/src/main.c index cf1481418..60cf794dc 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.115 2003/03/19 03:14:02 drh Exp $ +** $Id: main.c,v 1.116 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -377,6 +377,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ return 0; } db->aDb[0].zName = "main"; + db->aDb[1].zName = "temp"; /* Attempt to read the schema */ sqliteRegisterBuiltinFunctions(db); @@ -469,6 +470,9 @@ void sqlite_close(sqlite *db){ if( db->aDb[j].pBt ){ sqliteBtreeClose(db->aDb[j].pBt); } + if( j>=2 ){ + sqliteFree(db->aDb[j].zName); + } } if( db->aDb!=db->aDbStatic ){ sqliteFree(db->aDb); diff --git a/src/parse.y b/src/parse.y index e38522ec1..17d137d5f 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.91 2003/02/20 00:44:52 drh Exp $ +** @(#) $Id: parse.y,v 1.92 2003/03/20 01:16:59 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -126,8 +126,8 @@ id(A) ::= ID(X). {A = X;} // This obviates the need for the "id" nonterminal. // %fallback ID - ABORT AFTER ASC BEFORE BEGIN CASCADE CLUSTER CONFLICT - COPY DEFERRED DELIMITERS DESC EACH END EXPLAIN FAIL FOR + ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CLUSTER CONFLICT + COPY DATABASE DEFERRED DELIMITERS DESC DETACH EACH END EXPLAIN FAIL FOR IGNORE IMMEDIATE INITIALLY INSTEAD MATCH KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT TEMP TRIGGER VACUUM VIEW. @@ -353,8 +353,8 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). { if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = Y; } stl_prefix(A) ::= . {A = 0;} -seltablist(A) ::= stl_prefix(X) nm(Y) as(Z) on_opt(N) using_opt(U). { - A = sqliteSrcListAppend(X,&Y); +seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { + A = sqliteSrcListAppend(X,&Y,&D); if( Z.n ) sqliteSrcListAddAlias(A,&Z); if( N ){ if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; } @@ -366,7 +366,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) as(Z) on_opt(N) using_opt(U). { } } seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { - A = sqliteSrcListAppend(X,0); + A = sqliteSrcListAppend(X,0,0); A->a[A->nSrc-1].pSelect = S; if( Z.n ) sqliteSrcListAddAlias(A,&Z); if( N ){ @@ -379,6 +379,10 @@ seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { } } +%type dbnm {Token} +dbnm(A) ::= . {A.z=0; A.n=0;} +dbnm(A) ::= DOT nm(X). {A = X;} + %type joinop {int} %type joinop2 {int} joinop(X) ::= COMMA. { X = JT_INNER; } @@ -447,8 +451,9 @@ limit_opt(A) ::= LIMIT INTEGER(X) COMMA INTEGER(Y). /////////////////////////// The DELETE statement ///////////////////////////// // -cmd ::= DELETE FROM nm(X) where_opt(Y). - {sqliteDeleteFrom(pParse, &X, Y);} +cmd ::= DELETE FROM nm(X) dbnm(D) where_opt(Y). { + sqliteDeleteFrom(pParse, sqliteSrcListAppend(0,&X,&D), Y); +} %type where_opt {Expr*} %destructor where_opt {sqliteExprDelete($$);} @@ -461,8 +466,8 @@ where_opt(A) ::= WHERE expr(X). {A = X;} ////////////////////////// The UPDATE command //////////////////////////////// // -cmd ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z). - {sqliteUpdate(pParse,&X,Y,Z,R);} +cmd ::= UPDATE orconf(R) nm(X) dbnm(D) SET setlist(Y) where_opt(Z). + {sqliteUpdate(pParse,sqliteSrcListAppend(0,&X,&D),Y,Z,R);} setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y). {A = sqliteExprListAppend(Z,Y,&X);} @@ -470,10 +475,11 @@ setlist(A) ::= nm(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);} ////////////////////////// The INSERT command ///////////////////////////////// // -cmd ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) VALUES LP itemlist(Y) RP. - {sqliteInsert(pParse, &X, Y, 0, F, R);} -cmd ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S). - {sqliteInsert(pParse, &X, 0, S, F, R);} +cmd ::= insert_cmd(R) INTO nm(X) dbnm(D) inscollist_opt(F) + VALUES LP itemlist(Y) RP. + {sqliteInsert(pParse, sqliteSrcListAppend(0,&X,&D), Y, 0, F, R);} +cmd ::= insert_cmd(R) INTO nm(X) dbnm(D) inscollist_opt(F) select(S). + {sqliteInsert(pParse, sqliteSrcListAppend(0,&X,&D), 0, S, F, R);} %type insert_cmd {int} insert_cmd(A) ::= INSERT orconf(R). {A = R;} @@ -825,3 +831,12 @@ expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y). { cmd ::= DROP TRIGGER nm(X). { sqliteDropTrigger(pParse,&X,0); } + +//////////////////////// ATTACH DATABASE file AS name ///////////////////////// +cmd ::= ATTACH database_kw_opt ids AS nm. + +database_kw_opt ::= DATABASE. +database_kw_opt ::= . + +//////////////////////// DETACH DATABASE name ///////////////////////////////// +cmd ::= DETACH database_kw_opt nm. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 63610ae8e..0e7090ea4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.163 2003/03/19 03:14:02 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.164 2003/03/20 01:16:59 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -608,6 +608,7 @@ struct IdList { struct SrcList { int nSrc; /* Number of tables or subqueries in the FROM clause */ struct SrcList_item { + char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ @@ -615,7 +616,7 @@ struct SrcList { int jointype; /* Type of join between this table and the next */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ - } *a; /* One entry for each identifier on the list */ + } a[1]; /* One entry for each identifier on the list */ }; /* @@ -975,10 +976,10 @@ int sqliteViewGetColumnNames(Parse*,Table*); void sqliteViewResetAll(sqlite*); void sqliteDropTable(Parse*, Token*, int); void sqliteDeleteTable(sqlite*, Table*); -void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int); +void sqliteInsert(Parse*, SrcList*, ExprList*, Select*, IdList*, int); IdList *sqliteIdListAppend(IdList*, Token*); int sqliteIdListIndex(IdList*,const char*); -SrcList *sqliteSrcListAppend(SrcList*, Token*); +SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*); void sqliteSrcListAddAlias(SrcList*, Token*); void sqliteIdListDelete(IdList*); void sqliteSrcListDelete(SrcList*); @@ -992,9 +993,8 @@ Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, void sqliteSelectDelete(Select*); void sqliteSelectUnbind(Select*); Table *sqliteTableNameToTable(Parse*, const char*); -SrcList *sqliteTableTokenToSrcList(Parse*, Token*); -void sqliteDeleteFrom(Parse*, Token*, Expr*); -void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int); +void sqliteDeleteFrom(Parse*, SrcList*, Expr*); +void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int, ExprList**); void sqliteWhereEnd(WhereInfo*); void sqliteExprCode(Parse*, Expr*); diff --git a/src/tokenize.c b/src/tokenize.c index 7dd49b21a..d30804294 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.55 2003/01/29 14:06:09 drh Exp $ +** $Id: tokenize.c,v 1.56 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -44,6 +44,7 @@ static Keyword aKeywordTable[] = { { "AND", 0, TK_AND, 0 }, { "AS", 0, TK_AS, 0 }, { "ASC", 0, TK_ASC, 0 }, + { "ATTACH", 0, TK_ATTACH, 0 }, { "BEFORE", 0, TK_BEFORE, 0 }, { "BEGIN", 0, TK_BEGIN, 0 }, { "BETWEEN", 0, TK_BETWEEN, 0 }, @@ -59,12 +60,14 @@ static Keyword aKeywordTable[] = { { "COPY", 0, TK_COPY, 0 }, { "CREATE", 0, TK_CREATE, 0 }, { "CROSS", 0, TK_JOIN_KW, 0 }, + { "DATABASE", 0, TK_DATABASE, 0 }, { "DEFAULT", 0, TK_DEFAULT, 0 }, { "DEFERRED", 0, TK_DEFERRED, 0 }, { "DEFERRABLE", 0, TK_DEFERRABLE, 0 }, { "DELETE", 0, TK_DELETE, 0 }, { "DELIMITERS", 0, TK_DELIMITERS, 0 }, { "DESC", 0, TK_DESC, 0 }, + { "DETACH", 0, TK_DETACH, 0 }, { "DISTINCT", 0, TK_DISTINCT, 0 }, { "DROP", 0, TK_DROP, 0 }, { "END", 0, TK_END, 0 }, diff --git a/src/trigger.c b/src/trigger.c index 03032fe25..76bdc77ba 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -514,24 +514,29 @@ static int codeTriggerProgram( break; } case TK_UPDATE: { + SrcList *pSrc; + pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); - sqliteUpdate(pParse, &pTriggerStep->target, + sqliteUpdate(pParse, pSrc, sqliteExprListDup(pTriggerStep->pExprList), sqliteExprDup(pTriggerStep->pWhere), orconf); sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); break; } case TK_INSERT: { - sqliteInsert(pParse, &pTriggerStep->target, - sqliteExprListDup(pTriggerStep->pExprList), - sqliteSelectDup(pTriggerStep->pSelect), - sqliteIdListDup(pTriggerStep->pIdList), orconf); + SrcList *pSrc; + pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); + sqliteInsert(pParse, pSrc, + sqliteExprListDup(pTriggerStep->pExprList), + sqliteSelectDup(pTriggerStep->pSelect), + sqliteIdListDup(pTriggerStep->pIdList), orconf); break; } case TK_DELETE: { + SrcList *pSrc; sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); - sqliteDeleteFrom(pParse, &pTriggerStep->target, - sqliteExprDup(pTriggerStep->pWhere)); + pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); + sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere)); sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); break; } @@ -611,7 +616,6 @@ int sqliteCodeRowTrigger( Expr * whenExpr; dummyTablist.nSrc = 0; - dummyTablist.a = 0; /* Push an entry on to the trigger stack */ pTriggerStack->pTrigger = pTrigger; @@ -682,7 +686,7 @@ void sqliteViewTriggers( theSelect.isDistinct = 0; theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); - theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken); + theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken, 0); theSelect.pWhere = pWhere; pWhere = 0; theSelect.pGroupBy = 0; theSelect.pHaving = 0; diff --git a/src/update.c b/src/update.c index c914e61ab..93a67448c 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.54 2003/03/19 03:14:02 drh Exp $ +** $Id: update.c,v 1.55 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" @@ -21,14 +21,14 @@ */ void sqliteUpdate( Parse *pParse, /* The parser context */ - Token *pTableName, /* The table in which we should change things */ + SrcList *pTabList, /* The table in which we should change things */ ExprList *pChanges, /* Things to be changed */ Expr *pWhere, /* The WHERE clause. May be null */ int onError /* How to handle constraint errors */ ){ int i, j; /* Loop counters */ + char *zTab; /* Name of the table to be updated */ Table *pTab; /* The table to be updated */ - SrcList *pTabList = 0; /* Fake FROM clause containing only pTab */ int addr; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ @@ -53,28 +53,27 @@ void sqliteUpdate( if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; db = pParse->db; + assert( pTabList->nSrc==1 ); /* Check for the special case of a VIEW with one or more ON UPDATE triggers * defined */ - { - char *zTab = sqliteTableNameFromToken(pTableName); - - if( zTab != 0 ){ - pTab = sqliteFindTable(pParse->db, zTab); - if( pTab ){ - row_triggers_exist = - sqliteTriggersExist(pParse, pTab->pTrigger, - TK_UPDATE, TK_BEFORE, TK_ROW, pChanges) || - sqliteTriggersExist(pParse, pTab->pTrigger, - TK_UPDATE, TK_AFTER, TK_ROW, pChanges); - } - sqliteFree(zTab); - if( row_triggers_exist && pTab->pSelect ){ - /* Just fire VIEW triggers */ - sqliteViewTriggers(pParse, pTab, pWhere, onError, pChanges); - return; - } + zTab = pTabList->a[0].zName; + if( zTab != 0 ){ + pTab = sqliteFindTable(pParse->db, zTab); + if( pTab ){ + row_triggers_exist = + sqliteTriggersExist(pParse, pTab->pTrigger, + TK_UPDATE, TK_BEFORE, TK_ROW, pChanges) || + sqliteTriggersExist(pParse, pTab->pTrigger, + TK_UPDATE, TK_AFTER, TK_ROW, pChanges); + } + + if( row_triggers_exist && pTab->pSelect ){ + /* Just fire VIEW triggers */ + sqliteSrcListDelete(pTabList); + sqliteViewTriggers(pParse, pTab, pWhere, onError, pChanges); + return; } } @@ -83,9 +82,8 @@ void sqliteUpdate( ** will be calling are designed to work with multiple tables and expect ** an SrcList* parameter instead of just a Table* parameter. */ - pTabList = sqliteTableTokenToSrcList(pParse, pTableName); - if( pTabList==0 ) goto update_cleanup; - pTab = pTabList->a[0].pTab; + pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab); + if( pTab==0 ) 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; diff --git a/src/vdbe.c b/src/vdbe.c index 85baf6890..8e088b786 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -36,7 +36,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.208 2003/03/19 03:14:02 drh Exp $ +** $Id: vdbe.c,v 1.209 2003/03/20 01:16:59 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1210,7 +1210,6 @@ static void Cleanup(Vdbe *p){ */ void sqliteVdbeDelete(Vdbe *p){ int i; - sqlite *db = p->db; if( p==0 ) return; Cleanup(p); if( p->pPrev ){ @@ -1232,13 +1231,6 @@ void sqliteVdbeDelete(Vdbe *p){ sqliteFree(p->aOp[i].p3); } } - for(i=2; i<db->nDb; i++){ - if( db->aDb[i].pBt && db->aDb[i].zName==0 ){ - sqliteBtreeClose(db->aDb[i].pBt); - db->aDb[i].pBt = 0; - db->aDb[i].inTrans = 0; - } - } sqliteFree(p->aOp); sqliteFree(p->aLabel); sqliteFree(p->aStack); @@ -1505,6 +1497,9 @@ void sqliteVdbeMakeReady( int isExplain /* True if the EXPLAIN keywords is present */ ){ int n; +#ifdef MEMORY_DEBUG + extern int access(const char*,int); +#endif assert( p!=0 ); assert( p->aStack==0 ); @@ -3345,7 +3340,6 @@ case OP_SetCookie: { case OP_VerifyCookie: { int aMeta[SQLITE_N_BTREE_META]; assert( pOp->p1>=0 && pOp->p1<db->nDb ); - assert( db->aDb[pOp->p1].zName!=0 ); rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta); if( rc==SQLITE_OK && aMeta[1]!=pOp->p2 ){ sqliteSetString(&p->zErrMsg, "database schema has changed", 0); |