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