]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
:-) (CVS 15)
authordrh <drh@noemail.net>
Tue, 30 May 2000 16:27:03 +0000 (16:27 +0000)
committerdrh <drh@noemail.net>
Tue, 30 May 2000 16:27:03 +0000 (16:27 +0000)
FossilOrigin-Name: 8d66c7355de1d87b25c4fb92d0ef3603da72899a

manifest
manifest.uuid
src/build.c
src/parse.y
src/sqliteInt.h
src/tokenize.c
src/util.c
src/vdbe.c
src/vdbe.h
test/table.test

index 6abbd882b3529d0a1f0be0e589336bf5b87a5201..48d5603d3a97c46eb2c5a3a0e8b1b93c982ba19c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,31 +1,31 @@
-C :-)\s(CVS\s14)
-D 2000-05-30T13:44:19
+C :-)\s(CVS\s15)
+D 2000-05-30T16:27:04
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
 F Makefile.in 89921c1ee4de75275bfadfbac198396da31704d1
 F README 6b5960603c7f8bf42fc022b4b6436f242f238dbb
 F configure 00a5b5c82147a576fa6e82d7c1b0d55c321d6d2c x
 F configure.in 6ccfd5fc80517f7cfe605a7fc7e0f62d962a233c
 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
-F src/build.c bc81ec2f7c3296c1f784f7c94d2d8afea9f787e7
+F src/build.c 971796c068b8ae25b476f924e5e0da0b57adb9e6
 F src/dbbe.c ab05293e89525041eaab8b4aca10516db3648792
 F src/dbbe.h bedeb3a0985bb584458e7849fb59927e99e751e6
 F src/main.c 25cce7bce0eb3ba10bada7c05f4b38dc6dbbc86f
-F src/parse.y 265c8596598afba0a94b94acd9c866d01603dfe5
+F src/parse.y 50ca06d471132e16bb47c56f19553e4efd5b3d4a
 F src/shell.c 125f84ea5f8b725ba474d4702b575d062cc94d92
 F src/sqlite.h 2397c17a8f4ca90c09acab0100dc7e2f8f441b69
-F src/sqliteInt.h 562760efc29cf5b37a9029de04a5a8bca156f025
+F src/sqliteInt.h 749da8b3e4ce146fd172aeb59b6db04c57726d7a
 F src/tclsqlite.c 9efd29f79ded6a900aa3d142169c8bfe03b7affd
-F src/tokenize.c 948b8897ba211b58069d4a4465be23a2c639cf18
-F src/util.c dc1e1814cf69587e6ed58b82dd880ddb2165f3ce
-F src/vdbe.c 80132b6bb9a744d1990a1c16666d54baaff2dbc3
-F src/vdbe.h e721ad308f2e6ca805cebc4dd0a196ce4419d030
+F src/tokenize.c e176b2c1c38e11482ee3419d6b50b733860a1587
+F src/util.c 2a0314dcc9de230526380765339071a5b304d70d
+F src/vdbe.c 117ce5541143e3af9dccdc15c22c4920a7b9bdb4
+F src/vdbe.h 03de26632f2e608c2a44a40262fbba21a8bdfd81
 F src/where.c be3973952e9bb5d2bb0bc5523b03f5d1f9e9d6f9
 F test/all.test 66a8a5b8291a472157944edcdce51a320ebd1f35
 F test/delete.test 814d53e3b0d2d7069fb17e005d4041454d6585d4
 F test/expr.test 11e00880d2de0f60ff1ba7fdd4e09a0d72a01910
 F test/index.test 8d4f26901a5582daa353fe3c8266cbf4a53af830
 F test/insert.test 161bc67a4189738c559e3569323ceae31f4d49d6
-F test/table.test 2d6b3ba1024032d341aec0d3c48272c8407485b4
+F test/table.test 85d6f410d127ec508c6640f02d7c40d218414e81
 F test/tester.tcl 70d25b7ced0a958bc377c72399b3dc6bf6a2d09e
 F test/update.test 69459302ea75cafac1479e60b0e36efb88123c0e
 F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b
@@ -37,7 +37,7 @@ F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
 F www/c_interface.tcl f875864edf7974157d1c257ca08de854660882a5
 F www/index.tcl 2466d1b2e26c6f354b0acedee12025309a216799
 F www/sqlite.tcl 947e067bcc347dc767af4c1a6e5a8d47d8404aa3
