1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

:-) (CVS 15)

FossilOrigin-Name: 8d66c7355de1d87b25c4fb92d0ef3603da72899a
This commit is contained in:
drh
2000-05-30 16:27:03 +00:00
parent dcc581ccae
commit 982cef7e98
10 changed files with 387 additions and 84 deletions

View File

@@ -1,31 +1,31 @@
C :-)\s(CVS\s14) C :-)\s(CVS\s15)
D 2000-05-30T13:44:19 D 2000-05-30T16:27:04
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 89921c1ee4de75275bfadfbac198396da31704d1 F Makefile.in 89921c1ee4de75275bfadfbac198396da31704d1
F README 6b5960603c7f8bf42fc022b4b6436f242f238dbb F README 6b5960603c7f8bf42fc022b4b6436f242f238dbb
F configure 00a5b5c82147a576fa6e82d7c1b0d55c321d6d2c x F configure 00a5b5c82147a576fa6e82d7c1b0d55c321d6d2c x
F configure.in 6ccfd5fc80517f7cfe605a7fc7e0f62d962a233c F configure.in 6ccfd5fc80517f7cfe605a7fc7e0f62d962a233c
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
F src/build.c bc81ec2f7c3296c1f784f7c94d2d8afea9f787e7 F src/build.c 971796c068b8ae25b476f924e5e0da0b57adb9e6
F src/dbbe.c ab05293e89525041eaab8b4aca10516db3648792 F src/dbbe.c ab05293e89525041eaab8b4aca10516db3648792
F src/dbbe.h bedeb3a0985bb584458e7849fb59927e99e751e6 F src/dbbe.h bedeb3a0985bb584458e7849fb59927e99e751e6
F src/main.c 25cce7bce0eb3ba10bada7c05f4b38dc6dbbc86f F src/main.c 25cce7bce0eb3ba10bada7c05f4b38dc6dbbc86f
F src/parse.y 265c8596598afba0a94b94acd9c866d01603dfe5 F src/parse.y 50ca06d471132e16bb47c56f19553e4efd5b3d4a
F src/shell.c 125f84ea5f8b725ba474d4702b575d062cc94d92 F src/shell.c 125f84ea5f8b725ba474d4702b575d062cc94d92
F src/sqlite.h 2397c17a8f4ca90c09acab0100dc7e2f8f441b69 F src/sqlite.h 2397c17a8f4ca90c09acab0100dc7e2f8f441b69
F src/sqliteInt.h 562760efc29cf5b37a9029de04a5a8bca156f025 F src/sqliteInt.h 749da8b3e4ce146fd172aeb59b6db04c57726d7a
F src/tclsqlite.c 9efd29f79ded6a900aa3d142169c8bfe03b7affd F src/tclsqlite.c 9efd29f79ded6a900aa3d142169c8bfe03b7affd
F src/tokenize.c 948b8897ba211b58069d4a4465be23a2c639cf18 F src/tokenize.c e176b2c1c38e11482ee3419d6b50b733860a1587
F src/util.c dc1e1814cf69587e6ed58b82dd880ddb2165f3ce F src/util.c 2a0314dcc9de230526380765339071a5b304d70d
F src/vdbe.c 80132b6bb9a744d1990a1c16666d54baaff2dbc3 F src/vdbe.c 117ce5541143e3af9dccdc15c22c4920a7b9bdb4
F src/vdbe.h e721ad308f2e6ca805cebc4dd0a196ce4419d030 F src/vdbe.h 03de26632f2e608c2a44a40262fbba21a8bdfd81
F src/where.c be3973952e9bb5d2bb0bc5523b03f5d1f9e9d6f9 F src/where.c be3973952e9bb5d2bb0bc5523b03f5d1f9e9d6f9
F test/all.test 66a8a5b8291a472157944edcdce51a320ebd1f35 F test/all.test 66a8a5b8291a472157944edcdce51a320ebd1f35
F test/delete.test 814d53e3b0d2d7069fb17e005d4041454d6585d4 F test/delete.test 814d53e3b0d2d7069fb17e005d4041454d6585d4
F test/expr.test 11e00880d2de0f60ff1ba7fdd4e09a0d72a01910 F test/expr.test 11e00880d2de0f60ff1ba7fdd4e09a0d72a01910
F test/index.test 8d4f26901a5582daa353fe3c8266cbf4a53af830 F test/index.test 8d4f26901a5582daa353fe3c8266cbf4a53af830
F test/insert.test 161bc67a4189738c559e3569323ceae31f4d49d6 F test/insert.test 161bc67a4189738c559e3569323ceae31f4d49d6
F test/table.test 2d6b3ba1024032d341aec0d3c48272c8407485b4 F test/table.test 85d6f410d127ec508c6640f02d7c40d218414e81
F test/tester.tcl 70d25b7ced0a958bc377c72399b3dc6bf6a2d09e F test/tester.tcl 70d25b7ced0a958bc377c72399b3dc6bf6a2d09e
F test/update.test 69459302ea75cafac1479e60b0e36efb88123c0e F test/update.test 69459302ea75cafac1479e60b0e36efb88123c0e
F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b
@@ -37,7 +37,7 @@ F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
F www/c_interface.tcl f875864edf7974157d1c257ca08de854660882a5 F www/c_interface.tcl f875864edf7974157d1c257ca08de854660882a5
F www/index.tcl 2466d1b2e26c6f354b0acedee12025309a216799 F www/index.tcl 2466d1b2e26c6f354b0acedee12025309a216799
F www/sqlite.tcl 947e067bcc347dc767af4c1a6e5a8d47d8404aa3 F www/sqlite.tcl 947e067bcc347dc767af4c1a6e5a8d47d8404aa3
P 191a7f484e0a10839e7e1c8eb6658536643e4756 P 1bb8ee8d9f1d3c409a11910e7552e4bb5e7f5f87
R 0c03c3a3c9ac1b3b825b1193112ad5a4 R 0bda635e569bcbbf1f49ce4a3f5d3df9
U drh U drh
Z df606080358f2355e3007d65ffed4f54 Z 1c759b788ddf2200404a81ace8a2be6e

