Record the database name in addition to the table name for DELETE, INSERT,
and UPDATE statements. (CVS 879) FossilOrigin-Name: a5d8fc95ee58dc3205a0bbbcadaa3b9c902a941b
This commit is contained in:
parent
001bbcbb8f
commit
113088ec68
32
manifest
32
manifest
@ -1,5 +1,5 @@
|
||||
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
|
||||
@ -21,39 +21,39 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
||||
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
|
||||
@ -155,7 +155,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
|
||||
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
|
||||
|
@ -1 +1 @@
|
||||
875da9eed981bfa27b98e95025f9fdbed74b4098
|
||||
a5d8fc95ee58dc3205a0bbbcadaa3b9c902a941b
|
62
src/build.c
62
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;
|
||||
|
42
src/delete.c
42
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"
|
||||
|
||||
@ -41,42 +41,17 @@ Table *sqliteTableNameToTable(Parse *pParse, const char *zTab){
|
||||
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 */
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
13
src/insert.c
13
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
43
src/parse.y
43
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.
|
||||
|
@ -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*);
|
||||
|
@ -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 },
|
||||
|
@ -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;
|
||||
|
44
src/update.c
44
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);
|
||||
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( 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;
|
||||
}
|
||||
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;
|
||||
|
14
src/vdbe.c
14
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);
|
||||
|
Loading…
Reference in New Issue
Block a user