diff --git a/manifest b/manifest index 6abbd882b3..48d5603d3a 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 4e7f9b5c69..61ae20b3fe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1bb8ee8d9f1d3c409a11910e7552e4bb5e7f5f87 \ No newline at end of file +8d66c7355de1d87b25c4fb92d0ef3603da72899a \ No newline at end of file diff --git a/src/build.c b/src/build.c index 40c4d39c95..34d200d265 100644 --- a/src/build.c +++ b/src/build.c @@ -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; inCol; 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; jnField; 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; +} diff --git a/src/parse.y b/src/parse.y index 65ee042444..7b58846e61 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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);} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0ef51f9ba8..7bbabff159 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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*); diff --git a/src/tokenize.c b/src/tokenize.c index cc7615bac0..ac062d0b55 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -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 @@ -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; diff --git a/src/util.c b/src/util.c index 11e4449b6f..1c59ad7d57 100644 --- a/src/util.c +++ b/src/util.c @@ -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 @@ -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. */ diff --git a/src/vdbe.c b/src/vdbe.c index a93c237c20..de87f9646f 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 && iazField[i] = z; + } + } + while( iazField[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 && inField && 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: { diff --git a/src/vdbe.h b/src/vdbe.h index 5bafa9943b..d5dca045ec 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -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_FileOpen 30 +#define OP_FileRead 31 +#define OP_FileField 32 +#define OP_FileClose 33 -#define OP_Goto 32 -#define OP_If 33 -#define OP_Halt 34 +#define OP_MakeRecord 34 +#define OP_MakeKey 35 -#define OP_ColumnCount 35 -#define OP_ColumnName 36 -#define OP_Callback 37 +#define OP_Goto 36 +#define OP_If 37 +#define OP_Halt 38 -#define OP_Integer 38 -#define OP_String 39 -#define OP_Pop 40 -#define OP_Dup 41 -#define OP_Pull 42 +#define OP_ColumnCount 39 +#define OP_ColumnName 40 +#define OP_Callback 41 -#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_Integer 42 +#define OP_String 43 +#define OP_Pop 44 +#define OP_Dup 45 +#define OP_Pull 46 -#define OP_MAX 63 +#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 diff --git a/test/table.test b/test/table.test index dbd68ed89d..fb609bff81 100644 --- a/test/table.test +++ b/test/table.test @@ -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 #