View File

@@ -1 +1 @@
1bb8ee8d9f1d3c409a11910e7552e4bb5e7f5f87 8d66c7355de1d87b25c4fb92d0ef3603da72899a

View File

@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** when syntax rules are reduced. ** 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" #include "sqliteInt.h"
@@ -191,6 +191,7 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
static char *sqliteTableNameFromToken(Token *pName){ static char *sqliteTableNameFromToken(Token *pName){
char *zName = 0; char *zName = 0;
sqliteSetNString(&zName, pName->z, pName->n, 0); sqliteSetNString(&zName, pName->z, pName->n, 0);
sqliteDequote(zName);
return zName; return zName;
} }
@@ -252,6 +253,7 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
pz = &p->azCol[p->nCol++]; pz = &p->azCol[p->nCol++];
*pz = 0; *pz = 0;
sqliteSetNString(pz, pName->z, pName->n, 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; pList->a[i].zName = 0;
if( pName ){ if( pName ){
sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0); sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
sqliteDequote(pList->a[i].zName);
} }
return pList; return pList;
} }
@@ -702,6 +705,7 @@ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
memset(&pList->a[pList->nId], 0, sizeof(pList->a[0])); memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
if( pToken ){ if( pToken ){
sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0); sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0);
sqliteDequote(pList->a[pList->nId].zName);
} }
pList->nId++; pList->nId++;
return pList; return pList;
@@ -714,6 +718,7 @@ void sqliteIdListAddAlias(IdList *pList, Token *pToken){
if( pList && pList->nId>0 ){ if( pList && pList->nId>0 ){
int i = pList->nId - 1; int i = pList->nId - 1;
sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0); sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
sqliteDequote(pList->a[i].zAlias);
} }
} }
@@ -1433,3 +1438,85 @@ update_cleanup:
sqliteExprDelete(pWhere); sqliteExprDelete(pWhere);
return; 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;
}

View File

