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:
26
manifest
26
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
|
||||
|
@@ -1 +1 @@
|
||||
1bb8ee8d9f1d3c409a11910e7552e4bb5e7f5f87
|
||||
8d66c7355de1d87b25c4fb92d0ef3603da72899a
|
89
src/build.c
89
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; 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;
|
||||
}
|
||||
|
26
src/parse.y
26
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);}
|
||||
|
@@ -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*);
|
||||
|
@@ -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;
|
||||
|
28
src/util.c
28
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 <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.
|
||||
*/
|
||||
|
190
src/vdbe.c
190
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 && 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: {
|
||||
|
77
src/vdbe.h
77
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
|
||||
|
@@ -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
|
||||
#
|
||||
|
Reference in New Issue
Block a user