⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subsql.cpp

📁 实现内存数据库的源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//-< 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"
#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",
	"Unknown" 
};

char* dbSubSql::prompt = ">> ";


dbSubSql::dbSubSql()
{
    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},
	{"create",  tkn_create},
	{"delete",  tkn_delete},
	{"describe",tkn_describe},
	{"drop",    tkn_drop},
	{"exit",    tkn_exit},
	{"hash",    tkn_hash},
	{"help",    tkn_help},
	{"index",   tkn_index},
	{"insert",  tkn_insert},
	{"int1",    tkn_int1},
	{"int2",    tkn_int2},
	{"int4",    tkn_int4},
	{"int8",    tkn_int8},
	{"into",    tkn_into},
	{"of",      tkn_of},
	{"on",      tkn_on},
	{"open",    tkn_open},
	{"reference",tkn_reference},
	{"real4",   tkn_real4},
	{"real8",   tkn_real8},
	{"rollback",tkn_rollback},
	{"select",  tkn_select},
	{"server",  tkn_server},
	{"set",     tkn_set},
	{"stop",    tkn_stop},
	{"show",    tkn_show},
	{"to",      tkn_to},
	{"table",   tkn_table},
	{"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(int8), sizeof(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;
	    }
	    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(true);
	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);
		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;

⌨️ 快捷键说明

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