@@ -26,7 +26,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** 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_prefix TK_
%token_type {Token} %token_type {Token}
@@ -65,7 +65,7 @@ explain ::= EXPLAIN. {pParse->explain = 1;}
// The first form of a command is a CREATE TABLE statement. // The first form of a command is a CREATE TABLE statement.
// //
cmd ::= create_table create_table_args. 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). create_table_args ::= LP columnlist conslist_opt RP(X).
{sqliteEndTable(pParse,&X);} {sqliteEndTable(pParse,&X);}
columnlist ::= columnlist COMMA column. columnlist ::= columnlist COMMA column.
@@ -76,7 +76,10 @@ columnlist ::= column.
// an elaborate typename. Perhaps someday we'll do something with it. // an elaborate typename. Perhaps someday we'll do something with it.
// //
column ::= columnid type carglist. 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.
type ::= typename LP signed RP. type ::= typename LP signed RP.
type ::= typename LP signed COMMA 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);} {sqliteCreateIndex(pParse,0,0,X,0,0);}
tcons2 ::= UNIQUE LP idlist RP. tcons2 ::= UNIQUE LP idlist RP.
tcons2 ::= CHECK expr. tcons2 ::= CHECK expr.
idlist ::= idlist COMMA ID. idlist ::= idlist COMMA id.
idlist ::= ID. idlist ::= id.
// The next command format is dropping tables. // 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 // The select statement
// //
@@ -149,8 +152,8 @@ selcollist(A) ::= sclp(P) expr(X) AS STRING(Y).
from(A) ::= FROM seltablist(X). {A = X;} from(A) ::= FROM seltablist(X). {A = X;}
stl_prefix(A) ::= seltablist(X) COMMA. {A = X;} stl_prefix(A) ::= seltablist(X) COMMA. {A = X;}
stl_prefix(A) ::= . {A = 0;} stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) ID(Y). {A = sqliteIdListAppend(X,&Y);} 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) AS id(Z).
{A = sqliteIdListAppend(X,&Y); {A = sqliteIdListAppend(X,&Y);
sqliteIdListAddAlias(A,&Z);} sqliteIdListAddAlias(A,&Z);}
@@ -300,4 +303,9 @@ idxlist(A) ::= idxitem(Y).
{A = sqliteIdListAppend(0,&Y);} {A = sqliteIdListAppend(0,&Y);}
idxitem(A) ::= ID(X). {A = X;} 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);}

View File

@@ -23,7 +23,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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 "sqlite.h"
#include "dbbe.h" #include "dbbe.h"
@@ -219,6 +219,7 @@ int sqliteSortCompare(const char *, const char *);
int sqliteGetToken(const char*, int *); int sqliteGetToken(const char*, int *);
void sqliteSetString(char **, const char *, ...); void sqliteSetString(char **, const char *, ...);
void sqliteSetNString(char **, ...); void sqliteSetNString(char **, ...);
void sqliteDequote(char*);
int sqliteRunParser(Parse*, char*, char **); int sqliteRunParser(Parse*, char*, char **);
void sqliteExec(Parse*); void sqliteExec(Parse*);
Expr *sqliteExpr(int, Expr*, Expr*, Token*); Expr *sqliteExpr(int, Expr*, Expr*, Token*);
@@ -246,3 +247,4 @@ void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int); void sqliteExprIfTrue(Parse*, Expr*, int);
void sqliteExprIfFalse(Parse*, Expr*, int); void sqliteExprIfFalse(Parse*, Expr*, int);
Table *sqliteFindTable(sqlite*,char*); Table *sqliteFindTable(sqlite*,char*);
void sqliteCopy(Parse*, Token*, Token*, Token*);

View File

