Allow CREATE TABLE and CREATE INDEX on attached databases. (CVS 1483)

FossilOrigin-Name: 4984a130ccf3b8e486941a5d0d0cc70a691f0dac
diff --git a/manifest b/manifest
index 8ebddf2..59832eb 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Tables\sand\sindices\suse\sthe\ssame\srecord\sformat.\s(CVS\s1482)
-D 2004-05-28T08:21:06
+C Allow\sCREATE\sTABLE\sand\sCREATE\sINDEX\son\sattached\sdatabases.\s(CVS\s1483)
+D 2004-05-28T11:37:27
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -26,7 +26,7 @@
 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
 F src/btree.c 6db76fbf63efd6008c5e6cb038ea40f94abffcf7
 F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545
-F src/build.c 35cbeb439b49cca5eb5e8a1de010a5194f4523e8
+F src/build.c 7ae5b3efeb30c7bd9e74d0ef6f41c2aa43d9c586
 F src/date.c 0eb922af5c5f5e2455f8dc2f98023ed3e04a857e
 F src/delete.c 66c5ab98cbad7e6b315fc997bfe6c8080784a701
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
@@ -48,14 +48,14 @@
 F src/os_win.h 5d41af24caaef6c13a2d8e2399caa1c57d45c84d
 F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
 F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
-F src/parse.y 63d39b6fe17d0c2c2c1f691e75a119a71d25439a
+F src/parse.y 1ab0393a97a17fa528b6762e14912d6ed982a28a
 F src/pragma.c f2b05b087a5764802296a28d7abdd75728beedee
 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
 F src/select.c 26f726b398af8708c81178acc9c68d64e78e6f5e
 F src/shell.c ed4d237b3e52a0a42512bfcc53530e46de20c28f
 F src/sqlite.h.in edc6408c7f53c2104f781a76b926036e17018ec9
-F src/sqliteInt.h 7978f406b41819f37fb6fb1be64115a2e7a28ab5
+F src/sqliteInt.h a52ac00d36fd231068c92df169474c473a5b4a61
 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
 F src/tclsqlite.c 877d0b96013a25b03ed6bd2d32917c42e84403bc
 F src/test1.c 32934478366531503d634968db414df17cb38238
@@ -64,21 +64,22 @@
 F src/test4.c 34848a9fd31aa65857b20a8bfc03aff77d8c3426
 F src/test5.c 9a1f15133f6955f067c5246e564723b5f23ff221
 F src/tokenize.c 50a87c7414de54a008427c9fed22e4e86efb6844
-F src/trigger.c 11afe9abfba13a2ba142944c797c952e162d117f
+F src/trigger.c 9ab75040aec65b593b54a7c1d4546f2f9ca058ef
 F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e
 F src/utf.c 59b5c8f06a4384a9f64933d6c57a2de02ce3673b
-F src/util.c d299404febd509556e720fbecadd880756b0f899
+F src/util.c 79a813dfc81329c5a1c5c9f7f40fbd4c570a7c75
 F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad
-F src/vdbe.c c661752ea19a8b5a041d8c4f234e1524f6b3250e
+F src/vdbe.c 3b208964add3da0c35c41955a95e6aa44ce75850
 F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb
 F src/vdbeInt.h c2bcd6e5a6e6a3753e4c5a368629c3a625719bfc
 F src/vdbeapi.c b0bb1f98c899ba00c8a5cbca612c2a28a1bb79de
-F src/vdbeaux.c 75428f01c80382b5e2c91ba424c2f73db7645cbc
+F src/vdbeaux.c 7a0dd0fb224285e8c5f0b2edf68a10b29fd512a8
 F src/vdbemem.c c97c145ff6d9fc5b4236704c04a65849117e6214
 F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
 F test/attach2.test 5472d442bb2ef1ee587e0ae7472bb68b52509a38
+F test/attach3.test 2cdfb3933e89a2336f68396f7505aa8dfcb88e9c
 F test/auth.test 95809b8f6a9bec18b94d28cafd03fe27d2f8a9e9
 F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
@@ -133,8 +134,8 @@
 F test/quick.test 8800cd2f6b45ce2cafadb0e3d5161688c61c946a
 F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
 F test/rowid.test 863e6e75878cccf03d166fe52023f20e09508683
-F test/select1.test 3bfcccd2eadcddbb07f1f5da6550aee8484ea4fb
-F test/select2.test a7226dc9de4ae713943a408bb8f9d3de46ee8015
+F test/select1.test 2f161f9cdf9fb577336bc8c930edade538567123
+F test/select2.test 91a2225926039b0d1687840735c284dbbf89f0bc
 F test/select3.test f8ff60d98c7b4898f5e7326f0c5929ba56f5d047
 F test/select4.test 86e72fc3b07de4fe11439aa419e37db3c49467e2
 F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081
