00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __SUBSQL_H__
00012 #define __SUBSQL_H__
00013
00014 #ifdef _WIN32
00015 #pragma warning(disable: 4786)
00016 #endif
00017
00018 BEGIN_GIGABASE_NAMESPACE
00019
00020 enum SubSqlTokens {
00021 tkn_alter = tkn_last_token,
00022 tkn_array,
00023 tkn_autoincrement,
00024 tkn_autocommit,
00025 tkn_backup,
00026 tkn_bool,
00027 tkn_commit,
00028 tkn_compactify,
00029 tkn_count,
00030 tkn_create,
00031 tkn_delete,
00032 tkn_describe,
00033 tkn_drop,
00034 tkn_exit,
00035 tkn_export,
00036 tkn_hash,
00037 tkn_help,
00038 tkn_http,
00039 tkn_import,
00040 tkn_index,
00041 tkn_int1,
00042 tkn_int2,
00043 tkn_int4,
00044 tkn_int8,
00045 tkn_inverse,
00046 tkn_memory,
00047 tkn_of,
00048 tkn_off,
00049 tkn_on,
00050 tkn_open,
00051 tkn_profile,
00052 tkn_real4,
00053 tkn_real8,
00054 tkn_rectangle,
00055 tkn_reference,
00056 tkn_restore,
00057 tkn_rollback,
00058 tkn_server,
00059 tkn_set,
00060 tkn_stop,
00061 tkn_semi,
00062 tkn_show,
00063 tkn_to,
00064 tkn_update,
00065 tkn_values,
00066 tkn_version,
00067 tkn_include,
00068 tkn_exclude,
00069 };
00070
00071 struct tableField {
00072 char_t* name;
00073 char_t* refTableName;
00074 char_t* inverseRefName;
00075 int type;
00076
00077 tableField() { name = refTableName = inverseRefName = NULL; }
00078 ~tableField() { delete[] name; delete[] refTableName; delete[] inverseRefName; }
00079 };
00080
00081
00082 class dbList {
00083 public:
00084 enum NodeType {
00085 nInteger,
00086 nBool,
00087 nReal,
00088 nString,
00089 nTuple,
00090 nAutoinc
00091 };
00092
00093 dbList* next;
00094 int type;
00095 union {
00096 bool bval;
00097 db_int8 ival;
00098 real8 fval;
00099 char_t* sval;
00100 struct {
00101 int nComponents;
00102 dbList* components;
00103 } aggregate;
00104 };
00105
00106 ~dbList() {
00107 if (type == nTuple) {
00108 dbList* list = aggregate.components;
00109 while (list != NULL) {
00110 dbList* tail = list->next;
00111 delete list;
00112 list = tail;
00113 }
00114 } else if (type == nString) {
00115 delete[] sval;
00116 }
00117 }
00118
00119 dbList(int type) {
00120 this->type = type;
00121 next = NULL;
00122 }
00123 };
00124
00125 class dbUpdateElement {
00126 public:
00127 dbUpdateElement* next;
00128 dbFieldDescriptor* field;
00129 dbExprNode* value;
00130 char_t* strValue;
00131
00132 dbUpdateElement() {
00133 next = NULL;
00134 strValue = NULL;
00135 value = NULL;
00136 }
00137 ~dbUpdateElement() {
00138 delete[] strValue;
00139 delete value;
00140 }
00141 };
00142
00143
00144 #define MAX_HISTORY_SIZE 16
00145
00146 class dbXmlScanner {
00147 public:
00148 enum {
00149 MaxIdentSize = 256
00150 };
00151 enum token {
00152 xml_ident,
00153 xml_sconst,
00154 xml_iconst,
00155 xml_fconst,
00156 xml_lt,
00157 xml_gt,
00158 xml_lts,
00159 xml_gts,
00160 xml_eq,
00161 xml_eof,
00162 xml_error
00163 };
00164 dbXmlScanner(FILE* f) {
00165 in = f;
00166 sconst = new char_t[size = 1024];
00167 line = 1;
00168 pos = 0;
00169 }
00170 token scan();
00171
00172 char_t* getString() {
00173 return sconst;
00174 }
00175
00176 char_t* getIdentifier() {
00177 return ident;
00178 }
00179
00180 size_t getStringLength() {
00181 return slen;
00182 }
00183
00184 db_int8 getInt() {
00185 return iconst;
00186 }
00187
00188 double getReal() {
00189 return fconst;
00190 }
00191
00192 bool expect(int sourcePos, token expected) {
00193 return assure(scan(), sourcePos, expected);
00194 }
00195
00196 bool assure(token tkn, int sourcePos, token expected) {
00197 if (tkn != expected) {
00198 fprintf(stderr, "subsql.cpp:%d: line %d, column %d: Get token %d instead of expected token %d\n",
00199 sourcePos, line, pos, tkn, expected);
00200 return false;
00201 }
00202 return true;
00203 }
00204
00205 bool expect(int sourcePos, char_t* expected) {
00206 token tkn = scan();
00207 if (tkn != xml_ident) {
00208 fprintf(stderr, "subsql.cpp:%d: line %d, column %d: Get token %d instead of expected identifier\n",
00209 sourcePos, line, pos, tkn);
00210 return false;
00211 }
00212 if (STRCMP(ident, expected) != 0) {
00213 FPRINTF(stderr, STRLITERAL("subsql.cpp:%d: line %d, column %d: Get tag '%s' instead of expected '%s'\n"),
00214 sourcePos, line, pos, ident, expected);
00215 return false;
00216 }
00217 return true;
00218 }
00219
00220 private:
00221 int get();
00222 void unget(int ch);
00223
00224 int line;
00225 int pos;
00226 FILE* in;
00227 char_t* sconst;
00228 size_t size;
00229 size_t slen;
00230 db_int8 iconst;
00231 double fconst;
00232 char_t ident[MaxIdentSize];
00233 };
00234
00235 class dbTmpAllocator {
00236 enum {
00237 CHUNK_SIZE = 4096
00238 };
00239 struct Chunk {
00240 Chunk* next;
00241 Chunk* prev;
00242 };
00243 Chunk* curr;
00244 size_t used;
00245
00246 public:
00247 dbTmpAllocator() {
00248 curr = NULL;
00249 used = CHUNK_SIZE;
00250 }
00251
00252 ~dbTmpAllocator() {
00253 reset();
00254 }
00255
00256 void reset() {
00257 Chunk *c, *next;
00258 for (c = curr; c != NULL; c = next) {
00259 next = c->next;
00260 dbFree(c);
00261 }
00262 curr = NULL;
00263 used = CHUNK_SIZE;
00264 }
00265
00266
00267 void* alloc(size_t size) {
00268 size = DOALIGN(size, 8);
00269 if (size > CHUNK_SIZE/2) {
00270 Chunk* newChunk = (Chunk*)dbMalloc(size + sizeof(Chunk));
00271 if (curr != NULL) {
00272 newChunk->next = curr->next;
00273 curr->next = newChunk;
00274 } else {
00275 curr = newChunk;
00276 newChunk->next = NULL;
00277 used = CHUNK_SIZE;
00278 }
00279 return newChunk+1;
00280 } else if (size <= CHUNK_SIZE - used) {
00281 used += size;
00282 return (char*)curr + used - size;
00283 } else {
00284 Chunk* newChunk = (Chunk*)dbMalloc(CHUNK_SIZE);
00285 used = sizeof(Chunk) + size;
00286 newChunk->next = curr;
00287 curr = newChunk;
00288 return newChunk+1;
00289 }
00290 }
00291 };
00292
00300 class TextVector
00301 {
00302 public:
00303 TextVector();
00304 ~TextVector();
00305
00307 void clear();
00308
00310 void add(const char_t *text);
00311
00313 bool inVector(const char_t *text) const;
00314 protected:
00315 typedef char_t *CharPtr;
00316 CharPtr *m_items;
00317 int m_nrItems;
00318 int m_bufSize;
00319
00320 private:
00322 TextVector(const TextVector &other);
00323 TextVector &operator=(const TextVector &other);
00324 };
00325
00326 class dbSubSql : public dbDatabase {
00327 private:
00329 enum SelectionMethod {
00330 sel_all,
00331 sel_all_except,
00332 sel_named_only,
00333 };
00334
00335 int pos;
00336 int line;
00337 int tknPos;
00338 char_t* buf;
00339 int buflen;
00340 FILE* in;
00341 bool opened;
00342 db_int8 ival;
00343 real8 fval;
00344 char_t* name;
00345
00346 oid_t* oidMap;
00347 oid_t oidMapSize;
00348
00349 dbTmpAllocator tmpAlloc;
00350
00351 dbTableDescriptor* metatable;
00352 static char const* prompt;
00353
00354 dbTableDescriptor* droppedTables;
00355 dbTableDescriptor* existedTables;
00356
00357 dbQuery query;
00358 dbCompiler compiler;
00359
00360 int ungetToken;
00361 bool autocommit;
00362
00363 bool dotIsPartOfIdentifier;
00364
00365 char_t* dateFormat;
00366
00367 dbEvent daemonTerminationEvent;
00368 dbThread httpServerThread;
00369 HTTPapi* httpServer;
00370 bool httpServerRunning;
00371 char_t* databasePath;
00372 char* queryHistory[MAX_HISTORY_SIZE];
00373 unsigned historyUsed;
00374 unsigned historyCurr;
00375
00376 static void thread_proc httpServerThreadProc(void* arg);
00377
00378 void deleteColumns(dbFieldDescriptor* columns);
00379
00380 void httpServerLoop();
00381
00382 void startHttpServer(char_t const* address);
00383 void stopHttpServer(char_t const* address);
00384
00385 void handleError(dbErrorClass error, char const* msg = NULL, int arg = 0);
00386
00387 void warning(char const* msg);
00388 void error(char const* msg);
00389
00390 int get();
00391 void unget(int ch);
00392 int scan();
00393 bool parse();
00394
00395 bool expect(char const* expected, int token);
00396
00397 void recovery();
00398 void profile();
00399
00400 void exportDatabase(FILE* out, const TextVector &tables, SelectionMethod method);
00401 bool importDatabase(FILE* in);
00402
00403 oid_t mapId(long id);
00404 bool importField(char_t* terminator, dbFieldDescriptor* fd, byte* rec, dbXmlScanner& scanner);
00405 bool importRecord(char_t* terminator, dbFieldDescriptor* fieldList, byte* rec, dbXmlScanner& scanner);
00406 void insertRecord(dbTableDescriptor* desc, oid_t oid, void const* record);
00407
00408 bool isValidOid(oid_t oid);
00409
00410 void dumpRecord(byte* record, dbFieldDescriptor* first);
00411 static int calculateRecordSize(dbList* list, int offs,
00412 dbFieldDescriptor* first);
00413 int initializeRecordFields(dbList* node, byte* dst, int offs,
00414 dbFieldDescriptor* first);
00415 bool insertRecord(dbList* list, dbTableDescriptor* desc);
00416 bool readCondition();
00417 int readExpression();
00418 int readValues(dbList** chain);
00419 bool updateFields(dbAnyCursor* cursor, dbUpdateElement* elems);
00420 bool updateTable(bool create);
00421 int parseType(char_t*& reftableName, char_t*& inverseRefName);
00422 int updateRecords(dbTableDescriptor* desc, dbList *fields, dbList *values, dbAnyCursor &cursor, byte *buf);
00423
00424 dbFieldDescriptor* readFieldName();
00425
00427 bool parseExportTables(TextVector &tables, SelectionMethod &method);
00428 bool shouldExportTable(const char_t *name, const TextVector &tableNames, SelectionMethod method);
00429
00430 public:
00431 void run(int argc, char* argv[]);
00432 void selectionPage(WWWconnection& con);
00433 void queryPage(WWWconnection& con);
00434 void defaultPage(WWWconnection& con);
00435
00436 dbSubSql(dbAccessType type = dbAllAccess, size_t poolSize = 0);
00437 virtual~dbSubSql();
00438 };
00439
00440 END_GIGABASE_NAMESPACE
00441
00442
00443 #endif