-P 191a7f484e0a10839e7e1c8eb6658536643e4756
-R 0c03c3a3c9ac1b3b825b1193112ad5a4
+P 1bb8ee8d9f1d3c409a11910e7552e4bb5e7f5f87
+R 0bda635e569bcbbf1f49ce4a3f5d3df9
 U drh
-Z df606080358f2355e3007d65ffed4f54
+Z 1c759b788ddf2200404a81ace8a2be6e
index 4e7f9b5c69675cdd60e6fd455afb07497d878ff8..61ae20b3fe64e6ad3f0eb08f24b25ad6b94285df 100644 (file)
@@ -1 +1 @@
-1bb8ee8d9f1d3c409a11910e7552e4bb5e7f5f87
\ No newline at end of file
+8d66c7355de1d87b25c4fb92d0ef3603da72899a
\ No newline at end of file
index 40c4d39c954cbaa0f3fc16bf7f781e5325d1b46c..34d200d26567dbeb8a430c30f3fd6ce905750d7c 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** when syntax rules are reduced.
 **
-** $Id: build.c,v 1.6 2000/05/30 13:44:19 drh Exp $
+** $Id: build.c,v 1.7 2000/05/30 16:27:04 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -191,6 +191,7 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
 static char *sqliteTableNameFromToken(Token *pName){
   char *zName = 0;
   sqliteSetNString(&zName, pName->z, pName->n, 0);
+  sqliteDequote(zName);
   return zName;
 }
 
@@ -252,6 +253,7 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
   pz = &p->azCol[p->nCol++];
   *pz = 0;
   sqliteSetNString(pz, pName->z, pName->n, 0);
