]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modify ATTACH and DETACH to execute at runtime instead of compile time. (CVS 2803)
authordanielk1977 <danielk1977@noemail.net>
Tue, 6 Dec 2005 17:19:11 +0000 (17:19 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 6 Dec 2005 17:19:11 +0000 (17:19 +0000)
FossilOrigin-Name: 5e04ec694add7a8331e3d6fbdfcaed51349ae7bc

manifest
manifest.uuid
src/attach.c
src/func.c
src/parse.y
src/sqliteInt.h
test/attach2.test

index 5f85343a919b0ea403936c97bdb83d1e49c98059..49f3cec97d53884bb04856717b0ec557a0579413 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Report\serrors\sout\sof\ssqlite3_open16().\s(CVS\s2802)
-D 2005-12-06T13:19:08
+C Modify\sATTACH\sand\sDETACH\sto\sexecute\sat\sruntime\sinstead\sof\scompile\stime.\s(CVS\s2803)
+D 2005-12-06T17:19:11
 F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -32,7 +32,7 @@ F sqlite3.def c413e514217736884254739a105c8c942fdf0c2f
 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
 F src/alter.c 7ed4b794c2e3a8ad8c1effe50202eaef42cedc23
 F src/analyze.c ea42005eed52c382fcc7ef66969e7f1858597633
-F src/attach.c 8c3e09452be967e005a016299a110ed8ee33606a
+F src/attach.c 39e678033d0be197dea4e9d5eeac2b2df51d6c9f
 F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
 F src/btree.c aa88194f460becf8fff6196996d6e38f1b37286e
 F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e
@@ -43,7 +43,7 @@ F src/date.c 8bc8d084a17d19c44d9cbf357b5f656db6706ce1
 F src/delete.c 6010a081edda9871895260def092e852f0bb60a0
 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
 F src/expr.c 540ed7eb44b79e5603c3656466bf1d7381abcfc7
-F src/func.c 7d81dccd9c440c6c4e761056333e629192814af0
+F src/func.c f5171a1bd0bc3eae91d37bd42724784570b203cd
 F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
 F src/insert.c 5393479164f317ea0aeec954c6500cafa097ef33
@@ -61,7 +61,7 @@ F src/os_win.c d962ac2dd0e482847e42b846d46cd044f97d1c32
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
 F src/pager.c 893cb2106261a4f77d84c1fa0d10a083e889b23b
 F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140
-F src/parse.y e4d57c2fd5cc02f19822ec41f6dc2bfc9bc85609
+F src/parse.y 87080d89439925de19f16189310d3dbc7f9ab3f6
 F src/pragma.c 2793699ab0d73fa730fa8c1c7521e9436604f024
 F src/prepare.c e93967011379051316728d316755f533a9bb438c
 F src/printf.c 3ea3a17d25d7ac498efc18007c70371a42c968f8
@@ -69,7 +69,7 @@ F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
 F src/select.c 0e4d3627fec4a445b45f6cb471f68aab9c97a8b3
 F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3
 F src/sqlite.h.in 8e648e1f386e4509f2f96c09ded7c07b0df0c9a2
-F src/sqliteInt.h 71dc0f753e9a646d9c9b3b6b5bb9d2fcc2dad9e5
+F src/sqliteInt.h bbc310a83a32476aa960055a166af4a0ef503a79
 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
 F src/tclsqlite.c a497c3adfd2c85da6a934331ec0041e47884fbcb
 F src/test1.c 0b4bf8ab9afb37f34a83c46f81de54adf519b23d
@@ -100,7 +100,7 @@ F test/alter3.test d4eecd8dbd008d0e66f1c201fa6dc2edca853c38
 F test/altermalloc.test 6e1f404ec021eb2ba6582e3c77b0a35cf206b7af
 F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0
 F test/attach.test dae07fa1554b618b9cc4c7bc349b3bc1a532180e
-F test/attach2.test 3396c012a39ddf7ba6b528d80bd79554168aa115
+F test/attach2.test 4c31484096fd24b7b98487f9c6d04d9f3f156c6c
 F test/attach3.test 63013383adc4380af69779f34f4af19bd49f7cbe
 F test/attachmalloc.test cdb26c42850f04698377ccec05f5fa89d987837c
 F test/auth.test 973ae7274eae32c4453fbbcbd0ec2b80c5b1eeb3
@@ -325,7 +325,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 0b82f9623cf25b1cb02f70628c992903a6e8ca1c
-R ad7e2ffd6d5056830e431f0a65615391
-U drh
-Z 553bce70d7b9b8480be2fd03ddd473e4
+P f5b58163d4520fa3e7137e8445a8ef19aae3e799
+R 5b292cae1efee3561e8e46d85db25e2a
+U danielk1977
+Z adc67f11e55d6ddbfd0953632e9d61d6
index bba8a407d3fd783d4d608d5d367edb7d710e396c..382185bb8de2da65d5d0ad76b99c3fe002af30f7 100644 (file)
@@ -1 +1 @@
-f5b58163d4520fa3e7137e8445a8ef19aae3e799
\ No newline at end of file
+5e04ec694add7a8331e3d6fbdfcaed51349ae7bc
\ No newline at end of file
index d7d9ef824effe75627321d7936fa2f20b8e5a7b7..0088417502243cd185b8737058bc46a39662ba8f 100644 (file)
 *************************************************************************
 ** This file contains code used to implement the ATTACH and DETACH commands.
 **
-** $Id: attach.c,v 1.35 2005/12/06 12:52:59 danielk1977 Exp $
+** $Id: attach.c,v 1.36 2005/12/06 17:19:11 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
 /*
-** This routine is called by the parser to process an ATTACH statement:
+** Resolve an expression that was part of an ATTACH or DETACH statement. This
+** is slightly different from resolving a normal SQL expression, because simple
+** identifiers are treated as strings, not possible column names or aliases.
 **
-**     ATTACH DATABASE filename AS dbname
+** i.e. if the parser sees:
 **
-** The pFilename and pDbname arguments are the tokens that define the
-** filename and dbname in the ATTACH statement.
+**     ATTACH DATABASE abc AS def
+**
+** it treats the two expressions as literal strings 'abc' and 'def' instead of
+** looking for columns of the same name.
+**
+** This only applies to the root node of pExpr, so the statement:
+**
+**     ATTACH DATABASE abc||def AS 'db2'
+**
+** will fail because neither abc or def can be resolved.
 */
-void sqlite3Attach(
-  Parse *pParse,       /* The parser context */
-  Token *pFilename,    /* Name of database file */
-  Token *pDbname,      /* Name of the database to use internally */
-  int keyType,         /* 0: no key.  1: TEXT,  2: BLOB */
-  Token *pKey          /* Text of the key for keytype 1 and 2 */
+int resolveAttachExpr(NameContext *pName, Expr *pExpr)
+{
+  int rc = SQLITE_OK;
+  if( pExpr ){
+    if( pExpr->op!=TK_ID ){
+      rc = sqlite3ExprResolveNames(pName, pExpr);
+    }else{
+      pExpr->op = TK_STRING;
+    }
+  }
+  return rc;
+}
+
+/*
+** An SQL user-function registered to do the work of an ATTACH statement. The
+** three arguments to the function come directly from an attach statement:
+**
+**     ATTACH DATABASE x AS y KEY z
+**
+**     SELECT sqlite_attach(x, y, z)
+**
+** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
+** third argument.
+*/
+static void attachFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
 ){
+  int i;
+  int rc = 0;
+  sqlite3 *db = sqlite3_user_data(context);
+  const char *zName;
+  const char *zFile;
   Db *aNew;
-  int rc, i;
-  char *zFile = 0;
-  char *zName = 0;
-  sqlite3 *db;
-  Vdbe *v;
+  char zErr[128];
+  char *zErrDyn = 0;
 
-  v = sqlite3GetVdbe(pParse);
-  if( !v ) return;
-  sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
-  sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
-  if( pParse->explain ) return;
-  db = pParse->db;
+  zFile = (const char *)sqlite3_value_text(argv[0]);
+  zName = (const char *)sqlite3_value_text(argv[1]);
+
+  /* Check for the following errors:
+  **
+  **     * Too many attached databases,
+  **     * Transaction currently open
+  **     * Specified database name already being used.
+  */
   if( db->nDb>=MAX_ATTACHED+2 ){
-    sqlite3ErrorMsg(pParse, "too many attached databases - max %d", 
-       MAX_ATTACHED);
-    pParse->rc = SQLITE_ERROR;
-    return;
+    sqlite3_snprintf(
+      127, zErr, "too many attached databases - max %d", MAX_ATTACHED
+    );
+    goto attach_error;
   }
-
   if( !db->autoCommit ){
-    sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
-    pParse->rc = SQLITE_ERROR;
-    return;
-  }
-
-  zFile = sqlite3NameFromToken(pFilename);
-  if( zFile==0 ){
-    goto attach_end;
-  }
-#ifndef SQLITE_OMIT_AUTHORIZATION
-  if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
-    goto attach_end;
-  }
-#endif /* SQLITE_OMIT_AUTHORIZATION */
-
-  zName = sqlite3NameFromToken(pDbname);
-  if( zName==0 ){
-    goto attach_end;
+    strcpy(zErr, "cannot ATTACH database within transaction");
+    goto attach_error;
   }
   for(i=0; i<db->nDb; i++){
     char *z = db->aDb[i].zName;
     if( z && sqlite3StrICmp(z, zName)==0 ){
-      sqlite3ErrorMsg(pParse, "database %s is already in use", zName);
-      pParse->rc = SQLITE_ERROR;
-      goto attach_end;
+      sqlite3_snprintf(127, zErr, "database %s is already in use", zName);
+      goto attach_error;
     }
   }
 
+  /* Allocate the new entry in the db->aDb[] array and initialise the schema
+  ** hash tables.
+  */
   if( db->aDb==db->aDbStatic ){
     aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
     if( aNew==0 ){
-      goto attach_end;
+      return;
     }
     memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
   }else{
     aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
     if( aNew==0 ){
-      goto attach_end;
+      return;
     } 
   }
   db->aDb = aNew;
@@ -98,45 +120,51 @@ void sqlite3Attach(
   sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
   sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
   sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
-  aNew->zName = zName;
-  zName = 0;
+  aNew->zName = sqliteStrDup(zName);
   aNew->safety_level = 3;
+  
+  /* Open the database file */
   rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
-  if( rc ){
-    sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
-  }
+
 #if SQLITE_HAS_CODEC
   {
     extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
-    char *zKey;
-    int nKey;
-    if( keyType==0 ){
-      /* No key specified.  Use the key from the main database */
-      extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
-      sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
-    }else if( keyType==1 ){
-      /* Key specified as text */
-      zKey = sqlite3NameFromToken(pKey);
-      nKey = strlen(zKey);
-    }else{
-      /* Key specified as a BLOB */
-      char *zTemp;
-      assert( keyType==2 );
-      pKey->z++;
-      pKey->n--;
-      zTemp = sqlite3NameFromToken(pKey);
-      zKey = sqlite3HexToBlob(zTemp);
-      sqliteFree(zTemp);
-    }
-    sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
-    if( keyType ){
-      sqliteFree(zKey);
+    extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
+
+    int t = sqlite3_value_type(argv[2]);
+    switch( t ){
+      case SQLITE_INTEGER:
+      case SQLITE_FLOAT:
+        zErrDyn = sqliteStrDup("Invalid key value");
+        rc = SQLITE_ERROR;
+        break;
+        
+      case SQLITE_TEXT:
+      case SQLITE_BLOB:
+        nKey = sqlite3_value_bytes(argv[2]);
+        zKey = (char *)sqlite3_value_blob(argv[2]);
+        sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+        break;
+
+      case SQLITE_NULL:
+        /* No key specified.  Use the key from the main database */
+        sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
+        sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+        break;
     }
   }
 #endif
-  db->flags &= ~SQLITE_Initialized;
-  if( pParse->nErr==0 && rc==SQLITE_OK ){
-    rc = sqlite3ReadSchema(pParse);
+
+  /* If the file was opened successfully, read the schema for the new database.
+  ** If this fails, or if opening the file failed, then close the file and 
+  ** remove the entry from the db->aDb[] array. i.e. put everything back the way
+  ** we found it.
+  */
+  if( rc==SQLITE_OK ){
+    db->flags &= ~SQLITE_Initialized;
+    sqlite3SafetyOn(db);
+    rc = sqlite3Init(db, &zErrDyn);
+    sqlite3SafetyOff(db);
   }
   if( rc ){
     int i = db->nDb - 1;
@@ -146,67 +174,162 @@ void sqlite3Attach(
       db->aDb[i].pBt = 0;
     }
     sqlite3ResetInternalSchema(db, 0);
-    assert( pParse->nErr>0 );  /* Always set by sqlite3ReadSchema() */
-    if( pParse->rc==SQLITE_OK ){
-      pParse->rc = SQLITE_ERROR;
-    }
     db->nDb = i;
+    sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
+    goto attach_error;
   }
+  
+  return;
 
-attach_end:
-  sqliteFree(zFile);
-  sqliteFree(zName);
+attach_error:
+  /* Return an error if we get here */
+  if( zErrDyn ){
+    sqlite3_result_error(context, zErrDyn, -1);
+    sqliteFree(zErrDyn);
+  }else{
+    zErr[sizeof(zErr)-1] = 0;
+    sqlite3_result_error(context, zErr, -1);
+  }
 }
 
 /*
-** This routine is called by the parser to process a DETACH statement:
+** An SQL user-function registered to do the work of an DETACH statement. The
+** three arguments to the function come directly from a detach statement:
 **
-**    DETACH DATABASE dbname
+**     DETACH DATABASE x
 **
-** The pDbname argument is the name of the database in the DETACH statement.
+**     SELECT sqlite_detach(x)
 */
-void sqlite3Detach(Parse *pParse, Token *pDbname){
+static void detachFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const char *zName = (const char *)sqlite3_value_text(argv[0]);
+  sqlite3 *db = sqlite3_user_data(context);
   int i;
-  sqlite3 *db;
-  Vdbe *v;
   Db *pDb = 0;
-  char *zName;
+  char zErr[128];
 
-  v = sqlite3GetVdbe(pParse);
-  if( !v ) return;
-  sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
-  sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
-  if( pParse->explain ) return;
-  db = pParse->db;
-  zName = sqlite3NameFromToken(pDbname);
-  if( zName==0 ) return;
+  assert(zName);
   for(i=0; i<db->nDb; i++){
     pDb = &db->aDb[i];
     if( pDb->pBt==0 ) continue;
     if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
   }
+
   if( i>=db->nDb ){
-    sqlite3ErrorMsg(pParse, "no such database: %z", zName);
-    return;
+    sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName);
+    goto detach_error;
   }
   if( i<2 ){
-    sqlite3ErrorMsg(pParse, "cannot detach database %z", zName);
-    return;
+    sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName);
+    goto detach_error;
   }
-  sqliteFree(zName);
   if( !db->autoCommit ){
-    sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
-    pParse->rc = SQLITE_ERROR;
-    return;
-  }
-#ifndef SQLITE_OMIT_AUTHORIZATION
-  if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
-    return;
+    strcpy(zErr, "cannot DETACH database within transaction");
+    goto detach_error;
   }
-#endif /* SQLITE_OMIT_AUTHORIZATION */
+
   sqlite3BtreeClose(pDb->pBt);
   pDb->pBt = 0;
   sqlite3ResetInternalSchema(db, 0);
+  return;
+
+detach_error:
+  sqlite3_result_error(context, zErr, -1);
+}
+
+/*
+** This procedure generates VDBE code for a single invocation of either the
+** sqlite_detach() or sqlite_attach() SQL user functions.
+*/
+static void codeAttach(
+  Parse *pParse,       /* The parser context */
+  int type,            /* Either SQLITE_ATTACH or SQLITE_DETACH */
+  const char *zFunc,   /* Either "sqlite_attach" or "sqlite_detach */
+  int nFunc,           /* Number of args to pass to zFunc */
+  Expr *pAuthArg,      /* Expression to pass to authorization callback */
+  Expr *pFilename,     /* Name of database file */
+  Expr *pDbname,       /* Name of the database to use internally */
+  Expr *pKey           /* Database key for encryption extension */
+){
+  int rc;
+  NameContext sName;
+  Vdbe *v;
+  FuncDef *pFunc;
+  sqlite3* db = pParse->db;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
+  if( !zAuthArg ){
+    goto attach_end;
+  }
+  if( sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0)!=SQLITE_OK ){
+    goto attach_end;
+  }
+#endif /* SQLITE_OMIT_AUTHORIZATION */
+
+  memset(&sName, 0, sizeof(NameContext));
+  sName.pParse = pParse;
+
+  if( 
+      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
+      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
+      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
+  ){
+    pParse->nErr++;
+    goto attach_end;
+  }
+
+  v = sqlite3GetVdbe(pParse);
+  sqlite3ExprCode(pParse, pFilename);
+  sqlite3ExprCode(pParse, pDbname);
+  sqlite3ExprCode(pParse, pKey);
+
+  assert(v || sqlite3Tsd()->mallocFailed);
+  if( v ){
+    sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
+    pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
+    sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
+
+    /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
+    ** statement only). For DETACH, set it to false (expire all existing
+    ** statements).
+    */
+    sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0);
+  }
+  
+attach_end:
+  sqlite3ExprDelete(pFilename);
+  sqlite3ExprDelete(pDbname);
+  sqlite3ExprDelete(pKey);
+  sqliteFree(zAuthArg);
+}
+
+/*
+** Called by the parser to compile a DETACH statement.
+**
+**     DETACH pDbname
+*/
+void sqlite3Detach(Parse *pParse, Expr *pDbname){
+  codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);
+}
+
+/*
+** Called by the parser to compile an ATTACH statement.
+**
+**     ATTACH p AS pDbname KEY pKey
+*/
+void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
+  codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
+}
+
+void sqlite3AttachFunctions(sqlite3 *db)
+{
+  static const int enc = SQLITE_UTF8;
+  sqlite3_create_function(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
+  sqlite3_create_function(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
 }
 
 /*
index 6071aa452b0397622c6749394797d46be08a1f78..c0038904be0f1602ec1daf628a8034dbe0e99930 100644 (file)
@@ -16,7 +16,7 @@
 ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: func.c,v 1.111 2005/10/13 02:09:50 drh Exp $
+** $Id: func.c,v 1.112 2005/12/06 17:19:11 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1025,6 +1025,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
 #ifndef SQLITE_OMIT_ALTERTABLE
   sqlite3AlterFunctions(db);
 #endif
+  sqlite3AttachFunctions(db);
   for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
     void *pArg = 0;
     switch( aAggs[i].argType ){
index 1fb8989668da7bddee2f35f452f5e3221510354c..5b2700a36fa723fed178bbbd277d601eb26f8182 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.185 2005/11/24 22:22:30 drh Exp $
+** @(#) $Id: parse.y,v 1.186 2005/12/06 17:19:11 danielk1977 Exp $
 */
 
 // All token codes are small integers with #defines that begin with "TK_"
@@ -990,20 +990,19 @@ cmd ::= DROP TRIGGER fullname(X). {
 %endif // !SQLITE_OMIT_TRIGGER
 
 //////////////////////// ATTACH DATABASE file AS name /////////////////////////
-cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
-  sqlite3Attach(pParse, &F, &D, K.type, &K.key);
+cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
+  sqlite3Attach(pParse, F, D, K);
 }
-%type key_opt {struct AttachKey}
-key_opt(A) ::= .                     { A.type = 0; }
-key_opt(A) ::= KEY ids(X).           { A.type=1; A.key = X; }
-key_opt(A) ::= KEY BLOB(X).          { A.type=2; A.key = X; }
+%type key_opt {Expr *}
+key_opt(A) ::= .                     { A = 0; }
+key_opt(A) ::= KEY expr(X).          { A = X; }
 
 database_kw_opt ::= DATABASE.
 database_kw_opt ::= .
 
 //////////////////////// DETACH DATABASE name /////////////////////////////////
-cmd ::= DETACH database_kw_opt nm(D). {
-  sqlite3Detach(pParse, &D);
+cmd ::= DETACH database_kw_opt expr(D). {
+  sqlite3Detach(pParse, D);
 }
 
 ////////////////////////// REINDEX collation //////////////////////////////////
index 05a5b3abe5a2e5492ea5b28d27e72c2eda8cff29..6c9ae45115e397dc7b6e3c4b972cd7105fe20516 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.429 2005/12/06 12:52:59 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.430 2005/12/06 17:19:11 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1603,8 +1603,8 @@ void sqlite3DeferForeignKey(Parse*, int);
 # define sqlite3AuthContextPush(a,b,c)
 # define sqlite3AuthContextPop(a)  ((void)(a))
 #endif
-void sqlite3Attach(Parse*, Token*, Token*, int, Token*);
-void sqlite3Detach(Parse*, Token*);
+void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
+void sqlite3Detach(Parse*, Expr*);
 int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename,
                        int omitJournal, int nCache, Btree **ppBtree);
 int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
@@ -1678,6 +1678,7 @@ void sqlite3RegisterLikeFunctions(sqlite3*, int);
 int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
 SqliteTsd *sqlite3Tsd();
 void sqlite3ClearMallocFailed();
+void sqlite3AttachFunctions(sqlite3 *);
 
 #ifdef SQLITE_SSE
 #include "sseInt.h"
index 700da9795213d0acf09b99246463b0a33554cf7b..c4ec2aa194a3e97b9a52adaefd14ee9ed151cc24 100644 (file)
@@ -12,7 +12,7 @@
 # focus of this script is testing the ATTACH and DETACH commands
 # and related functionality.
 #
-# $Id: attach2.test,v 1.32 2005/03/29 03:11:00 danielk1977 Exp $
+# $Id: attach2.test,v 1.33 2005/12/06 17:19:12 danielk1977 Exp $
 #
 
 set testdir [file dirname $argv0]
@@ -134,12 +134,14 @@ do_test attach2-3.1 {
   set DB [sqlite3 db test.db]
   set rc [catch {sqlite3_prepare $DB "ATTACH 'test2.db' AS t2" -1 TAIL} VM]
   if {$rc} {lappend rc $VM}
+  sqlite3_step $VM
   sqlite3_finalize $VM
   set rc
 } {0}
 do_test attach2-3.2 {
   set rc [catch {sqlite3_prepare $DB "DETACH t2" -1 TAIL} VM]
   if {$rc} {lappend rc $VM}
+  sqlite3_step $VM
   sqlite3_finalize $VM
   set rc
 } {0}