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 + -
显示快捷键?