00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __COMPILER_H__
00012 #define __COMPILER_H__
00013
00014 #ifndef DO_NOT_USE_SETJMP
00015 #include <setjmp.h>
00016 #endif
00017
00018 #ifdef USE_REGEX
00019 extern "C" {
00020 #include <regex.h>
00021 };
00022 #endif
00023
00024 BEGIN_GIGABASE_NAMESPACE
00025
00026 #ifdef DO_NOT_USE_SETJMP
00027 struct CompileErrorException {};
00028 struct OutOfBoundsException {};
00029 #else
00030 #if defined(__osf__) || defined(__FreeBSD__)
00031 #define longjmp(b,s) _longjmp(b,s) // do not restore signal context
00032 #define setjmp(b) _setjmp(b)
00033 #endif
00034 #endif
00035
00036 enum dbvmCodes {
00037 #define DBVM(cop, type, n_operands, commutative) cop,
00038 #include "compiler.d"
00039 dbvmLastCode
00040 };
00041
00042
00043 #define IS_CONSTANT(c) \
00044 (unsigned(c) - dbvmLoadVarBool <= (unsigned)dbvmLoadRectangleConstant - dbvmLoadVarBool)
00045
00046
00047
00048
00049
00050 #define IS_EQUAL_CMP(c) dbExprNode::commutativeOperator[c] == c
00051
00052 enum nodeType {
00053 tpInteger,
00054 tpBoolean,
00055 tpReal,
00056 tpString,
00057 tpReference,
00058 tpRectangle,
00059 tpArray,
00060 tpRawBinary,
00061 tpFreeVar,
00062 tpList,
00063 tpVoid
00064 };
00065
00066 enum tokens {
00067 tkn_ident,
00068 tkn_lpar,
00069 tkn_rpar,
00070 tkn_lbr,
00071 tkn_rbr,
00072 tkn_dot,
00073 tkn_comma,
00074 tkn_power,
00075 tkn_iconst,
00076 tkn_sconst,
00077 tkn_fconst,
00078 tkn_all,
00079 tkn_add,
00080 tkn_sub,
00081 tkn_mul,
00082 tkn_div,
00083 tkn_and,
00084 tkn_or,
00085 tkn_not,
00086 tkn_null,
00087 tkn_neg,
00088 tkn_eq,
00089 tkn_ne,
00090 tkn_gt,
00091 tkn_ge,
00092 tkn_lt,
00093 tkn_le,
00094 tkn_between,
00095 tkn_escape,
00096 tkn_exists,
00097 tkn_like,
00098 tkn_limit,
00099 tkn_in,
00100 tkn_length,
00101 tkn_lower,
00102 tkn_upper,
00103 tkn_abs,
00104 tkn_area,
00105 tkn_is,
00106 tkn_integer,
00107 tkn_real,
00108 tkn_string,
00109 tkn_first,
00110 tkn_last,
00111 tkn_current,
00112 tkn_var,
00113 tkn_col,
00114 tkn_true,
00115 tkn_false,
00116 tkn_where,
00117 tkn_follow,
00118 tkn_start,
00119 tkn_from,
00120 tkn_order,
00121 tkn_overlaps,
00122 tkn_by,
00123 tkn_asc,
00124 tkn_desc,
00125 tkn_eof,
00126 tkn_insert,
00127 tkn_into,
00128 tkn_select,
00129 tkn_table,
00130 tkn_error,
00131 tkn_match,
00132 tkn_last_token
00133 };
00134
00135 struct dbStrLiteral {
00136 char_t* str;
00137 int len;
00138 };
00139
00140
00141 class dbUserFunction;
00142 class dbExprNodeSegment;
00143
00144 class GIGABASE_DLL_ENTRY dbExprNodeAllocator {
00145 private:
00146 friend class dbExprNodeSegment;
00147 dbExprNode* freeNodeList;
00148 dbExprNodeSegment* segmentList;
00149 dbMutex mutex;
00150
00151 public:
00152 dbMutex& getMutex() {
00153 return mutex;
00154 }
00155 dbExprNode* allocate();
00156 void deallocate(dbExprNode* node);
00157 void reset();
00158
00159 ~dbExprNodeAllocator();
00160 static dbExprNodeAllocator instance;
00161 };
00162
00163 class GIGABASE_DLL_ENTRY dbExprNode {
00164 public:
00165 nat1 cop;
00166 nat1 type;
00167 nat2 offs;
00168
00169 static const nat1 nodeTypes[];
00170 static const nat1 nodeOperands[];
00171 static const nat1 commutativeOperator[];
00172
00173
00174 union {
00175 dbExprNode* operand[3];
00176 dbExprNode* next;
00177 oid_t oid;
00178 db_int8 ivalue;
00179 real8 fvalue;
00180 rectangle rvalue;
00181 dbStrLiteral svalue;
00182 void const* var;
00183
00184 struct {
00185 dbExprNode* base;
00186 dbFieldDescriptor* field;
00187 } ref;
00188
00189 struct {
00190 dbExprNode* arg[3];
00191 void* fptr;
00192 } func;
00193
00194 #ifdef USE_REGEX
00195 struct {
00196 dbExprNode* opd;
00197 regex_t re;
00198 } regex;
00199 #endif
00200 };
00201
00202 dbExprNode(dbExprNode* node);
00203
00204 dbExprNode(int cop, dbExprNode* left = NULL, dbExprNode* right = NULL,
00205 dbExprNode* right2 = NULL)
00206 {
00207 this->cop = cop;
00208 type = nodeTypes[cop];
00209 operand[0] = left;
00210 operand[1] = right;
00211 operand[2] = right2;
00212 }
00213 dbExprNode(int cop, dbExprNode* expr1, dbExprNode* expr2, int offs) {
00214 this->cop = cop;
00215 this->offs = (nat2)offs;
00216 type = nodeTypes[cop];
00217 operand[0] = expr1;
00218 operand[1] = expr2;
00219 }
00220 dbExprNode(int cop, dbExprNode* expr, int offs) {
00221 this->cop = cop;
00222 this->offs = (nat2)offs;
00223 type = nodeTypes[cop];
00224 operand[0] = expr;
00225 }
00226 dbExprNode(int cop, dbFieldDescriptor* field, dbExprNode* base = NULL)
00227 {
00228 this->cop = cop;
00229 this->offs = (nat2)field->dbsOffs;
00230 type = nodeTypes[cop];
00231 ref.field = field;
00232 ref.base = base;
00233 }
00234 dbExprNode(int cop, db_int8 ivalue) {
00235 this->cop = cop;
00236 this->ivalue = ivalue;
00237 type = tpInteger;
00238 }
00239 dbExprNode(int cop, rectangle rvalue) {
00240 this->cop = cop;
00241 this->rvalue = rvalue;
00242 type = tpRectangle;
00243 }
00244 dbExprNode(int cop, real8 fvalue) {
00245 this->cop = cop;
00246 this->fvalue = fvalue;
00247 type = tpReal;
00248 }
00249 dbExprNode(int cop, dbStrLiteral& svalue) {
00250 this->cop = cop;
00251 this->svalue = svalue;
00252 type = tpString;
00253 }
00254 dbExprNode(int cop, void const* var) {
00255 this->cop = cop;
00256 this->var = var;
00257 type = nodeTypes[cop];
00258 }
00259 dbExprNode(int cop, void* fptr, dbExprNode* expr1, dbExprNode* expr2 = NULL, dbExprNode* expr3 = NULL) {
00260 this->cop = cop;
00261 func.arg[0] = expr1;
00262 func.arg[1] = expr2;
00263 func.arg[2] = expr3;
00264 func.fptr = fptr;
00265 type = nodeTypes[cop];
00266 }
00267 ~dbExprNode();
00268
00269 void* operator new(size_t size) {
00270 return dbExprNodeAllocator::instance.allocate();
00271 }
00272
00273 void operator delete(void* ptr) {
00274 dbExprNodeAllocator::instance.deallocate((dbExprNode*)ptr);
00275 }
00276 };
00277
00278
00279 class dbExprNodeSegment {
00280 public:
00281 enum { allocationQuantum = 1024};
00282 char buf[sizeof(dbExprNode)*allocationQuantum];
00283 dbExprNodeSegment* next;
00284 };
00285
00286
00287 class dbBinding {
00288 public:
00289 dbBinding* next;
00290 char_t const* name;
00291 bool used;
00292 int index;
00293 };
00294
00295 class dbOrderByNode {
00296 public:
00297 dbOrderByNode* next;
00298 dbFieldDescriptor* field;
00299 dbTableDescriptor* table;
00300 dbExprNode* expr;
00301 bool ascent;
00302
00303 dbFieldDescriptor* getField() {
00304 return (field != NULL) ? field
00305 : ((unsigned)expr->cop - dbvmLoadBool <= dbvmLoadRawBinary - dbvmLoadBool)
00306 ? expr->ref.field : NULL;
00307 }
00308
00309 ~dbOrderByNode() {
00310 delete expr;
00311 }
00312 };
00313
00314 class dbFollowByNode {
00315 public:
00316 dbFollowByNode* next;
00317 dbFieldDescriptor* field;
00318 };
00319
00320 class GIGABASE_DLL_ENTRY dbCompiler {
00321 friend class dbQuery;
00322 friend class dbQueryElement;
00323 public:
00324 enum {
00325 #ifdef __SYMBIAN32__
00326 maxStrLen = 1024,
00327 #else
00328 maxStrLen = 4096,
00329 #endif
00330 maxFreeVars = 4
00331 };
00332
00333 dbTableDescriptor* table;
00334 dbQueryElement* queryElement;
00335 int currPos;
00336 int firstPos;
00337 int offsetWithinStatement;
00338 int bvalue;
00339 db_int8 ivalue;
00340 real8 fvalue;
00341 dbStrLiteral svalue;
00342 int lex;
00343 bool has_token;
00344 char_t* name;
00345 dbBinding* bindings;
00346 int nFreeVars;
00347 int varType;
00348 void const* varPtr;
00349 dbTableDescriptor* varRefTable;
00350
00351 #ifndef DO_NOT_USE_SETJMP
00352 jmp_buf abortCompilation;
00353 #endif
00354 static bool initialized;
00355
00356 void compare(dbExprNode* expr, dbExprNode* list);
00357
00358 int scan();
00359 void unget_token(int tkn) {
00360 lex = tkn;
00361 has_token = true;
00362 }
00363
00364 void error(const char* msg, int pos = -1);
00365 dbExprNode* conjunction();
00366 dbExprNode* disjunction();
00367 dbExprNode* comparison();
00368 dbExprNode* addition();
00369 dbExprNode* multiplication();
00370 dbExprNode* power();
00371 dbExprNode* userDefinedOperator();
00372 dbExprNode* term();
00373 dbExprNode* buildList();
00374 dbExprNode* field(dbExprNode* expr, dbTableDescriptor* refTable,
00375 dbFieldDescriptor* fd);
00376
00377 bool compile(dbTableDescriptor* table, dbQuery& query);
00378 dbExprNode* compileExpression(dbTableDescriptor* table, char_t const* expr, int startPos);
00379 void compileOrderByPart(dbQuery& query);
00380 void compileLimitPart(dbQuery& query);
00381 void compileStartFollowPart(dbQuery& query);
00382
00383 void deleteNode(dbExprNode* node);
00384 dbExprNode* rectangleConstant(dbExprNode* head);
00385
00386 dbCompiler();
00387 };
00388
00389 class GIGABASE_DLL_ENTRY dbDatabaseThreadContext : public dbL2List {
00390 public:
00391 dbLockType holdLock;
00392 dbEvent event;
00393
00394 int concurrentId;
00395 dbL2List cursors;
00396
00397 dbCompiler compiler;
00398
00399 bool interactive;
00400 bool catched;
00401 bool commitDelayed;
00402 bool removeContext;
00403
00404 dbLockType pendingLock;
00405 dbDatabaseThreadContext* nextPending;
00406
00407 #ifndef DO_NOT_USE_SETJMP
00408 jmp_buf unwind;
00409 #endif
00410 dbDatabaseThreadContext() {
00411 concurrentId = 0;
00412 holdLock = dbNoLock;
00413 pendingLock = dbNoLock;
00414 interactive = false;
00415 catched = false;
00416 commitDelayed = false;
00417 removeContext = false;
00418 event.open();
00419 }
00420 ~dbDatabaseThreadContext() {
00421 event.close();
00422 }
00423 };
00424
00425 class dbSynthesizedAttribute {
00426 public:
00427 union {
00428 byte* base;
00429 int bvalue;
00430 db_int8 ivalue;
00431 rectangle rvalue;
00432 real8 fvalue;
00433 void* raw;
00434 oid_t oid;
00435
00436 struct {
00437 char* base;
00438 int size;
00439 } array;
00440 };
00441 enum ObjectStorageClass {
00442 osSelf,
00443 osStack,
00444 osDynamic,
00445 osPage,
00446 osFree
00447 };
00448 ObjectStorageClass osClass;
00449 union {
00450 size_t sp;
00451 struct {
00452 byte* addr;
00453 dbSynthesizedAttribute* next;
00454 } loc;
00455 } os;
00456
00457 dbSynthesizedAttribute() : osClass(osSelf) {}
00458 };
00459
00460 class dbInheritedAttribute {
00461 public:
00462 byte* record;
00463 oid_t oid;
00464 dbTableDescriptor* table;
00465 dbDatabase* db;
00466 size_t paramBase;
00467
00468 enum {
00469 #if defined(_ARM) || defined(__SYMBIAN32__)
00470 internalStackSize = 4*1024
00471 #else
00472 internalStackSize = 64*1024
00473 #endif
00474 };
00475
00476
00477 dbSynthesizedAttribute* dynChain;
00478 size_t sp;
00479
00480 struct IteratorContext {
00481 int index;
00482 int sp;
00483 dbSynthesizedAttribute* dynChain;
00484 #ifndef DO_NOT_USE_SETJMP
00485 jmp_buf unwind;
00486 #endif
00487 } exists_iterator[dbCompiler::maxFreeVars];
00488
00489 byte stack[internalStackSize];
00490
00491 void cleanup() {
00492 dbSynthesizedAttribute* attr;
00493 for (attr = dynChain; attr != NULL; attr = attr->os.loc.next) {
00494 free(*attr);
00495 }
00496 }
00497
00498 void unwind(int i) {
00499 IteratorContext* ctx = &exists_iterator[i];
00500 sp = ctx->sp;
00501 while (dynChain != ctx->dynChain) {
00502 free(*dynChain);
00503 }
00504 #ifdef DO_NOT_USE_SETJMP
00505 throw OutOfBoundsException();
00506 #else
00507 longjmp(ctx->unwind, 1);
00508 #endif
00509 }
00510
00511 void makeDynamic(dbSynthesizedAttribute& attr, void* p) {
00512 attr.osClass = dbSynthesizedAttribute::osDynamic;
00513 attr.os.loc.addr = (byte*)p;
00514 attr.os.loc.next = dynChain;
00515 dynChain = &attr;
00516 }
00517 void allocateString(dbSynthesizedAttribute& attr, int len) {
00518 if (sp + len*sizeof(char_t) > sizeof(stack)) {
00519 attr.array.base = (char*)dbMalloc(len*sizeof(char_t));
00520 attr.array.size = len;
00521 makeDynamic(attr, attr.array.base);
00522 } else {
00523 attr.osClass = dbSynthesizedAttribute::osStack;
00524 attr.array.base = (char*)stack + sp;
00525 attr.array.size = len;
00526 attr.os.sp = sp;
00527 sp += len*sizeof(char_t);
00528 }
00529 }
00530 void allocateString(dbSynthesizedAttribute& attr, char_t* str, size_t len) {
00531 allocateString(attr, (int)len);
00532 memcpy(attr.array.base, str, len*sizeof(char_t));
00533 }
00534 void allocateString(dbSynthesizedAttribute& attr, char_t* str) {
00535 allocateString(attr, str, STRLEN(str) + 1);
00536 }
00537
00538 void free(dbSynthesizedAttribute& attr) {
00539 switch (attr.osClass) {
00540 case dbSynthesizedAttribute::osStack:
00541 sp = attr.os.sp;
00542 return;
00543 case dbSynthesizedAttribute::osPage:
00544 db->pool.unfix(attr.os.loc.addr);
00545 break;
00546 case dbSynthesizedAttribute::osDynamic:
00547 dbFree(attr.os.loc.addr);
00548 break;
00549 default:
00550 return;
00551 }
00552 dbSynthesizedAttribute** sap;
00553 for (sap = &dynChain; *sap != &attr; sap = &(*sap)->os.loc.next);
00554 *sap = attr.os.loc.next;
00555 attr.osClass = dbSynthesizedAttribute::osFree;
00556 }
00557
00558 void load(dbSynthesizedAttribute& sattr) {
00559 offs_t pos = db->getPos(sattr.oid) & ~dbFlagsMask;
00560 int offs = (int)pos & (dbPageSize-1);
00561 byte* page = db->pool.get(pos - offs);
00562 dbRecord* rec = (dbRecord*)(page + offs);
00563 size_t size = rec->size;
00564 if (offs + size > dbPageSize) {
00565 byte* dst;
00566 size_t start = DOALIGN(sp, 8);
00567 if (start + size > sizeof(stack)) {
00568 dst = dbMalloc(size);
00569 makeDynamic(sattr, dst);
00570 } else {
00571 sattr.osClass = dbSynthesizedAttribute::osStack;
00572 sattr.os.sp = sp;
00573 dst = stack + start;
00574 sp = start + size;
00575 }
00576 sattr.base = dst;
00577 memcpy(dst, rec, dbPageSize - offs);
00578 db->pool.unfix(page);
00579 size -= dbPageSize - offs;
00580 pos += dbPageSize - offs;
00581 dst += dbPageSize - offs;
00582 while (size > dbPageSize) {
00583 page = db->pool.get(pos);
00584 memcpy(dst, page, dbPageSize);
00585 db->pool.unfix(page);
00586 dst += dbPageSize;
00587 size -= dbPageSize;
00588 pos += dbPageSize;
00589 }
00590 page = db->pool.get(pos);
00591 memcpy(dst, page, size);
00592 db->pool.unfix(page);
00593 } else {
00594 sattr.base = (byte*)rec;
00595 sattr.osClass = dbSynthesizedAttribute::osPage;
00596 sattr.os.loc.addr = page;
00597 sattr.os.loc.next = dynChain;
00598 dynChain = &sattr;
00599 }
00600 }
00601
00602 dbInheritedAttribute() {
00603 dynChain = NULL;
00604 sp = 0;
00605 }
00606
00607 ~dbInheritedAttribute() {
00608 cleanup();
00609 }
00610 };
00611
00612 inline char_t* findWildcard(char_t* pattern, char_t* escape = NULL)
00613 {
00614 if (escape == NULL) {
00615 while (*pattern != dbMatchAnyOneChar &&
00616 *pattern != dbMatchAnySubstring)
00617 {
00618 if (*pattern++ == '\0') {
00619 return NULL;
00620 }
00621 }
00622 } else {
00623 char_t esc = *escape;
00624 while (*pattern != dbMatchAnyOneChar &&
00625 *pattern != dbMatchAnySubstring &&
00626 *pattern != esc)
00627 {
00628 if (*pattern++ == '\0') {
00629 return NULL;
00630 }
00631 }
00632 }
00633 return pattern;
00634 }
00635
00636
00637 END_GIGABASE_NAMESPACE
00638
00639 #endif
00640
00641
00642