]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Record the database name in addition to the table name for DELETE, INSERT,
authordrh <drh@noemail.net>
Thu, 20 Mar 2003 01:16:58 +0000 (01:16 +0000)
committerdrh <drh@noemail.net>
Thu, 20 Mar 2003 01:16:58 +0000 (01:16 +0000)
and UPDATE statements. (CVS 879)

FossilOrigin-Name: a5d8fc95ee58dc3205a0bbbcadaa3b9c902a941b

13 files changed:
manifest
manifest.uuid
src/build.c
src/delete.c
src/expr.c
src/insert.c
src/main.c
src/parse.y
src/sqliteInt.h
src/tokenize.c
src/trigger.c
src/update.c
src/vdbe.c

index d9eb81fc87375a21c061d5b26cd358e67affd567..29ccadec49bc0aef52f31642bed9f32d3d87ff26 100644 (file)
--- a/manifest
+++ b/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
index 35b85046ec2ac3582372c1ebb44d443e094ad45a..446ef24f08ad0361bd74e04b9b0ef21d44cba061 100644 (file)
@@ -1 +1 @@
-875da9eed981bfa27b98e95025f9fdbed74b4098
\ No newline at end of file
+a5d8fc95ee58dc3205a0bbbcadaa3b9c902a941b
\ No newline at end of file
index 0c763d07a7def7f763cf7e25e10d225ddcd50f90..ba6da93c3e387464291375c6711dfcaa454ba264 100644 (file)
@@ -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;
index 62bcf9ca1e697fc5ff0a203370b23e03c69673a8..c55c6f37ecc8aaf5b6122ebc6b391c167585a439 100644 (file)
@@ -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;
index 8ee9802d5dde95717b98c6ed8dd1ef32ab390e6e..47a7dd1a8b1d96d27a59c1e809562657881ada06 100644 (file)
@@ -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);
index 5b96f48a1b81824cbe1dfd5bd5e008fbf84fae26..5ed66168cce1d01a8b0082a25d7f704758715d61 100644 (file)
@@ -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"
 
 */
 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);
 }
 
index cf1481418d28e8c882a6add1bcfed73a5b1b88df..60cf794dc5b8d970d533373b30b7d0127b056520 100644 (file)
@@ -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);
index e38522ec18801d4a20668743c5088979e0946d4d..17d137d5fd30e24beb680972f7b7c18b4e752c02 100644 (file)
@@ -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.
index 63610ae8ea47fadba8dedacd2f500174d957d2e9..0e7090ea4180b80794f7dc021d9f7a36e9e57ec7 100644 (file)
@@ -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*);
index 7dd49b21a4a3c5d370d0c3b606e64fa9abfe4797..d30804294de8b2cc70289531b6a7f48915dae14a 100644 (file)
@@ -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 },
index 03032fe259b2ea973e2c297c27e1d6038f113f86..76bdc77ba87a7639f9ac5d355d1aaf0e359a1ab7 100644 (file)
@@ -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;
index c914e61abbdfc1a89361418f355e41644c4d9f2e..93a67448c4186f8a214b99c53db880a6658f2df3 100644 (file)
@@ -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"
 
 */
 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;
index 85baf68903a8877f252efdcffe2c162cfc32dca2..8e088b786de6b52ce4109d1bc8bed7765bf823f8 100644 (file)
@@ -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);