📄 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;
dateFormat = getenv("SUBSQL_DATE_FORMAT");
}
dbSubSql::~dbSubSql()
{
delete[] buf;
}
//
// 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;
case '#':
ival = 0;
while (true) {
ch = get();
if (ch >= '0' && ch <= '9') {
ival += (ival << 4) + ch-'0';
} else if (ch >= 'a' && ch <= 'f') {
ival += (ival << 4) + ch-'a'+10;
} else if (ch >= 'A' && ch <= 'F') {
ival += (ival << 4) + ch-'A'+10;
} else {
unget(ch);
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[] = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -