-C Modifications\sto\sthe\sVDBE\sto\ssupport\smore\sthan\sone\sdatabase\sfile.\s(CVS\s878)
-D 2003-03-19T03:14:01
+C Record\sthe\sdatabase\sname\sin\saddition\sto\sthe\stable\sname\sfor\sDELETE,\sINSERT,\nand\sUPDATE\sstatements.\s(CVS\s879)
+D 2003-03-20T01:16:58
F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729
F src/btree.c 327819bb858d534072f5004973f8bcdd50f133d6
F src/btree.h 8209bfadf5845d4fdaa60f471bb360f894cd4095
-F src/build.c be6db117e97d8c47596b09480b1aa2626f083ab3
-F src/delete.c d76f767696b0ee3661e937ccf4c6c45857c1b78e
+F src/build.c a965338bee81ce20fb0ce38419e9a9d159e720f0
+F src/delete.c 96a0ae021f960a7f2dbb3d1456802624deacfd3c
F src/encode.c faf03741efe921755ec371cf4a6984536de00042
-F src/expr.c bd690b3a6174e97a0f16800e78c8aeae749a4e71
+F src/expr.c 8af430cdbcb6122dd0320c8860602bd4cc778486
F src/func.c 90c583f0b91220f7cd411a2407deaf9327245d63
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
-F src/insert.c 02ac6147cb360385be94b0e6f572db131505d1c9
-F src/main.c d0418850385895202f9b28e0bd7d0b0fdfd868df
+F src/insert.c 1f31bdec48bd3915615e7251b74c27dcfaee9b88
+F src/main.c 66cd7ff4fc9f43719aaa2bc22db5babd8f437a9f
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
F src/os.c dfed46091f69cd2d1e601f8a214d41344f2b00b6
F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0
F src/pager.c dd1dfa4d929a58b44175f3117360ff1553671173
F src/pager.h 97d9a8cc5103750efd8037d71ebfb41849ef2f2f
-F src/parse.y 4c4b2ff3d20d4a2afb51f05ac18edde20a173abe
+F src/parse.y 7a9f333e7b09b0584fb4cc3799f8828f612e282e
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c 06ddc007c20862b3beb8c1c2504db664335d6706
F src/shell.c 0d260a007e0668fc7dda2b0c89bd597ef2966ec6
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 6f648803f2ffb9beb35cb1cfa42b323d55519171
-F src/sqliteInt.h 888faaa05195bcdb24a9aa22108894b778132cbc
+F src/sqliteInt.h ad95c947582d0584240ed413c5f1e9df71749ebe
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 8167d40fd34036701e07492d07a6f9e5c4015241
F src/test1.c 7ad4e6308dde0bf5a0f0775ce20cb2ec37a328f8
F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
-F src/tokenize.c bc40937d6666f188037aa3e54f0a2661a6fef6d1
-F src/trigger.c da142decd2808bc39e801f3bb1f161dbc2bd4005
-F src/update.c c523bf6ef4106ca45761a3e54fc6d09ee273804b
+F src/tokenize.c 675b4718d17c69fe7609dc8e85e426ef002be811
+F src/trigger.c aafc83ea108ec6a1b501b31b7fb6cebcd4725fd1
+F src/update.c 5c644629cc73993ba762bf186944816581213bd1
F src/util.c 73b668d1ed468df650dc00685a5e4ffa6887feb4
-F src/vdbe.c e2313377c463fdeba2e8eb3d9e3336292c60f51e
+F src/vdbe.c 7171dbe873760f403b2501e96fd3d1bd852b3ce8
F src/vdbe.h ed43771f1dc2b994d5c484fdf2eab357c6ef0ee3
F src/where.c 3111c1c209023e4f6b7b7eb0df48cef0010967c3
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 2aba40bea5fc1c4aef8cfd4c790d40808821ca14
-R 5e37bd21e0d92e541d7a5b6e1113c76c
+P 875da9eed981bfa27b98e95025f9fdbed74b4098
+R 08491389f4b4be3f29552d1284957d26
U drh
-Z 586a66fe460de3c14ba71e3472471b48
+Z 9eb95d01444da0b85f74b43fda15e074
-875da9eed981bfa27b98e95025f9fdbed74b4098
\ No newline at end of file
+a5d8fc95ee58dc3205a0bbbcadaa3b9c902a941b
\ No newline at end of file
** 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>
** 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;
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 ){
sqliteExprDelete(pList->a[i].pOn);
sqliteIdListDelete(pList->a[i].pUsing);
}
- sqliteFree(pList->a);
sqliteFree(pList);
}
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;
** 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"
return pTab;
}
-/*
-** 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 */
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 ){
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;
}
** 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;
** 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>
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);
** 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"
*/
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 */
/* 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 ){
pParse->nErr++;
goto insert_cleanup;
}
- sqliteFree(zTab);
- zTab = 0;
if( pTab==0 ) goto insert_cleanup;
}
insert_cleanup:
+ sqliteSrcListDelete(pTabList);
if( pList ) sqliteExprListDelete(pList);
if( pSelect ) sqliteSelectDelete(pSelect);
- if ( zTab ) sqliteFree(zTab);
sqliteIdListDelete(pColumn);
}
** 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"
return 0;
}
db->aDb[0].zName = "main";
+ db->aDb[1].zName = "temp";
/* Attempt to read the schema */
sqliteRegisterBuiltinFunctions(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);
** 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}
// 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.
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; }
}
}
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 ){
}
}
+%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; }
/////////////////////////// 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($$);}
////////////////////////// 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);}
////////////////////////// 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;}
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.
*************************************************************************
** 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"
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 */
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 */
};
/*
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*);
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*);
** 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"
{ "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 },
{ "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 },
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;
}
Expr * whenExpr;
dummyTablist.nSrc = 0;
- dummyTablist.a = 0;
/* Push an entry on to the trigger stack */
pTriggerStack->pTrigger = pTrigger;
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;
** 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"
*/
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 */
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;
}
}
** 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;
** 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>
*/
void sqliteVdbeDelete(Vdbe *p){
int i;
- sqlite *db = p->db;
if( p==0 ) return;
Cleanup(p);
if( p->pPrev ){
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);
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 );
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);