?? subsql.cpp
字號:
//-< SUBSQL.CPP >----------------------------------------------------*--------*
// FastDB Version 1.0 (c) 1999 GARRET * ? *
// (Main Memory Database Management System) * /\| *
// * / \ *
// Created: 20-Nov-98 K.A. Knizhnik * / [] \ *
// Last update: 10-Dec-98 K.A. Knizhnik * GARRET *
//-------------------------------------------------------------------*--------*
// Interactive data manipulation language (subset of SQL)
//-------------------------------------------------------------------*--------*
#include <stdio.h>
#include <ctype.h>
#include "fastdb.h"
#include "compiler.h"
#include "wwwapi.h"
#include "subsql.h"
#include "symtab.h"
#include "hashtab.h"
#include "ttree.h"
#if THREADS_SUPPORTED
#include "server.h"
#endif
static char* typeMnem[] = {
"Boolean",
"Int1",
"Int2",
"Int4",
"Int8",
"Real4",
"Real8",
"String",
"Reference",
"Array",
"MethodBool",
"MethodInt1",
"MethodInt2",
"MethodInt4",
"MethodInt8",
"MethodReal4",
"MethodReal8",
"MethodString",
"MethodReference",
"Structure",
"RawBinary",
"StdString",
"Unknown"
};
char* dbSubSql::prompt = ">> ";
dbSubSql::dbSubSql(dbAccessType accessType)
: dbDatabase(accessType)
{
static struct
{
char* name;
int tag;
}
keywords[] = {
{"alter", tkn_alter},
{"array", tkn_array},
{"autocommit", tkn_autocommit},
{"autoincrement",tkn_autoincrement},
{"backup", tkn_backup},
{"bool", tkn_bool},
{"commit", tkn_commit},
{"compactify",tkn_compactify},
{"count", tkn_count},
{"create", tkn_create},
{"delete", tkn_delete},
{"describe",tkn_describe},
{"drop", tkn_drop},
{"exit", tkn_exit},
{"export", tkn_export},
{"hash", tkn_hash},
{"help", tkn_help},
{"http", tkn_http},
{"import", tkn_import},
{"index", tkn_index},
{"int1", tkn_int1},
{"int2", tkn_int2},
{"int4", tkn_int4},
{"int8", tkn_int8},
{"inverse", tkn_inverse},
{"of", tkn_of},
{"off", tkn_off},
{"on", tkn_on},
{"open", tkn_open},
{"reference",tkn_reference},
{"real4", tkn_real4},
{"real8", tkn_real8},
{"rollback",tkn_rollback},
{"server", tkn_server},
{"set", tkn_set},
{"stop", tkn_stop},
{"show", tkn_show},
{"to", tkn_to},
{"update", tkn_update},
{"values", tkn_values},
{"version", tkn_version}
};
for (unsigned i = 0; i < itemsof(keywords); i++)
{
dbSymbolTable::add
(keywords[i].name, keywords[i].tag, FASTDB_CLONE_ANY_IDENTIFIER);
}
droppedTables = NULL;
existedTables = NULL;
opened = false;
buflen = 1024;
buf = new char[buflen];
httpServerRunning = false;
databaseName = NULL;
historyUsed = historyCurr = 0;
ungetToken = -1;
autocommit = false;
}
dbSubSql::~dbSubSql()
{
delete[] buf;
}
inline int strincmp(const char* p, const char* q, size_t n)
{
while (n > 0)
{
int diff = toupper(*(unsigned char*)p) - toupper(*(unsigned char*)q);
if (diff != 0)
{
return diff;
}
else if (*p == '\0')
{
return 0;
}
p += 1;
q += 1;
n -= 1;
}
return 0;
}
//
// Find one string within another, ignoring case
//
inline char* stristr(const char* haystack, const char* needle)
{
nat4 i, hayLen, ndlLen;
ndlLen = strlen(needle);
hayLen = strlen(haystack);
if (ndlLen > hayLen)
{
return NULL;
}
for (i = 0; i <= (hayLen - ndlLen); i++)
{
if (strincmp(&haystack[i], needle, ndlLen) == 0)
{
return (char*)&haystack[i];
}
}
return NULL;
}
bool contains(dbUserFunctionArgument& arg1, dbUserFunctionArgument& arg2)
{
assert(arg1.type == dbUserFunctionArgument::atString && arg2.type == dbUserFunctionArgument::atString);
return stristr(arg1.u.strValue, arg2.u.strValue) != NULL;
}
USER_FUNC(contains);
int dbSubSql::get
()
{
int ch = getc(in);
if (ch == '\n')
{
pos = 0;
line += 1;
}
else if (ch == '\t')
{
pos = DOALIGN(pos + 1, 8);
}
else
{
pos += 1;
}
return ch;
}
void dbSubSql::unget(int ch)
{
if (ch != EOF)
{
if (ch != '\n')
{
pos -= 1;
}
else
{
line -= 1;
}
ungetc(ch, in);
}
}
void dbSubSql::warning(char const* msg)
{
fprintf(stderr, "%s at line %d position %d\n", msg, line, tknPos > 0 ? tknPos - 1 : 0);
}
void dbSubSql::error(char const* msg)
{
#ifdef THROW_EXCEPTION_ON_ERROR
dbDatabaseThreadContext* ctx = threadContext.get();
if (ctx != NULL)
{
ctx->interactive = true;
}
try
{
handleError(QueryError, msg, tknPos > 0 ? tknPos - 1 : 0);
}
catch(dbException)
{}
#else
dbDatabaseThreadContext* ctx = threadContext.get();
if (ctx != NULL)
{
ctx->interactive = true;
ctx->catched = true;
if (setjmp(ctx->unwind) == 0)
{
handleError(QueryError, msg, tknPos > 0 ? tknPos - 1 : 0);
}
ctx->catched = false;
}
else
{
handleError(QueryError, msg, tknPos > 0 ? tknPos - 1 : 0);
}
#endif
}
int dbSubSql::scan()
{
int i, ch, digits;
if (ungetToken >= 0)
{
int tkn = ungetToken;
ungetToken = -1;
return tkn;
}
nextToken:
do
{
if ((ch = get
()) == EOF)
{
return tkn_eof;
}
}
while (isspace(ch));
tknPos = pos;
switch (ch)
{
case '*':
return tkn_all;
case '(':
return tkn_lpar;
case ')':
return tkn_rpar;
case ',':
return tkn_comma;
case '.':
return tkn_dot;
case ';':
return tkn_semi;
case '=':
return tkn_eq;
case '\'':
i = 0;
while (true)
{
ch = get
();
if (ch == '\'')
{
if ((ch = get
()) != '\'')
{
unget(ch);
break;
}
}
else if (ch == '\n' || ch == EOF)
{
unget(ch);
error("New line within character constant");
return tkn_error;
}
if (i+1 == buflen)
{
char* newbuf = new char[buflen*2];
memcpy(newbuf, buf, buflen);
delete[] buf;
buf = newbuf;
buflen *= 2;
}
buf[i++] = ch;
}
buf[i] = '\0';
return tkn_sconst;
case '-':
if ((ch = get
()) == '-')
{
// ANSI comments
while ((ch = get
()) != EOF && ch != '\n');
goto nextToken;
}
unget(ch);
ch = '-';
// no break
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
i = 0;
do
{
buf[i++] = ch;
if (i == buflen)
{
error("Numeric constant too long");
return tkn_error;
}
ch = get
();
}
while (ch != EOF
&& (isdigit(ch) || ch == '+' || ch == '-' || ch == 'e' ||
ch == 'E' || ch == '.'));
unget(ch);
buf[i] = '\0';
if (sscanf(buf, INT8_FORMAT "%n", &ival, &digits) != 1)
{
error("Bad integer constant");
return tkn_error;
}
if (digits != i)
{
if (sscanf(buf, "%lf%n", &fval, &digits) != 1 || digits != i)
{
error("Bad float constant");
return tkn_error;
}
return tkn_fconst;
}
return tkn_iconst;
default:
if (isalpha(ch) || ch == '$' || ch == '_')
{
i = 0;
do
{
buf[i++] = ch;
if (i == buflen)
{
error("Identifier too long");
return tkn_error;
}
ch = get
();
}
while (ch != EOF && (isalnum(ch) || ch == '$' || ch == '_'));
unget(ch);
buf[i] = '\0';
name = buf;
return dbSymbolTable::add
(name, tkn_ident);
}
else
{
error("Invalid symbol");
return tkn_error;
}
}
}
bool dbSubSql::expect(char* expected, int token)
{
int tkn = scan();
if (tkn != token)
{
if (tkn != tkn_error)
{
char buf[256];
sprintf(buf, "Token '%s' expected", expected);
error(buf);
}
return false;
}
return true;
}
bool dbSubSql::updateTable(bool create)
{
int tkn;
if (!expect("table name", tkn_ident) || !expect("(", tkn_lpar))
{
return false;
}
char* name = this->name;
int varyingLength = strlen(name)+1;
static const struct
{
int size;
int alignment;
}
typeDesc[] = {
{ sizeof(bool), sizeof(bool) },
{ sizeof(int1), sizeof(int1) },
{ sizeof(int2), sizeof(int2) },
{ sizeof(int4), sizeof(int4) },
{ sizeof(db_int8), sizeof(db_int8) },
{ sizeof(real4), sizeof(real4) },
{ sizeof(real8), sizeof(real8) },
{ sizeof(dbVarying), 4 },
{ sizeof(oid_t), sizeof(oid_t) },
{ sizeof(dbVarying), 4 }
};
const int maxFields = 256;
tableField fields[maxFields];
int nFields = 0;
int nColumns = 0;
tkn = tkn_comma;
while (tkn == tkn_comma)
{
if (nFields+1 == maxFields)
{
error("Too many fields");
break;
}
if (!expect("field name", tkn_ident))
{
break;
}
int nameLen = strlen(buf)+1;
fields[nFields].name = new char[nameLen];
strcpy(fields[nFields].name, buf);
varyingLength += nameLen + 2;
char* refTableName;
char* inverseRefName;
int type = parseType(refTableName, inverseRefName);
fields[nFields++].type = type;
if (type == dbField::tpUnknown)
{
break;
}
nColumns += 1;
if (type == dbField::tpArray)
{
if (nFields+1 == maxFields)
{
error("Too many fields");
break;
}
fields[nFields].name = new char[nameLen+2];
sprintf(fields[nFields].name, "%s[]", fields[nFields-1].name);
varyingLength += nameLen+2+2;
type = parseType(refTableName, inverseRefName);
if (type == dbField::tpUnknown)
{
break;
}
if (type == dbField::tpArray)
{
error("Arrays of arrays are not supported by CLI");
break;
}
if (type == dbField::tpReference)
{
fields[nFields].refTableName = refTableName;
varyingLength += strlen(refTableName);
if (inverseRefName != NULL)
{
fields[nFields-1].inverseRefName = inverseRefName;
varyingLength += strlen(inverseRefName);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -