//-< SUBSQL.H >------------------------------------------------------*--------* // 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) //-------------------------------------------------------------------*--------* #ifndef __SUBSQL_H__ #define __SUBSQL_H__ enum SubSqlTokens { tkn_array = tkn_last_token, tkn_autoincrement, tkn_backup, tkn_bool, tkn_commit, tkn_compactify, tkn_count, tkn_create, tkn_delete, tkn_describe, tkn_drop, tkn_exit, tkn_export, tkn_hash, tkn_help, tkn_http, tkn_import, tkn_index, tkn_int1, tkn_int2, tkn_int4, tkn_int8, tkn_of, tkn_on, tkn_open, tkn_real4, tkn_real8, tkn_reference, tkn_rollback, tkn_server, tkn_set, tkn_stop, tkn_semi, tkn_show, tkn_to, tkn_update, tkn_values }; class dbList { public: enum NodeType { nInteger, nBool, nReal, nString, nTuple, nAutoinc, nIdentifier }; dbList* next; int type; union { bool bval; db_int8 ival; real8 fval; char* sval; struct { int nComponents; dbList* components; } aggregate; }; ~dbList() { if (type == nTuple) { delete aggregate.components; } else if (type == nString || type == nIdentifier) { delete[] sval; } } dbList(int type) { this->type = type; next = NULL; } }; struct tableField { char* name; char* refTableName; int type; tableField() { name = refTableName = NULL; } ~tableField() { delete[] name; delete[] refTableName; } }; class dbUpdateElement { public: dbUpdateElement* next; dbFieldDescriptor* field; dbExprNode* value; char* strValue; dbUpdateElement() { next = NULL; strValue = NULL; } ~dbUpdateElement() { delete[] strValue; } }; #define MAX_HISTORY_SIZE 16 class dbXmlScanner { public: enum { MaxIdentSize = 256 }; enum token { xml_ident, xml_sconst, xml_iconst, xml_fconst, xml_lt, xml_gt, xml_lts, xml_gts, xml_eq, xml_eof, xml_error }; dbXmlScanner(FILE* f) { in = f; sconst = new char[size = 1024]; line = 1; pos = 0; } token scan(); char* getString() { return sconst; } char* getIdentifier() { return ident; } size_t getStringLength() { return slen; } db_int8 getInt() { return iconst; } double getReal() { return fconst; } bool expect(int sourcePos, token expected) { token tkn = scan(); if (tkn != expected) { fprintf(stderr, "subsql.cpp:%d: line %d, column %d: Get token %d instead of expected token %d\n", sourcePos, line, pos, tkn, expected); return false; } return true; } bool expect(int sourcePos, char* expected) { token tkn = scan(); if (tkn != xml_ident) { fprintf(stderr, "subsql.cpp:%d: line %d, column %d: Get token %d instead of expected identifier\n", sourcePos, line, pos, tkn); return false; } if (strcmp(ident, expected) != 0) { fprintf(stderr, "subsql.cpp:%d: line %d, column %d: Get tag '%s' instead of expected '%s'\n", sourcePos, line, pos, ident, expected); return false; } return true; } private: int get(); void unget(int ch); int line; int pos; FILE* in; char* sconst; size_t size; size_t slen; db_int8 iconst; double fconst; char ident[MaxIdentSize]; }; class dbTmpAllocator { enum { CHUNK_SIZE = 4096 }; struct Chunk { Chunk* next; }; Chunk* curr; size_t used; public: dbTmpAllocator() { curr = NULL; used = CHUNK_SIZE; } ~dbTmpAllocator() { reset(); } void reset() { Chunk *c, *next; for (c = curr; c != NULL; c = next) { next = c->next; dbFree(c); } curr = NULL; used = CHUNK_SIZE; } void* alloc(size_t size) { if (size > CHUNK_SIZE/2) { Chunk* newChunk = (Chunk*)dbMalloc(size + sizeof(Chunk)); if (curr != NULL) { newChunk->next = curr->next; curr->next = newChunk; } else { curr = newChunk; newChunk->next = NULL; used = CHUNK_SIZE; } return newChunk+1; } else if (size <= CHUNK_SIZE - used) { used += size; return (char*)(curr+1) + used - size; } else { Chunk* newChunk = (Chunk*)dbMalloc(CHUNK_SIZE); used = sizeof(Chunk) + size; newChunk->next = curr; curr = newChunk; return newChunk+1; } } }; class dbSubSql : public dbDatabase { private: int pos; int line; int tknPos; char* buf; int buflen; FILE* in; bool opened; db_int8 ival; real8 fval; char* name; oid_t* oidMap; oid_t oidMapSize; dbTmpAllocator tmpAlloc; static char* prompt; dbTableDescriptor* droppedTables; dbTableDescriptor* existedTables; dbQuery query; dbCompiler compiler; dbThread httpServerThread; HTTPapi* httpServer; bool httpServerRunning; char* queryHistory[MAX_HISTORY_SIZE]; unsigned historyUsed; unsigned historyCurr; static void thread_proc httpServerThreadProc(void* arg); void httpServerLoop(); void startHttpServer(char const* address); void stopHttpServer(char const* address); void handleError(dbErrorClass error, char const* msg = NULL, int arg = 0); void error(char const* msg); void warning(char const* msg); int get(); void unget(int ch); int scan(); bool parse(); bool expect(char* expected, int token); void recovery(); void exportDatabase(FILE* out); bool importDatabase(FILE* in); oid_t mapId(long id); bool importField(char* terminator, dbFieldDescriptor* fd, byte* rec, dbXmlScanner& scanner); bool importRecord(char* terminator, dbFieldDescriptor* fieldList, byte* rec, dbXmlScanner& scanner); void insertRecord(dbTableDescriptor* desc, oid_t oid, void const* record); bool isValidOid(oid_t oid); static void dumpRecord(byte* record, dbFieldDescriptor* first); static int calculateRecordSize(dbList* list, int offs, dbFieldDescriptor* first); int initializeRecordFields(dbList* node, byte* dst, int offs, dbFieldDescriptor* first); bool insertRecord(dbList* list, dbTableDescriptor* desc); bool readCondition(); int readExpression(); int readValues(dbList** chain); bool updateFields(dbAnyCursor* cursor, dbUpdateElement* elems); bool createTable(); int parseType(); int updateRecords(dbTableDescriptor* desc, dbList *fields, dbList *values, dbAnyCursor &cursor, byte *buf); dbFieldDescriptor* readFieldName(); public: void run(int argc, char* argv[]); void selectionPage(WWWconnection& con); void queryPage(WWWconnection& con); void defaultPage(WWWconnection& con); dbSubSql(dbAccessType accessType); virtual~dbSubSql(); }; #endif