@@ -203,7 +204,7 @@
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P ebd564d10b0ecd7ff15cbd6cd2b979c9f767476c
-R b3ce60af64a3cb61111b582624bafa84
-U drh
-Z 4321dd90c98a1981140d1a57a35baa0c
+P 1b15b32bdbccae555243e67aa011139c50dc2fb3
+R c5dc6cd70bfe11dc9fe64e163f737f43
+U danielk1977
+Z d391601bb46c037bdbb5671f03408a15
diff --git a/manifest.uuid b/manifest.uuid
index 300624b..f4fb818 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-1b15b32bdbccae555243e67aa011139c50dc2fb3
\ No newline at end of file
+4984a130ccf3b8e486941a5d0d0cc70a691f0dac
\ No newline at end of file
diff --git a/src/build.c b/src/build.c
index 679d019..fb0aec4 100644
--- a/src/build.c
+++ b/src/build.c
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.193 2004/05/22 08:09:11 danielk1977 Exp $
+** $Id: build.c,v 1.194 2004/05/28 11:37:27 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -399,18 +399,59 @@
 }
 
 /*
-** Generate code to open the appropriate master table.  The table
-** opened will be SQLITE_MASTER for persistent tables and 
-** SQLITE_TEMP_MASTER for temporary tables.  The table is opened
-** on cursor 0.
+** Open the sqlite_master table stored in database number iDb for
+** writing. The table is opened using cursor 0.
 */
-void sqlite3OpenMasterTable(Vdbe *v, int isTemp){
-  sqlite3VdbeAddOp(v, OP_Integer, isTemp, 0);
+void sqlite3OpenMasterTable(Vdbe *v, int iDb){
+  sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
   sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT);
   sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
 }
 
 /*
+** The token *pName contains the name of a database (either "main" or
+** "temp" or the name of an attached db). This routine returns the
+** index of the named database in db->aDb[], or -1 if the named db 
+** does not exist.
+*/
+int findDb(sqlite3 *db, Token *pName){
+  int i;
+  for(i=0; i<db->nDb; i++){
+    if( pName->n==strlen(db->aDb[i].zName) && 
+        0==sqlite3StrNICmp(db->aDb[i].zName, pName->z, pName->n) ){
+      return i;
+    }
+  }
+  return -1;
+}
+
+static int resolveSchemaName(
+  Parse *pParse, 
+  Token *pName1, 
+  Token *pName2, 
+  Token **pUnqual
+){
+  int iDb;
+  sqlite3 *db = pParse->db;
+
+  if( pName2 && pName2->n>0 ){
+    assert( !db->init.busy );
+    *pUnqual = pName2;
+    iDb = findDb(db, pName1);
+    if( iDb<0 ){
+      sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
+      pParse->nErr++;
+      return -1;
+    }
+  }else{
+    assert( db->init.iDb==0 || db->init.busy );
+    iDb = db->init.iDb;
+    *pUnqual = pName1;
+  }
+  return iDb;
+}
+
+/*
 ** Begin constructing a new table representation in memory.  This is
 ** the first of several action routines that get called in response
 ** to a CREATE TABLE statement.  In particular, this routine is called
@@ -430,7 +471,8 @@
 void sqlite3StartTable(
   Parse *pParse,   /* Parser context */
   Token *pStart,   /* The "CREATE" token */
-  Token *pName,    /* Name of table or view to create */
+  Token *pName1,   /* First part of the name of the table or view */
+  Token *pName2,   /* Second part of the name of the table or view */
   int isTemp,      /* True if this is a TEMP table */
   int isView       /* True if this is a VIEW */
 ){
@@ -439,9 +481,37 @@
   char *zName;
   sqlite *db = pParse->db;
   Vdbe *v;
-  int iDb;
+  int iDb;         /* Database number to create the table in */
+  Token *pName;    /* Unqualified name of the table to create */
 
-  pParse->sFirstToken = *pStart;
+  /* The table or view name to create is passed to this routine via tokens
+  ** pName1 and pName2. If the table name was fully qualified, for example:
+  **
+  ** CREATE TABLE xxx.yyy (...);
+  ** 
+  ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
+  ** the table name is not fully qualified, i.e.:
+  **
+  ** CREATE TABLE yyy(...);
+  **
+  ** Then pName1 is set to "yyy" and pName2 is "".
+  **
+  ** The call below sets the pName pointer to point at the token (pName1 or
+  ** pName2) that stores the unqualified table name. The variable iDb is
+  ** set to the index of the database that the table or view is to be
+  ** created in.
+  */
+  iDb = resolveSchemaName(pParse, pName1, pName2, &pName);
+  if( iDb<0 ) return;
+  if( isTemp && iDb>1 ){
+    /* If creating a temp table, the name may not be qualified */
+    sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
+    pParse->nErr++;
+    return;
+  }
+  if( isTemp ) iDb = 1;
+
+  pParse->sNameToken = *pName;
   zName = sqlite3TableNameFromToken(pName);
   if( zName==0 ) return;
   if( db->init.iDb==1 ) isTemp = 1;
@@ -449,7 +519,7 @@
   assert( (isTemp & 1)==isTemp );
   {
     int code;
-    char *zDb = isTemp ? "temp" : "main";
+    char *zDb = db->aDb[iDb].zName;
     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
       sqliteFree(zName);
       return;
@@ -473,7 +543,6 @@
     }
   }
 #endif