@@ -27,7 +27,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -55,9 +55,11 @@ static Keyword aKeywordTable[] = {
{ "BY", 0, TK_BY, 0 }, { "BY", 0, TK_BY, 0 },
{ "CHECK", 0, TK_CHECK, 0 }, { "CHECK", 0, TK_CHECK, 0 },
{ "CONSTRAINT", 0, TK_CONSTRAINT, 0 }, { "CONSTRAINT", 0, TK_CONSTRAINT, 0 },
{ "COPY", 0, TK_COPY, 0 },
{ "CREATE", 0, TK_CREATE, 0 }, { "CREATE", 0, TK_CREATE, 0 },
{ "DEFAULT", 0, TK_DEFAULT, 0 }, { "DEFAULT", 0, TK_DEFAULT, 0 },
{ "DELETE", 0, TK_DELETE, 0 }, { "DELETE", 0, TK_DELETE, 0 },
{ "DELIMITERS", 0, TK_DELIMITERS, 0 },
{ "DESC", 0, TK_DESC, 0 }, { "DESC", 0, TK_DESC, 0 },
{ "DROP", 0, TK_DROP, 0 }, { "DROP", 0, TK_DROP, 0 },
{ "EXPLAIN", 0, TK_EXPLAIN, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 },
@@ -80,6 +82,7 @@ static Keyword aKeywordTable[] = {
{ "TABLE", 0, TK_TABLE, 0 }, { "TABLE", 0, TK_TABLE, 0 },
{ "UNIQUE", 0, TK_UNIQUE, 0 }, { "UNIQUE", 0, TK_UNIQUE, 0 },
{ "UPDATE", 0, TK_UPDATE, 0 }, { "UPDATE", 0, TK_UPDATE, 0 },
{ "USING", 0, TK_USING, 0 },
{ "VALUES", 0, TK_VALUES, 0 }, { "VALUES", 0, TK_VALUES, 0 },
{ "WHERE", 0, TK_WHERE, 0 }, { "WHERE", 0, TK_WHERE, 0 },
}; };
@@ -288,7 +291,7 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
extern void sqliteParserTrace(FILE*, char *); extern void sqliteParserTrace(FILE*, char *);
i = 0; i = 0;
pEngine = sqliteParserAlloc((void(*)())malloc); pEngine = sqliteParserAlloc((void*(*)(int))malloc);
if( pEngine==0 ){ if( pEngine==0 ){
sqliteSetString(pzErrMsg, "out of memory", 0); sqliteSetString(pzErrMsg, "out of memory", 0);
return 1; return 1;

View File

@@ -26,7 +26,7 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** 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 "sqliteInt.h"
#include <stdarg.h> #include <stdarg.h>
@@ -226,6 +226,32 @@ void sqliteSetNString(char **pz, ...){
va_end(ap); 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 /* An array to map all upper-case characters into their corresponding
** lower-case character. ** lower-case character.
*/ */

View File

@@ -41,7 +41,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** 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" #include "sqliteInt.h"
@@ -103,6 +103,11 @@ struct Vdbe {
FILE **apList; /* An open file for each list */ FILE **apList; /* An open file for each list */
int nSort; /* Number of slots in apSort[] */ int nSort; /* Number of slots in apSort[] */
Sorter **apSort; /* An open sorter list */ 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. ** resolve to be a single actual quote character within the string.
*/ */
void sqliteVdbeDequoteP3(Vdbe *p, int addr){ void sqliteVdbeDequoteP3(Vdbe *p, int addr){
int quote;
int i, j;
char *z; char *z;
if( addr<0 || addr>=p->nOp ) return; if( addr<0 || addr>=p->nOp ) return;
z = p->aOp[addr].p3; z = p->aOp[addr].p3;
quote = z[0]; sqliteDequote(z);
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];
}
}
} }
/* /*
@@ -355,6 +344,20 @@ static void Cleanup(Vdbe *p){
sqliteFree(p->apSort); sqliteFree(p->apSort);
p->apSort = 0; p->apSort = 0;
p->nSort = 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", "ListWrite", "ListRewind", "ListRead", "ListClose",
"SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
"Sort", "SortNext", "SortKey", "SortCallback", "Sort", "SortNext", "SortKey", "SortCallback",
"SortClose", "MakeRecord", "MakeKey", "Goto", "SortClose", "FileOpen", "FileRead", "FileField",
"FileClose", "MakeRecord", "MakeKey", "Goto",
"If", "Halt", "ColumnCount", "ColumnName", "If", "Halt", "ColumnCount", "ColumnName",
"Callback", "Integer", "String", "Pop", "Callback", "Integer", "String", "Pop",
"Dup", "Pull", "Add", "AddImm", "Dup", "Pull", "Add", "AddImm",
@@ -1918,6 +1922,154 @@ int sqliteVdbeExec(
break; 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... /* An other opcode is illegal...
*/ */
default: { default: {

View File

@@ -27,7 +27,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** 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_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@@ -103,46 +103,51 @@ typedef struct VdbeOp VdbeOp;
#define OP_SortCallback 28 #define OP_SortCallback 28
#define OP_SortClose 29 #define OP_SortClose 29
#define OP_MakeRecord 30 #define OP_FileOpen 30
#define OP_MakeKey 31 #define OP_FileRead 31
#define OP_FileField 32
#define OP_FileClose 33
#define OP_Goto 32 #define OP_MakeRecord 34
#define OP_If 33 #define OP_MakeKey 35
#define OP_Halt 34
#define OP_ColumnCount 35 #define OP_Goto 36
#define OP_ColumnName 36 #define OP_If 37
#define OP_Callback 37 #define OP_Halt 38
#define OP_Integer 38 #define OP_ColumnCount 39
#define OP_String 39 #define OP_ColumnName 40
#define OP_Pop 40 #define OP_Callback 41
#define OP_Dup 41
#define OP_Pull 42
#define OP_Add 43 #define OP_Integer 42
#define OP_AddImm 44 #define OP_String 43
#define OP_Subtract 45 #define OP_Pop 44
#define OP_Multiply 46 #define OP_Dup 45
#define OP_Divide 47 #define OP_Pull 46
#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_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 ** Prototypes for the VDBE interface. See comments on the implementation

View File

@@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the CREATE TABLE statement. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -89,6 +89,26 @@ do_test table-1.6 {
execsql {SELECT name FROM sqlite_master} 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 # Verify that we cannot make two tables with the same name
# #