+  sqliteDequote(*pz);
 }
 
 /*
@@ -665,6 +667,7 @@ ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
   pList->a[i].zName = 0;
   if( pName ){
     sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
+    sqliteDequote(pList->a[i].zName);
   }
   return pList;
 }
@@ -702,6 +705,7 @@ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
   memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
   if( pToken ){
     sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0);
+    sqliteDequote(pList->a[pList->nId].zName);
   }
   pList->nId++;
   return pList;
@@ -714,6 +718,7 @@ void sqliteIdListAddAlias(IdList *pList, Token *pToken){
   if( pList && pList->nId>0 ){
     int i = pList->nId - 1;
     sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
+    sqliteDequote(pList->a[i].zAlias);
   }
 }
 
@@ -1433,3 +1438,85 @@ update_cleanup:
   sqliteExprDelete(pWhere);
   return;
 }
+
+/*
+** The COPY command is for compatibility with PostgreSQL and specificially
+** for the ability to read the output of pg_dump.  The format is as
+** follows:
+**
+**    COPY table FROM file [USING DELIMITERS string]
+**
+** "table" is an existing table name.  We will read lines of code from
+** file to fill this table with data.  File might be "stdin".  The optional
+** delimiter string identifies the field separators.  The default is a tab.
+*/
+void sqliteCopy(
+  Parse *pParse,       /* The parser context */
+  Token *pTableName,   /* The name of the table into which we will insert */
+  Token *pFilename,    /* The file from which to obtain information */
+  Token *pDelimiter    /* Use this as the field delimiter */
+){
+  Table *pTab;
+  char *zTab;
+  int i, j;
+  Vdbe *v;
+  int addr, end;
+  Index *pIdx;
+
+  zTab = sqliteTableNameFromToken(pTableName);
+  pTab = sqliteFindTable(pParse->db, zTab);
+  sqliteFree(zTab);
+  if( pTab==0 ){
+    sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, 
+        pTableName->z, pTableName->n, 0);
+    pParse->nErr++;
+    goto copy_cleanup;
+  }
+  if( pTab->readOnly ){
+    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
+        " may not be modified", 0);
+    pParse->nErr++;
+    goto copy_cleanup;
+  }
+  v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  if( v ){
+    addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
+    sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
+    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
+    for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+      sqliteVdbeAddOp(v, OP_Open, i, 0, pIdx->zName, 0);
+    }
+    end = sqliteVdbeMakeLabel(v);
+    addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
+    if( pDelimiter ){
+      sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
+      sqliteVdbeDequoteP3(v, addr);
+    }else{
+      sqliteVdbeChangeP3(v, addr, "\t", 1);
+    }
+    sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0);
+    if( pTab->pIndex ){
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+    }
+    for(i=0; i<pTab->nCol; i++){
+      sqliteVdbeAddOp(v, OP_FileField, i, 0, 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
+    for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+      if( pIdx->pNext ){
+        sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+      }
+      for(j=0; j<pIdx->nField; j++){
+        sqliteVdbeAddOp(v, OP_FileField, pIdx->aiField[j], 0, 0, 0);
+      }
+      sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_PutIdx, i, 0, 0, 0);
+    }
+    sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
+    sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, end);
+  }
+  
+copy_cleanup:
+  return;
+}
index 65ee04244458f91c62df6dd8b97501bdc2cac3f3..7b58846e61892ff8d26bcdd4ba69eb4f551bb0df 100644 (file)
@@ -26,7 +26,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.1 2000/05/29 20:42:06 drh Exp $
+** @(#) $Id: parse.y,v 1.2 2000/05/30 16:27:04 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -65,7 +65,7 @@ explain ::= EXPLAIN.    {pParse->explain = 1;}
 // The first form of a command is a CREATE TABLE statement.
 //
 cmd ::= create_table create_table_args.
-create_table ::= CREATE(X) TABLE ID(Y).    {sqliteStartTable(pParse,&X,&Y);}
+create_table ::= CREATE(X) TABLE id(Y).    {sqliteStartTable(pParse,&X,&Y);}
 create_table_args ::= LP columnlist conslist_opt RP(X).
                                            {sqliteEndTable(pParse,&X);}
 columnlist ::= columnlist COMMA column.
@@ -76,7 +76,10 @@ columnlist ::= column.
 // an elaborate typename.  Perhaps someday we'll do something with it.
 //
 column ::= columnid type carglist. 
-columnid ::= ID(X).                {sqliteAddColumn(pParse,&X);}
+columnid ::= id(X).                {sqliteAddColumn(pParse,&X);}
+%type id {Token}
+id(A) ::= ID(X).     {A = X;}
+id(A) ::= STRING(X). {A = X;}
 type ::= typename.
 type ::= typename LP signed RP.
 type ::= typename LP signed COMMA signed RP.
@@ -112,12 +115,12 @@ tcons2 ::= PRIMARY KEY LP idxlist(X) RP.
       {sqliteCreateIndex(pParse,0,0,X,0,0);}
 tcons2 ::= UNIQUE LP idlist RP.
 tcons2 ::= CHECK expr.
-idlist ::= idlist COMMA ID.
-idlist ::= ID.
+idlist ::= idlist COMMA id.
+idlist ::= id.
 
 // The next command format is dropping tables.
 //
-cmd ::= DROP TABLE ID(X).          {sqliteDropTable(pParse,&X);}
+cmd ::= DROP TABLE id(X).          {sqliteDropTable(pParse,&X);}
 
 // The select statement
 //
@@ -149,8 +152,8 @@ selcollist(A) ::= sclp(P) expr(X) AS STRING(Y).
 from(A) ::= FROM seltablist(X).               {A = X;}
 stl_prefix(A) ::= seltablist(X) COMMA.        {A = X;}
 stl_prefix(A) ::= .                           {A = 0;}
-seltablist(A) ::= stl_prefix(X) ID(Y).        {A = sqliteIdListAppend(X,&Y);}
-seltablist(A) ::= stl_prefix(X) ID(Y) AS ID(Z).
+seltablist(A) ::= stl_prefix(X) id(Y).        {A = sqliteIdListAppend(X,&Y);}
+seltablist(A) ::= stl_prefix(X) id(Y) AS id(Z).
    {A = sqliteIdListAppend(X,&Y);
     sqliteIdListAddAlias(A,&Z);}
 
@@ -300,4 +303,9 @@ idxlist(A) ::= idxitem(Y).
      {A = sqliteIdListAppend(0,&Y);}
 idxitem(A) ::= ID(X).           {A = X;}
 
-cmd ::= DROP INDEX ID(X).       {sqliteDropIndex(pParse, &X);}
+cmd ::= DROP INDEX id(X).       {sqliteDropIndex(pParse, &X);}
+
+cmd ::= COPY id(X) FROM id(Y) USING DELIMITERS STRING(Z).
+    {sqliteCopy(pParse,&X,&Y,&Z);}
+cmd ::= COPY id(X) FROM id(Y).
+    {sqliteCopy(pParse,&X,&Y,0);}
index 0ef51f9ba895bfd2276d605b03a2b5fdff815eed..7bbabff159b39fdb637096a6c6af2fc018e6ac15 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.2 2000/05/30 13:44:20 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.3 2000/05/30 16:27:04 drh Exp $
 */
 #include "sqlite.h"
 #include "dbbe.h"
@@ -219,6 +219,7 @@ int sqliteSortCompare(const char *, const char *);
 int sqliteGetToken(const char*, int *);
 void sqliteSetString(char **, const char *, ...);
 void sqliteSetNString(char **, ...);
+void sqliteDequote(char*);
 int sqliteRunParser(Parse*, char*, char **);
 void sqliteExec(Parse*);
 Expr *sqliteExpr(int, Expr*, Expr*, Token*);
@@ -246,3 +247,4 @@ void sqliteExprCode(Parse*, Expr*);
 void sqliteExprIfTrue(Parse*, Expr*, int);
 void sqliteExprIfFalse(Parse*, Expr*, int);
 Table *sqliteFindTable(sqlite*,char*);
+void sqliteCopy(Parse*, Token*, Token*, Token*);
index cc7615bac0f0067e45176028186fe5db18f5af2e..ac062d0b555eb2f7bc417a7d645edfa1c542d6c3 100644 (file)
@@ -27,7 +27,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.2 2000/05/30 13:44:20 drh Exp $
+** $Id: tokenize.c,v 1.3 2000/05/30 16:27:04 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -55,9 +55,11 @@ static Keyword aKeywordTable[] = {
   { "BY",                0, TK_BY,               0 },
   { "CHECK",             0, TK_CHECK,            0 },
   { "CONSTRAINT",        0, TK_CONSTRAINT,       0 },
+  { "COPY",              0, TK_COPY,             0 },
   { "CREATE",            0, TK_CREATE,           0 },
   { "DEFAULT",           0, TK_DEFAULT,          0 },
   { "DELETE",            0, TK_DELETE,           0 },
+  { "DELIMITERS",        0, TK_DELIMITERS,       0 },
   { "DESC",              0, TK_DESC,             0 },
   { "DROP",              0, TK_DROP,             0 },
   { "EXPLAIN",           0, TK_EXPLAIN,          0 },
@@ -80,6 +82,7 @@ static Keyword aKeywordTable[] = {
   { "TABLE",             0, TK_TABLE,            0 },
   { "UNIQUE",            0, TK_UNIQUE,           0 },
   { "UPDATE",            0, TK_UPDATE,           0 },
+  { "USING",             0, TK_USING,            0 },
   { "VALUES",            0, TK_VALUES,           0 },
   { "WHERE",             0, TK_WHERE,            0 },
 };
@@ -288,7 +291,7 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
   extern void sqliteParserTrace(FILE*, char *);
 
   i = 0;
-  pEngine = sqliteParserAlloc((void(*)())malloc);
+  pEngine = sqliteParserAlloc((void*(*)(int))malloc);
   if( pEngine==0 ){
     sqliteSetString(pzErrMsg, "out of memory", 0);
     return 1;
index 11e4449b6f517e63f351ceb4a58691b98f04f7b9..1c59ad7d5722defab1fecfabdffa66b77bf82a3a 100644 (file)
@@ -26,7 +26,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.5 2000/05/30 13:44:20 drh Exp $
+** $Id: util.c,v 1.6 2000/05/30 16:27:04 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -226,6 +226,32 @@ void sqliteSetNString(char **pz, ...){
   va_end(ap);
 }
 
+/*
+** Convert an SQL-style quoted string into a normal string by removing
+** the quote characters.  The conversion is done in-place.  If the
+** input does not begin with a quote character, then this routine
+** is a no-op.
+*/
+void sqliteDequote(char *z){
+  int quote;
+  int i, j;
+  quote = z[0];
+  if( quote!='\'' && quote!='"' ) return;
+  for(i=1, j=0; z[i]; i++){
+    if( z[i]==quote ){
+      if( z[i+1]==quote ){
+        z[j++] = quote;
+        i++;
+      }else{
+        z[j++] = 0;
+        break;
+      }
+    }else{
+      z[j++] = z[i];
+    }
+  }
+}
+
 /* An array to map all upper-case characters into their corresponding
 ** lower-case character. 
 */
index a93c237c20f3d62917b3a63de9eff9641e70af27..de87f9646f7d04cfd255b0f74e78d9b721346bc8 100644 (file)
@@ -41,7 +41,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.1 2000/05/29 14:26:02 drh Exp $
+** $Id: vdbe.c,v 1.2 2000/05/30 16:27:04 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -103,6 +103,11 @@ struct Vdbe {
   FILE **apList;      /* An open file for each list */
   int nSort;          /* Number of slots in apSort[] */
   Sorter **apSort;    /* An open sorter list */
+  FILE *pFile;        /* At most one open file handler */
+  int nField;         /* Number of file fields */
+  char **azField;     /* Data for each file field */
+  char *zLine;        /* A single line from the input file */
+  int nLineAlloc;     /* Number of spaces allocated for zLine */
 };
 
 /*
@@ -251,26 +256,10 @@ void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
 ** resolve to be a single actual quote character within the string.
 */
 void sqliteVdbeDequoteP3(Vdbe *p, int addr){
-  int quote;
-  int i, j;
   char *z;
   if( addr<0 || addr>=p->nOp ) return;
   z = p->aOp[addr].p3;
-  quote = z[0];
-  if( quote!='\'' && quote!='"' ) return;
-  for(i=1, j=0; z[i]; i++){
-    if( z[i]==quote ){
-      if( z[i+1]==quote ){
-        z[j++] = quote;
-        i++;
-      }else{
-        z[j++] = 0;
-        break;
-      }
-    }else{
-      z[j++] = z[i];
-    }
-  }
+  sqliteDequote(z);
 }
 
 /*
@@ -355,6 +344,20 @@ static void Cleanup(Vdbe *p){
   sqliteFree(p->apSort);
   p->apSort = 0;
   p->nSort = 0;
+  if( p->pFile ){
+    if( p->pFile!=stdin ) fclose(p->pFile);
+    p->pFile = 0;
+  }
+  if( p->azField ){
+    sqliteFree(p->azField);
+    p->azField = 0;
+  }
+  p->nField = 0;
+  if( p->zLine ){
+    sqliteFree(p->zLine);
+    p->zLine = 0;
+  }
+  p->nLineAlloc = 0;
 }
 
 /*
@@ -395,7 +398,8 @@ static char *zOpName[] = { 0,
   "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
   "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
   "Sort",           "SortNext",       "SortKey",        "SortCallback",
-  "SortClose",      "MakeRecord",     "MakeKey",        "Goto",
+  "SortClose",      "FileOpen",       "FileRead",       "FileField",
+  "FileClose",      "MakeRecord",     "MakeKey",        "Goto",
   "If",             "Halt",           "ColumnCount",    "ColumnName",
   "Callback",       "Integer",        "String",         "Pop",
   "Dup",            "Pull",           "Add",            "AddImm",
@@ -1918,6 +1922,154 @@ int sqliteVdbeExec(
         break;
       }
 
+      /* Opcode: FileOpen * * P3
+      **
+      ** Open the file named by P3 for reading using the FileRead opcode.
+      ** If P3 is "stdin" then output standard input for reading.
+      */
+      case OP_FileOpen: {
+        if( pOp->p3==0 ) goto bad_instruction;
+        if( p->pFile ){
+          if( p->pFile!=stdin ) fclose(p->pFile);
+          p->pFile = 0;
+        }
+        if( sqliteStrICmp(pOp->p3,"stdin")==0 ){
+          p->pFile = stdin;
+        }else{
+          p->pFile = fopen(pOp->p3, "r");
+        }
+        if( p->pFile==0 ){
+          sqliteSetString(pzErrMsg,"unable to open file: ", pOp->p3, 0);
+          rc = 1;
+          goto cleanup;
+        }
+        break;
+      }
+
+      /* Opcode: FileClose * * *
+      **
+      ** Close a file previously opened using FileOpen.  This is a no-op
+      ** if there is no prior FileOpen call.
+      */
+      case OP_FileClose: {
+        if( p->pFile ){
+          if( p->pFile!=stdin ) fclose(p->pFile);
+          p->pFile = 0;
+        }
+        if( p->azField ){
+          sqliteFree(p->azField);
+          p->azField = 0;
+        }
+        p->nField = 0;
+        if( p->zLine ){
+          sqliteFree(p->zLine);
+          p->zLine = 0;
+        }
+        p->nLineAlloc = 0;
+        break;
+      }
+
+      /* Opcode: FileRead P1 P2 P3
+      **
+      ** Read a single line of input the open file (the file opened using
+      ** FileOpen).  If we reach end-of-file, jump immediately to P2.  If
+      ** we are able to get another line, split the line apart using P3 as
+      ** a delimiter.  There should be exactly P1 fields.  Throw an exception
+      ** if the number of fields is different from P1.
+      */
+      case OP_FileRead: {
+        int n, eol, nField, i, c, nDelim;
+        char *zDelim, *z;
+        if( p->pFile==0 ) goto fileread_jump;
+        nField = pOp->p1;
+        if( nField<=0 ) goto fileread_jump;
+        if( nField!=p->nField || p->azField==0 ){
+          p->azField = sqliteRealloc(p->azField, sizeof(char*)*nField+1);
+          if( p->azField==0 ){
+            p->nField = 0;
+            goto fileread_jump;
+          }
+          p->nField = nField;
+        }
+        n = 0;
+        eol = 0;
+        while( eol==0 ){
+          if( p->zLine==0 || n+200>p->nLineAlloc ){
+            p->nLineAlloc = p->nLineAlloc*2 + 300;
+            p->zLine = sqliteRealloc(p->zLine, p->nLineAlloc);
+            if( p->zLine==0 ){
+              p->nLineAlloc = 0;
+              goto fileread_jump;
+            }
+          }
+          if( fgets(&p->zLine[n], p->nLineAlloc-n, p->pFile)==0 ){
+            eol = 1;
+            p->zLine[n] = 0;
+          }else{
+            while( p->zLine[n] ){ n++; }
+            if( n>0 && p->zLine[n-1]=='\n' ){
+              n--;
+              p->zLine[n] = 0;
+              eol = 1;
+            }
+          }
+        }
+        if( n==0 ) goto fileread_jump;
+        z = p->zLine;
+        if( z[0]=='\\' && z[1]=='.' && z[2]==0 ){
+          goto fileread_jump;
+        }
+        zDelim = pOp->p3;
+        if( zDelim==0 ) zDelim = "\t";
+        c = zDelim[0];
+        nDelim = strlen(zDelim);
+        p->azField[0] = z;
+        for(i=1; *z!=0 && i<nField; i++){
+          while( *z && (*z!=c || strncmp(z,zDelim,nDelim)) ){ z++; }
+          if( *z ){
+            *z = 0;
+            z += nDelim;
+            p->azField[i] = z;
+          }
+        }
+        while( i<nField ){
+          p->azField[i++] = "";
+        }
+        break;
+
+        /* If we reach end-of-file, or if anything goes wrong, jump here.
+        ** This code will cause a jump to P2 */
+      fileread_jump:
+        pc = pOp->p2;
+        if( pc<0 || pc>p->nOp ){
+          sqliteSetString(pzErrMsg, "jump destination out of range", 0);
+          rc = 1;
+        }
+        pc--;
+        break;
+      }
+
+      /* Opcode: FileField P1 * *
+      **
+      ** Push onto the stack the P1-th field of the most recently read line
+      ** from the file.
+      */
+      case OP_FileField: {
+        int i = pOp->p1;
+        char *z;
+        if( NeedStack(p, p->tos+1) ) goto no_mem;
+        if( i>=0 && i<p->nField && p->azField ){
+          z = p->azField[i];
+        }else{
+          z = 0;
+        }
+        if( z==0 ) z = "";
+        p->tos++;
+        p->iStack[p->tos] = strlen(z) + 1;
+        sqliteSetString(&p->zStack[p->tos], z, 0);
+        break;
+      }
+
       /* An other opcode is illegal...
       */
       default: {
index 5bafa9943bb99df7da9ce3d7a3252541c3dea8a8..d5dca045eccef8f98aebc8027cc9cb8ccfdff172 100644 (file)
@@ -27,7 +27,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.1 2000/05/29 14:26:02 drh Exp $
+** $Id: vdbe.h,v 1.2 2000/05/30 16:27:05 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -103,46 +103,51 @@ typedef struct VdbeOp VdbeOp;
 #define OP_SortCallback       28
 #define OP_SortClose          29
 
-#define OP_MakeRecord         30
-#define OP_MakeKey            31
-
-#define OP_Goto               32
-#define OP_If                 33
-#define OP_Halt               34
-
-#define OP_ColumnCount        35
-#define OP_ColumnName         36
-#define OP_Callback           37
-
-#define OP_Integer            38
-#define OP_String             39
-#define OP_Pop                40
-#define OP_Dup                41
-#define OP_Pull               42
-
-#define OP_Add                43
-#define OP_AddImm             44
-#define OP_Subtract           45
-#define OP_Multiply           46
-#define OP_Divide             47
-#define OP_Min                48
-#define OP_Max                49
-#define OP_Eq                 50
-#define OP_Ne                 51
-#define OP_Lt                 52
-#define OP_Le                 53
-#define OP_Gt                 54
-#define OP_Ge                 55
-#define OP_IsNull             56
-#define OP_NotNull            57
-#define OP_Negative           58
-#define OP_And                59
-#define OP_Or                 60
-#define OP_Not                61
-#define OP_Concat             62
-#define OP_Noop               63
-
-#define OP_MAX                63
+#define OP_FileOpen           30
+#define OP_FileRead           31
+#define OP_FileField          32
+#define OP_FileClose          33
+
+#define OP_MakeRecord         34
+#define OP_MakeKey            35
+
+#define OP_Goto               36
+#define OP_If                 37
+#define OP_Halt               38
+
+#define OP_ColumnCount        39
+#define OP_ColumnName         40
+#define OP_Callback           41
+
+#define OP_Integer            42
+#define OP_String             43
+#define OP_Pop                44
+#define OP_Dup                45
+#define OP_Pull               46
+
+#define OP_Add                47
+#define OP_AddImm             48
+#define OP_Subtract           49
+#define OP_Multiply           50
+#define OP_Divide             51
+#define OP_Min                52
+#define OP_Max                53
+#define OP_Eq                 54
+#define OP_Ne                 55
+#define OP_Lt                 56
+#define OP_Le                 57
+#define OP_Gt                 58
+#define OP_Ge                 59
+#define OP_IsNull             60
+#define OP_NotNull            61
+#define OP_Negative           62
+#define OP_And                63
+#define OP_Or                 64
+#define OP_Not                65
+#define OP_Concat             66
+#define OP_Noop               67
+
+#define OP_MAX                67
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation
index dbd68ed89d568e9e951f5e9e29538ad7598ce95f..fb609bff818ae29c676fd137856ecfed5dce5e5e 100644 (file)
@@ -23,7 +23,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the CREATE TABLE statement.
 #
-# $Id: table.test,v 1.3 2000/05/30 13:44:20 drh Exp $
+# $Id: table.test,v 1.4 2000/05/30 16:27:05 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -89,6 +89,26 @@ do_test table-1.6 {
   execsql {SELECT name FROM sqlite_master}
 } {}
 
+# Repeat the above steps, but this time quote the table name.
+#
+do_test table-1.10 {
+  execsql {CREATE TABLE "create" (f1 int)}
+  execsql {SELECT name FROM sqlite_master}
+} {create}
+do_test table-1.11 {
+  execsql {DROP TABLE "create"}
+  execsql {SELECT name FROM "sqlite_master"}
+} {}
+do_test table-1.12 {
+  execsql {CREATE TABLE test1("f1 ho" int)}
+  execsql {SELECT name as "X" FROM sqlite_master}
+} {test1}
+do_test table-1.13 {
+  execsql {DROP TABLE "TEST1"}
+  execsql {SELECT name FROM "sqlite_master"}
+} {}
+
+
 
 # Verify that we cannot make two tables with the same name
 #