subsql.cpp

来自「一个功能强大的内存数据库源代码,c++编写,有详细的注释」· C++ 代码 · 共 1,947 行 · 第 1/4 页

CPP
1,947
字号
//-< 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 "subsql.h"#include "symtab.h"#include "hashtab.h"#include "ttree.h"#if THREADS_SUPPORTED#include "server.h"#endifstatic char* typeMnem[] = {	"Boolean",	"Int1",	"Int2",	"Int4",	"Int8",	"Real4",	"Real8",	"String",	"Reference",	"Array",	"MethodBool",	"MethodInt1",	"MethodInt2",	"MethodInt4",	"MethodInt8",	"MethodReal4",	"MethodReal8",	"MethodString",	"MethodReference",	"Structure",	"RawBinary",	"Unknown" };char* dbSubSql::prompt = ">> ";dbSubSql::dbSubSql(dbAccessType accessType): dbDatabase(accessType){    static struct { 	char* name;	int   tag;    } keywords[] = { 	{"array",   tkn_array},	{"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},	{"hash",    tkn_hash},	{"help",    tkn_help},	{"index",   tkn_index},	{"int1",    tkn_int1},	{"int2",    tkn_int2},	{"int4",    tkn_int4},	{"int8",    tkn_int8},	{"of",      tkn_of},	{"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}    };    for (unsigned i = 0; i < items(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];}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::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;      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::createTable(){    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;	int type = parseType();	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();	    if (type == dbField::tpUnknown) { 		break;	    }	    if (type == dbField::tpArray) { 		error("Arrays of arrays are not supported by CLI");		break;	    }	    if (type == dbField::tpReference) {		int length = strlen(buf);		fields[nFields].refTableName = new char[length+1];		strcpy(fields[nFields].refTableName, buf);		fields[nFields-1].refTableName = new char[length+1];		strcpy(fields[nFields-1].refTableName, buf);		varyingLength += (length + length);	    }	    fields[nFields++].type = type;	} else if (type == dbField::tpReference) { 	    int len =  strlen(buf);	    fields[nFields-1].refTableName = new char[len+1];	    strcpy(fields[nFields-1].refTableName, buf);	    	    varyingLength += len;	}	tkn = scan();     }    if (tkn == tkn_rpar) { 	beginTransaction(dbExclusiveLock);	modified = true;	if (findTable(name) != NULL) { 	    error("Table already exists");	    return false;	}	oid_t oid = allocateRow(dbMetaTableId, 				sizeof(dbTable) + sizeof(dbField)*nFields 				+ varyingLength);	dbTable* table = (dbTable*)getRow(oid);    	int offs = sizeof(dbTable) + sizeof(dbField)*nFields;	table->name.offs = offs;	table->name.size = strlen(name)+1;	strcpy((char*)table + offs, name);	offs += table->name.size;	size_t size = sizeof(dbRecord);	table->fields.offs = sizeof(dbTable);	dbField* field = (dbField*)((char*)table + table->fields.offs);	offs -= sizeof(dbTable);	bool arrayComponent = false;	for (int i = 0; i < nFields; i++) { 	    field->name.offs = offs;	    field->name.size = strlen(fields[i].name) + 1;	    strcpy((char*)field + offs, fields[i].name);	    offs += field->name.size;	    	    field->tableName.offs = offs;	    if (fields[i].refTableName) { 		field->tableName.size = strlen(fields[i].refTableName) + 1;		strcpy((char*)field + offs, fields[i].refTableName);		offs += field->tableName.size;	    } else { 		field->tableName.size = 1;		*((char*)field + offs++) = '\0';	    }	    	    field->inverse.offs = offs;	    field->inverse.size = 1;	    *((char*)field + offs++) = '\0';	    	    field->type = fields[i].type;	    field->size = typeDesc[fields[i].type].size;	    if (!arrayComponent) { 		size = DOALIGN(size, typeDesc[fields[i].type].alignment);		field->offset = size;		size += field->size;	    } else { 		field->offset = 0;	    }	    field->hashTable = 0;	    field->tTree = 0;	    arrayComponent = field->type == dbField::tpArray; 	    field += 1;	    offs -= sizeof(dbField);	}	table->fields.size = nFields;	table->fixedSize = size;	table->nRows = 0;	table->nColumns = nColumns;	table->firstRow = 0;	table->lastRow = 0;	linkTable(new dbTableDescriptor(table), oid);	if (!completeDescriptorsInitialization()) { 	    error("Reference to undefined table");	}    }    return tkn == tkn_rpar;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?