- 
 
   /* Before trying to create a temporary table, make sure the Btree for
   ** holding temporary tables is open.
@@ -504,7 +573,6 @@
   ** an existing temporary table, that is not an error.
   */
   pTable = sqlite3FindTable(db, zName, 0);
-  iDb = isTemp ? 1 : db->init.iDb;
   if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
     sqlite3ErrorMsg(pParse, "table %T already exists", pName);
     sqliteFree(zName);
@@ -539,14 +607,18 @@
   ** now.
   */
   if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
-    sqlite3BeginWriteOperation(pParse, 0, isTemp);
+    sqlite3BeginWriteOperation(pParse, 0, iDb);
     if( !isTemp ){
+      /* Every time a new table is created the file-format
+      ** and encoding meta-values are set in the database, in
+      ** case this is the first table created.
+      */
       sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
-      sqlite3VdbeAddOp(v, OP_SetCookie, 0, 1);
+      sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
       sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
-      sqlite3VdbeAddOp(v, OP_SetCookie, 0, 4);
+      sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
     }
-    sqlite3OpenMasterTable(v, isTemp);
+    sqlite3OpenMasterTable(v, iDb);
     sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
     sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
     sqlite3VdbeAddOp(v, OP_String, 0, 0);
@@ -721,7 +793,7 @@
     pTab->iPKey = iCol;
     pTab->keyConf = onError;
   }else{
-    sqlite3CreateIndex(pParse, 0, 0, pList, onError, 0, 0);
+    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0);
     pList = 0;
   }
 
@@ -850,14 +922,14 @@
 ** and the probability of hitting the same cookie value is only
 ** 1 chance in 2^32.  So we're safe enough.
 */
-void sqlite3ChangeCookie(sqlite *db, Vdbe *v){
+void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){
   if( db->next_cookie==db->aDb[0].schema_cookie ){
     unsigned char r;
     sqlite3Randomness(1, &r);
     db->next_cookie = db->aDb[0].schema_cookie + r + 1;
     db->flags |= SQLITE_InternChanges;
     sqlite3VdbeAddOp(v, OP_Integer, db->next_cookie, 0);
-    sqlite3VdbeAddOp(v, OP_SetCookie, 0, 0);
+    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
   }
 }
 
@@ -1015,21 +1087,28 @@
     sqlite3VdbeOp3(v, OP_String, 0, 0, p->zName, 0);
     sqlite3VdbeOp3(v, OP_String, 0, 0, p->zName, 0);
     sqlite3VdbeAddOp(v, OP_Dup, 4, 0);
