aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2003-03-20 01:16:58 +0000
committerdrh <drh@noemail.net>2003-03-20 01:16:58 +0000
commit113088ec685755a8abc94ddadc7d0e57dba9c914 (patch)
tree10f7dfca4a91abe824f641dafcacf41483cf476c /src
parent001bbcbb8fa5a55e9950445c6287a1fc0496e83e (diff)
downloadsqlite-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.c62
-rw-r--r--src/delete.c42
-rw-r--r--src/expr.c8
-rw-r--r--src/insert.c13
-rw-r--r--src/main.c6
-rw-r--r--src/parse.y43
-rw-r--r--src/sqliteInt.h14
-rw-r--r--src/tokenize.c5
-rw-r--r--src/trigger.c22
-rw-r--r--src/update.c46
-rw-r--r--src/vdbe.c14
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);