-    sqlite3VdbeAddOp(v, OP_String, 0, 0);
     if( pSelect ){
       char *z = createTableStmt(p);
       n = z ? strlen(z) : 0;
+      sqlite3VdbeAddOp(v, OP_String, 0, 0);
       sqlite3VdbeChangeP3(v, -1, z, n);
       sqliteFree(z);
     }else{
+      if( p->pSelect ){
+        sqlite3VdbeOp3(v, OP_String, 0, 0, "CREATE VIEW ", P3_STATIC);
+      }else{
+        sqlite3VdbeOp3(v, OP_String, 0, 0, "CREATE TABLE ", P3_STATIC);
+      }
       assert( pEnd!=0 );
-      n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
-      sqlite3VdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
+      n = Addr(pEnd->z) - Addr(pParse->sNameToken.z) + 1;
+      sqlite3VdbeAddOp(v, OP_String, 0, 0);
+      sqlite3VdbeChangeP3(v, -1, pParse->sNameToken.z, n);
+      sqlite3VdbeAddOp(v, OP_Concat, 2, 0);
     }
     sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
     if( !p->iDb ){
-      sqlite3ChangeCookie(db, v);
+      sqlite3ChangeCookie(db, v, p->iDb);
     }
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     if( pSelect ){
@@ -1079,7 +1158,7 @@
   Token sEnd;
   DbFixer sFix;
 
-  sqlite3StartTable(pParse, pBegin, pName, isTemp, 1);
+  sqlite3StartTable(pParse, pBegin, pName, 0, isTemp, 1);
   p = pParse->pNewTable;
   if( p==0 || pParse->nErr ){
     sqlite3SelectDelete(pSelect);
@@ -1349,8 +1428,8 @@
       sqlite3VdbeChangeP3(v, base+1, pTable->zName, 0);
     }
 
-    if( pTable->iDb==0 ){
-      sqlite3ChangeCookie(db, v);
+    if( pTable->iDb!=1 ){  /* Temp database has no schema cookie */
+      sqlite3ChangeCookie(db, v, pTable->iDb);
     }
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     if( !isView ){
@@ -1517,14 +1596,15 @@
 */
 void sqlite3CreateIndex(
   Parse *pParse,   /* All information about this parse */
-  Token *pName,    /* Name of the index.  May be NULL */
-  SrcList *pTable, /* Name of the table to index.  Use pParse->pNewTable if 0 */
+  Token *pName1,   /* First part of index name. May be NULL */
+  Token *pName2,   /* Second part of index name. May be NULL */
+  Token *pTblName, /* Name of the table to index. Use pParse->pNewTable if 0 */
   IdList *pList,   /* A list of columns to be indexed */
   int onError,     /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
   Token *pStart,   /* The CREATE token that begins a CREATE TABLE statement */
   Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
 ){
-  Table *pTab;     /* Table to be indexed */
+  Table *pTab = 0; /* Table to be indexed */
   Index *pIndex;   /* The index to be created */
   char *zName = 0;
   int i, j;
@@ -1533,6 +1613,10 @@
   int isTemp;      /* True for a temporary index */
   sqlite *db = pParse->db;
 
+  int iDb;          /* Index of the database that is being written */
+  Token *pName = 0; /* Unqualified name of the index to create */
+
+/*
   if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index;
   if( db->init.busy 
      && sqlite3FixInit(&sFix, pParse, db->init.iDb, "index", pName)
@@ -1540,27 +1624,59 @@
   ){
     goto exit_create_index;
   }
+*/
 
   /*
   ** Find the table that is to be indexed.  Return early if not found.
   */
-  if( pTable!=0 ){
-    assert( pName!=0 );
-    assert( pTable->nSrc==1 );
-    pTab =  sqlite3SrcListLookup(pParse, pTable);
+  if( pTblName!=0 ){
+    char *zTblName;
+
+    /* Use the two-part index name to determine the database 
+    ** to search for the table. If no database name is specified, 
+    ** iDb is set to 0. In this case search both the temp and main
+    ** databases for the named table.
+    */
+    assert( pName1 && pName2 );
+    iDb = resolveSchemaName(pParse, pName1, pName2, &pName);
+    if( iDb<0 ) goto exit_create_index;
+
+    /* Now search for the table in the database iDb. If iDb is
+    ** zero, then search both the "main" and "temp" databases.
+    */
+    zTblName = sqlite3TableNameFromToken(pTblName);
+    if( !zTblName ){
+      pParse->nErr++;
+      pParse->rc = SQLITE_NOMEM;
+      goto exit_create_index;
+    }
+    assert( pName1!=0 );
+    if( iDb==0 ){
+      pTab = sqlite3FindTable(db, zTblName, "temp");
+    }
+    if( !pTab ){
+      pTab = sqlite3LocateTable(pParse, zTblName, db->aDb[iDb].zName);
+    }
+    sqliteFree( zTblName );
+    if( !pTab ) goto exit_create_index;
+    iDb = pTab->iDb;
   }else{
     assert( pName==0 );
     pTab =  pParse->pNewTable;
+    iDb = pTab->iDb;
   }
+
   if( pTab==0 || pParse->nErr ) goto exit_create_index;
   if( pTab->readOnly ){
     sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
     goto exit_create_index;
   }
+/*
   if( pTab->iDb>=2 && db->init.busy==0 ){
     sqlite3ErrorMsg(pParse, "table %s may not have indices added", pTab->zName);
     goto exit_create_index;
   }
+*/
   if( pTab->pSelect ){
     sqlite3ErrorMsg(pParse, "views may not be indexed");
     goto exit_create_index;
@@ -1611,8 +1727,6 @@
 #ifndef SQLITE_OMIT_AUTHORIZATION
   {
     const char *zDb = db->aDb[pTab->iDb].zName;
-
-    assert( pTab->iDb==db->init.iDb || isTemp );
     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
       goto exit_create_index;
     }
@@ -1648,7 +1762,7 @@
   pIndex->nColumn = pList->nId;
   pIndex->onError = onError;
   pIndex->autoIndex = pName==0;
-  pIndex->iDb = isTemp ? 1 : db->init.iDb;
+  pIndex->iDb = iDb;
 
   /* Scan the names of the columns of the table to be indexed and
   ** load the column indices into the Index structure.  Report an error
@@ -1706,7 +1820,7 @@
   ** "sqlite_master" table on the disk.  So do not write to the disk
   ** again.  Extract the table number from the db->init.newTnum field.
   */
-  if( db->init.busy && pTable!=0 ){
+  if( db->init.busy && pTblName!=0 ){
     pIndex->tnum = db->init.newTnum;
   }
 
@@ -1720,7 +1834,7 @@
   ** the latter case the index already exists on disk, which is why
   ** we don't want to recreate it.
   **
-  ** If pTable==0 it means this index is generated as a primary key
+  ** If pTblName==0 it means this index is generated as a primary key
   ** or UNIQUE constraint of a CREATE TABLE statement.  Since the table
   ** has just been created, it contains no data and the index initialization
   ** step can be skipped.
@@ -1730,36 +1844,38 @@
     Vdbe *v;
     int lbl1, lbl2;
     int i;
-    int addr;
 
     v = sqlite3GetVdbe(pParse);
     if( v==0 ) goto exit_create_index;
-    if( pTable!=0 ){
-      sqlite3BeginWriteOperation(pParse, 0, isTemp);
-      sqlite3OpenMasterTable(v, isTemp);
+    if( pTblName!=0 ){
+      sqlite3BeginWriteOperation(pParse, 0, iDb);
+      sqlite3OpenMasterTable(v, iDb);
     }
     sqlite3VdbeAddOp(v, OP_NewRecno, 0, 0);
     sqlite3VdbeOp3(v, OP_String, 0, 0, "index", P3_STATIC);
     sqlite3VdbeOp3(v, OP_String, 0, 0, pIndex->zName, 0);
     sqlite3VdbeOp3(v, OP_String, 0, 0, pTab->zName, 0);
-    sqlite3VdbeOp3(v, OP_CreateIndex, 0, isTemp,(char*)&pIndex->tnum,P3_POINTER);
+    sqlite3VdbeOp3(v, OP_CreateIndex, 0, iDb,(char*)&pIndex->tnum,P3_POINTER);
     pIndex->tnum = 0;
-    if( pTable ){
+    if( pTblName ){
       sqlite3VdbeCode(v,
           OP_Dup,       0,      0,
-          OP_Integer,   isTemp, 0,
+          OP_Integer,   iDb,    0,
       0);
       sqlite3VdbeOp3(v, OP_OpenWrite, 1, 0,
                      (char*)&pIndex->keyInfo, P3_KEYINFO);
     }
-    addr = sqlite3VdbeAddOp(v, OP_String, 0, 0);
+    sqlite3VdbeAddOp(v, OP_String, 0, 0);
     if( pStart && pEnd ){
-      n = Addr(pEnd->z) - Addr(pStart->z) + 1;
-      sqlite3VdbeChangeP3(v, addr, pStart->z, n);
+      sqlite3VdbeChangeP3(v, -1, "CREATE INDEX ", n);
+      sqlite3VdbeAddOp(v, OP_String, 0, 0);
+      n = Addr(pEnd->z) - Addr(pName->z) + 1;
+      sqlite3VdbeChangeP3(v, -1, pName->z, n);
+      sqlite3VdbeAddOp(v, OP_Concat, 2, 0);
     }
     sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
     sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
-    if( pTable ){
+    if( pTblName ){
       sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
       sqlite3VdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
       /* VdbeComment((v, "%s", pTab->zName)); */
@@ -1784,9 +1900,9 @@
       sqlite3VdbeAddOp(v, OP_Close, 2, 0);
       sqlite3VdbeAddOp(v, OP_Close, 1, 0);
     }
-    if( pTable!=0 ){
+    if( pTblName!=0 ){
       if( !isTemp ){
-        sqlite3ChangeCookie(db, v);
+        sqlite3ChangeCookie(db, v, iDb);
       }
       sqlite3VdbeAddOp(v, OP_Close, 0, 0);
       sqlite3EndWriteOperation(pParse);
@@ -1796,7 +1912,7 @@
   /* Clean up before exiting */
 exit_create_index:
   sqlite3IdListDelete(pList);
-  sqlite3SrcListDelete(pTable);
+  /* sqlite3SrcListDelete(pTable); */
   sqliteFree(zName);
   return;
 }
@@ -1863,8 +1979,8 @@
     sqlite3OpenMasterTable(v, pIndex->iDb);
     base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
     sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);
-    if( pIndex->iDb==0 ){
-      sqlite3ChangeCookie(db, v);
+    if( pIndex->iDb!=1 ){
+      sqlite3ChangeCookie(db, v, pIndex->iDb);
     }
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
diff --git a/src/parse.y b/src/parse.y
index 4a0657b..fc14b5d 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.119 2004/05/27 17:22:55 drh Exp $
+** @(#) $Id: parse.y,v 1.120 2004/05/28 11:37:28 danielk1977 Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -87,8 +87,8 @@
 ///////////////////// The CREATE TABLE statement ////////////////////////////
 //
 cmd ::= create_table create_table_args.
-create_table ::= CREATE(X) temp(T) TABLE nm(Y). {
-   sqlite3StartTable(pParse,&X,&Y,T,0);
+create_table ::= CREATE(X) temp(T) TABLE nm(Y) dbnm(Z). {
+   sqlite3StartTable(pParse,&X,&Y,&Z,T,0);
 }
 %type temp {int}
 temp(A) ::= TEMP.  {A = 1;}
@@ -188,7 +188,7 @@
 ccons ::= NULL onconf.
 ccons ::= NOT NULL onconf(R).               {sqlite3AddNotNull(pParse, R);}
 ccons ::= PRIMARY KEY sortorder onconf(R).  {sqlite3AddPrimaryKey(pParse,0,R);}
-ccons ::= UNIQUE onconf(R).           {sqlite3CreateIndex(pParse,0,0,0,R,0,0);}
+ccons ::= UNIQUE onconf(R).           {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);}
 ccons ::= CHECK LP expr RP onconf.
 ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
                                 {sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
@@ -233,7 +233,7 @@
 tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
                                              {sqlite3AddPrimaryKey(pParse,X,R);}
 tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
-                                       {sqlite3CreateIndex(pParse,0,0,X,R,0,0);}
+                                       {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);}
 tcons ::= CHECK expr onconf.
 tcons ::= FOREIGN KEY LP idxlist(FA) RP
           REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
@@ -727,12 +727,11 @@
 
 ///////////////////////////// The CREATE INDEX command ///////////////////////
 //
-cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X)
-        ON nm(Y) dbnm(D) LP idxlist(Z) RP(E) onconf(R). {
-  SrcList *pSrc = sqlite3SrcListAppend(0, &Y, &D);
+cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
+        ON nm(Y) LP idxlist(Z) RP(E) onconf(R). {
   if( U!=OE_None ) U = R;
   if( U==OE_Default) U = OE_Abort;
-  sqlite3CreateIndex(pParse, &X, pSrc, Z, U, &S, &E);
+  sqlite3CreateIndex(pParse, &X, &D, &Y, Z, U, &S, &E);
 }
 
 %type uniqueflag {int}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 454d4d4..7f77a47 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.256 2004/05/27 17:22:56 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.257 2004/05/28 11:37:28 danielk1977 Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -969,7 +969,7 @@
   int rc;              /* Return code from execution */
   char *zErrMsg;       /* An error message */
   Token sErrToken;     /* The token at which the error occurred */
-  Token sFirstToken;   /* The first token parsed */
+  Token sNameToken;    /* Token with unqualified schema object name */
   Token sLastToken;    /* The last token parsed */
   const char *zTail;   /* All SQL text past the last semicolon parsed */
   Table *pNewTable;    /* A table being constructed by CREATE TABLE */
@@ -1199,7 +1199,7 @@
 void sqlite3CommitInternalChanges(sqlite*);
 Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
 void sqlite3OpenMasterTable(Vdbe *v, int);
-void sqlite3StartTable(Parse*,Token*,Token*,int,int);
+void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
 void sqlite3AddColumn(Parse*,Token*);
 void sqlite3AddNotNull(Parse*, int);
 void sqlite3AddPrimaryKey(Parse*, IdList*, int);
@@ -1221,7 +1221,7 @@
 void sqlite3SrcListAssignCursors(Parse*, SrcList*);
 void sqlite3IdListDelete(IdList*);
 void sqlite3SrcListDelete(SrcList*);
-void sqlite3CreateIndex(Parse*,Token*,SrcList*,IdList*,int,Token*,Token*);
+void sqlite3CreateIndex(Parse*,Token*,Token*,Token*,IdList*,int,Token*,Token*);
 void sqlite3DropIndex(Parse*, SrcList*);
 void sqlite3AddKeyType(Vdbe*, ExprList*);
 void sqlite3AddIdxKeyType(Vdbe*, Index*);
@@ -1284,7 +1284,7 @@
 int sqlite3SafetyOn(sqlite*);
 int sqlite3SafetyOff(sqlite*);
 int sqlite3SafetyCheck(sqlite*);
-void sqlite3ChangeCookie(sqlite*, Vdbe*);
+void sqlite3ChangeCookie(sqlite*, Vdbe*, int);
 void sqlite3BeginTrigger(Parse*, Token*,int,int,IdList*,SrcList*,int,Expr*,int);
 void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
 void sqlite3DropTrigger(Parse*, SrcList*);
@@ -1350,4 +1350,4 @@
 void sqlite3Error(sqlite *, int, const char*,...);
 int sqlite3utfTranslate(const void *, int , u8 , void **, int *, u8);
 u8 sqlite3UtfReadBom(const void *zData, int nData);
-char *sqlite3HexToBlob(const char *z);
+void *sqlite3HexToBlob(const char *z);
diff --git a/src/trigger.c b/src/trigger.c
index 758513e..e224db6 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -205,7 +205,7 @@
     sqlite3VdbeChangeP3(v, addr+3, nt->table, 0); 
     sqlite3VdbeChangeP3(v, addr+5, pAll->z, pAll->n);
     if( nt->iDb==0 ){
-      sqlite3ChangeCookie(db, v);
+      sqlite3ChangeCookie(db, v, 0);
     }
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     sqlite3EndWriteOperation(pParse);
@@ -467,7 +467,7 @@
     base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
     sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
     if( pTrigger->iDb==0 ){
-      sqlite3ChangeCookie(db, v);
+      sqlite3ChangeCookie(db, v, 0);
     }
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     sqlite3EndWriteOperation(pParse);
diff --git a/src/util.c b/src/util.c
index 27c94bc..92dff91 100644
--- a/src/util.c
+++ b/src/util.c
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.92 2004/05/27 13:35:20 danielk1977 Exp $
+** $Id: util.c,v 1.93 2004/05/28 11:37:28 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -1299,7 +1299,7 @@
   return i;
 }
 
-char * sqlite3HexToBlob(const char *z){
+void *sqlite3HexToBlob(const char *z){
   char *zBlob;
   int i;
   int n = strlen(z);
diff --git a/src/vdbe.c b/src/vdbe.c
index 4d7ea7c..e695961 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,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.343 2004/05/28 08:21:09 drh Exp $
+** $Id: vdbe.c,v 1.344 2004/05/28 11:37:28 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -693,20 +693,39 @@
   Realify(pTos, 0);
   break;
 }
+
+#if 0
+/* Opcode: String8 * * P3
+**
+** This opcode does not exist at vdbe execution time.
+*/
+case OP_String8: {
+  break;
+}
+#endif
   
 /* Opcode: String * * P3
 **
 ** The string value P3 is pushed onto the stack.  If P3==0 then a
-** NULL is pushed onto the stack.
+** NULL is pushed onto the stack. P3 is assumed to be a nul terminated
+** string encoded with the database native encoding.
 */
 case OP_String: {
   pTos++;
   if( pOp->p3 ){
     pTos->flags = MEM_Str|MEM_Static|MEM_Term;
-    pTos->enc = TEXT_Utf8;
     pTos->z = pOp->p3;
     pTos->n = strlen(pTos->z);
+    pTos->enc = TEXT_Utf8;
     sqlite3VdbeChangeEncoding(pTos, db->enc);
+/*
+    if( db->enc==TEXT_Utf8 ){
+      pTos->n = strlen(pTos->z);
+    }else{
+      pTos->n  = sqlite3utf16ByteLen(pTos->z, -1);
+    }
+    pTos->enc = db->enc;
+*/
   }else{
     pTos->flags = MEM_Null;
   }
@@ -726,7 +745,11 @@
 /* Opcode: Blob P1 * P3
 **
 ** P3 points to a blob of data P1 bytes long. Push this
-** value onto the stack.
+** value onto the stack. This instruction is not coded directly
+** by the compiler. Instead, the compiler layer specifies
+** an OP_HexBlob opcode, with the hex string representation of
+** the blob as P3. This opcode is transformed to an OP_Blob
+** before execution (within the sqlite3_prepare() function).
 */
 case OP_Blob: {
   pTos++;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index e643284..93a30fd 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -610,7 +610,8 @@
 ** If pOp is an OP_HexBlob opcode, then transform it to an OP_Blob
 ** opcode. 
 */
-static int translateOp(Op *pOp){
+static int translateOp(Op *pOp, u8 enc){
+  
   if( pOp->opcode==OP_HexBlob ){
     pOp->p1 = strlen(pOp->p3)/2;
     if( pOp->p1 ){
@@ -627,6 +628,28 @@
     }
     pOp->opcode = OP_Blob;
   }
+
+  else if( pOp->opcode==OP_String8 ){
+    if( pOp->p3 ){
+      void *z = 0;
+      switch( enc ){
+        case TEXT_Utf16be:
+          z = sqlite3utf8to16be(pOp->p3, -1);
+          if( !z ) return SQLITE_NOMEM;
+          break;
+        case TEXT_Utf16le:
+          z = sqlite3utf8to16be(pOp->p3, -1);
+          if( !z ) return SQLITE_NOMEM;
+          break;
+      }
+      if( z ){
+        if( pOp->p3type==P3_DYNAMIC ) sqliteFree( pOp->p3 );
+        
+      }
+    }
+    pOp->opcode = OP_String;
+  }
+
   return SQLITE_OK;
 }
 
@@ -704,7 +727,7 @@
   if( !isExplain ){
     int i;
     for(i=0; i<p->nOp; i++){
-      translateOp(&p->aOp[i]);
+      translateOp(&p->aOp[i], p->db->enc);
     }
   }
 }
diff --git a/test/attach3.test b/test/attach3.test
new file mode 100644
index 0000000..06ccbff
--- /dev/null
+++ b/test/attach3.test
@@ -0,0 +1,89 @@
+# 2003 July 1
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this script is testing the ATTACH and DETACH commands
+# and schema changes to attached databases.
+#
+# $Id: attach3.test,v 1.1 2004/05/28 11:37:29 danielk1977 Exp $
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Create tables t1 and t2 in the main database
+execsql {
+  CREATE TABLE t1(a, b);
+  CREATE TABLE t2(c, d);
+}
+
+# Create tables t1 and t2 in database file test2.db
+file delete -force test2.db
+sqlite db2 test2.db
+execsql {
+  CREATE TABLE t1(a, b);
+  CREATE TABLE t2(c, d);
+} db2
+db2 close
+
+# Create a table in the auxilary database.
+do_test attach3-1 {
+  execsql {
+    ATTACH 'test2.db' AS aux;
+  }
+} {}
+do_test attach3-2 {
+  execsql {
+    CREATE TABLE aux.t3(e, f);
+  }
+} {}
+do_test attach3-3 {
+  execsql {
+    SELECT * FROM sqlite_master WHERE name = 't3';
+  }
+} {}
+do_test attach3-4 {
+  execsql {
+    SELECT * FROM aux.sqlite_master WHERE name = 't3';
+  }
+} {table t3 t3 4 {CREATE TABLE t3(e, f)}}
+do_test attach3-5 {
+  execsql {
+    INSERT INTO t3 VALUES(1, 2);
+    SELECT * FROM t3;
+  }
+} {1 2}
+
+# Create an index on the auxilary database table.
+do_test attach4-1 {
+  execsql {
+    CREATE INDEX aux.i1 on t3(e);
+  }
+} {}
+execsql {
+  pragma vdbe_trace = off;
+}
+do_test attach4-2 {
+  execsql {
+    SELECT * FROM sqlite_master WHERE name = 'i1';
+  }
+} {}
+do_test attach4-3 {
+  execsql {
+    SELECT * FROM aux.sqlite_master WHERE name = 'i1';
+  }
+} {index i1 t3 5 {CREATE INDEX i1 on t3(e)}}
+
+finish_test
+
+
+
+
diff --git a/test/select1.test b/test/select1.test
index ab6d60b..3e647b3 100644
--- a/test/select1.test
+++ b/test/select1.test
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: select1.test,v 1.31 2004/05/12 11:24:03 danielk1977 Exp $
+# $Id: select1.test,v 1.32 2004/05/28 11:37:29 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -535,14 +535,17 @@
 
 # Check the behavior when the result set is empty
 #
-do_test select1-9.1 {
-  catch {unset r}
-  set r(*) {}
-  db eval {SELECT * FROM test1 WHERE f1<0} r {}
-  set r(*)
-} {}
+# SQLite v3 always sets r(*).
+#
+# do_test select1-9.1 {
+#   catch {unset r}
+#   set r(*) {}
+#   db eval {SELECT * FROM test1 WHERE f1<0} r {}
+#   set r(*)
+# } {}
 do_test select1-9.2 {
   execsql {PRAGMA empty_result_callbacks=on}
+  catch {unset r}
   set r(*) {}
   db eval {SELECT * FROM test1 WHERE f1<0} r {}
   set r(*)
diff --git a/test/select2.test b/test/select2.test
index 73ed90f..82304b1 100644
--- a/test/select2.test
+++ b/test/select2.test
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: select2.test,v 1.21 2004/05/27 17:22:56 drh Exp $
+# $Id: select2.test,v 1.22 2004/05/28 11:37:29 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -30,6 +30,7 @@
 do_test select2-1.1 {
   set sql {SELECT DISTINCT f1 FROM tbl1 ORDER BY f1}
   set r {}
+  catch {unset data}
   db eval $sql data {
     set f1 $data(f1)
     lappend r $f1: