00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <assert.h>
00029 #include <wctype.h>
00030 #include <limits.h>
00031 #include <eyedb/oqlctb.h>
00032 #include <set>
00033 #include <vector>
00034
00035
00036
00037
00038
00039
00040 #define SYNC_SYM_GARB_1
00041 #define SYNC_SYM_GARB_2
00042
00043
00044
00045
00046 #define NEW_SUPPRESS_DOUBLES
00047
00048 #include "oql_p.h"
00049
00050 namespace eyedb {
00051
00052
00053
00054
00055
00056
00057
00058 LinkedList oqmlObjectManager::freeList;
00059 ObjCache *oqmlObjectManager::objCacheIdx = new ObjCache(1024);
00060 ObjCache *oqmlObjectManager::objCacheObj = new ObjCache(1024);
00061
00062 gbLink *oqmlGarbManager::first, *oqmlGarbManager::last;
00063 oqmlBool oqmlGarbManager::garbaging = oqml_False;
00064 unsigned int oqmlGarbManager::count = 0;
00065 LinkedList oqmlGarbManager::str_list;
00066 LinkedList oqmlNode::node_list;
00067
00068
00069
00070
00071
00072
00073
00074 std::list<gbContext *> oqmlGarbManager::ctx_l;
00075
00076 gbContext *oqmlGarbManager::peek()
00077 {
00078 gbContext *ctx = new gbContext(last);
00079 ctx_l.push_back(ctx);
00080 return ctx;
00081 }
00082
00083 void oqmlGarbManager::garbage(gbContext *ctx)
00084 {
00085 garbage(ctx->link, false);
00086
00087 delete ctx;
00088
00089 std::list<gbContext *>::iterator begin = ctx_l.begin();
00090 std::list<gbContext *>::iterator end = ctx_l.end();
00091 while (begin != end) {
00092 if ((*begin) == ctx) {
00093 ctx_l.erase(begin);
00094 return;
00095 }
00096 ++begin;
00097 }
00098 }
00099
00100 void oqmlGarbManager::garbage(gbLink *l, bool full)
00101 {
00102 if (!l)
00103 return;
00104
00105 if (!full)
00106 l = l->next;
00107
00108 unsigned int cnt_atoms = 0, cnt_lists = 0;
00109 unsigned int total_cnt_atoms = 0, total_cnt_lists = 0;
00110
00111 #ifdef GARB_TRACE
00112 printf("GARBAGE %s %u %u\n", (full ? "full" : "partial"),
00113 oqmlObjectManager::objCacheIdx->getObjectCount(),
00114 oqmlObjectManager::objCacheObj->getObjectCount());
00115 #endif
00116 garbaging = oqml_True;
00117 int toDel_cnt = 0;
00118 gbLink **links = new gbLink*[count];
00119
00120 while (l) {
00121 Bool toDel = False;
00122 gbLink *next = l->next;
00123 if (l->at) {
00124 if (!l->at->refcnt) {
00125 delete l->at;
00126 cnt_atoms++;
00127 toDel = True;
00128 }
00129 total_cnt_atoms++;
00130 }
00131
00132 if (l->atlist) {
00133 if (!l->atlist->refcnt) {
00134 l->atlist->first = 0;
00135 delete l->atlist;
00136 cnt_lists++;
00137 toDel = True;
00138 }
00139 total_cnt_lists++;
00140 }
00141
00142 if (toDel)
00143 links[toDel_cnt++] = l;
00144 l = next;
00145 }
00146
00147 garbaging = oqml_False;
00148
00149 for (int i = 0; i < toDel_cnt; i++)
00150 remove(links[i]);
00151
00152 delete [] links;
00153
00154 #ifdef GARB_TRACE
00155 printf("%u/%u atoms garbaged\n", cnt_atoms, total_cnt_atoms);
00156 printf("%u/%u lists garbaged\n", cnt_lists, total_cnt_atoms);
00157 #endif
00158 }
00159
00160 void oqmlGarbManager::garbage()
00161 {
00162 unsigned int cnt_str = 0;
00163 #if 0
00164 unsigned int cnt_atoms = 0, cnt_lists = 0;
00165 unsigned int total_cnt_atoms = 0, total_cnt_lists = 0;
00166 gbLink *l = first;
00167
00168 #ifdef GARB_TRACE
00169 printf("GARBAGE global %u %u\n",
00170 oqmlObjectManager::objCacheIdx->getObjectCount(),
00171 oqmlObjectManager::objCacheObj->getObjectCount());
00172 #endif
00173
00174 garbaging = oqml_True;
00175 int toDel_cnt = 0;
00176 gbLink **links = new gbLink*[count];
00177
00178 while (l) {
00179 Bool toDel = False;
00180 gbLink *next = l->next;
00181 if (l->at) {
00182 if (!l->at->refcnt) {
00183 delete l->at;
00184 cnt_atoms++;
00185 toDel = True;
00186 }
00187 total_cnt_atoms++;
00188 }
00189
00190 if (l->atlist) {
00191 if (!l->atlist->refcnt) {
00192 l->atlist->first = 0;
00193 delete l->atlist;
00194 cnt_lists++;
00195 toDel = True;
00196 }
00197 total_cnt_lists++;
00198 }
00199
00200 if (toDel)
00201 links[toDel_cnt++] = l;
00202 l = next;
00203 }
00204 #else
00205 garbage(first, true);
00206 garbaging = oqml_True;
00207 #endif
00208 if (str_list.getCount()) {
00209 LinkedListCursor c(str_list);
00210 char **tabs = new char *[str_list.getCount()];
00211 char *s;
00212 while (c.getNext((void* &)s)) {
00213 free(s);
00214 tabs[cnt_str++] = s;
00215 }
00216
00217 for (int i = 0; i < cnt_str; i++)
00218 str_list.deleteObject(tabs[i]);
00219
00220 delete [] tabs;
00221 }
00222
00223 garbaging = oqml_False;
00224
00225 #if 0
00226 for (int i = 0; i < toDel_cnt; i++)
00227 remove(links[i]);
00228
00229 delete [] links;
00230 #endif
00231
00232 #if 0
00233 #ifdef GARB_TRACE
00234 printf("%u/%u atoms garbaged\n", cnt_atoms, total_cnt_atoms);
00235 printf("%u/%u lists garbaged\n", cnt_lists, total_cnt_atoms);
00236 printf("%u strings garbaged\n", cnt_str);
00237 #endif
00238 #endif
00239 oqmlNode::garbageNodes();
00240 oqmlObjectManager::garbageObjects();
00241 }
00242
00243 const char *
00244 oqmlAtomType::getString() const
00245 {
00246 static char typestr[4][32];
00247 static int n;
00248
00249 if (n >= 4)
00250 n = 0;
00251
00252 switch(type) {
00253 case oqmlATOM_BOOL:
00254 strcpy(typestr[n], "bool");
00255 break;
00256
00257 case oqmlATOM_OID:
00258 strcpy(typestr[n], "oid");
00259 break;
00260
00261 case oqmlATOM_INT:
00262 strcpy(typestr[n], "integer");
00263 break;
00264
00265 case oqmlATOM_DOUBLE:
00266 strcpy(typestr[n], "float");
00267 break;
00268
00269 case oqmlATOM_CHAR:
00270 strcpy(typestr[n], char_class_name);
00271 break;
00272
00273 case oqmlATOM_STRING:
00274 strcpy(typestr[n], "string");
00275 break;
00276
00277 case oqmlATOM_IDENT:
00278 strcpy(typestr[n], "ident");
00279 break;
00280
00281 case oqmlATOM_LIST:
00282 strcpy(typestr[n], "list");
00283 break;
00284
00285 case oqmlATOM_BAG:
00286 strcpy(typestr[n], "bag");
00287 break;
00288
00289 case oqmlATOM_SET:
00290 strcpy(typestr[n], "set");
00291 break;
00292
00293 case oqmlATOM_ARRAY:
00294 strcpy(typestr[n], "array");
00295 break;
00296
00297 case oqmlATOM_STRUCT:
00298 strcpy(typestr[n], "struct");
00299 break;
00300
00301 case oqmlATOM_OBJ:
00302 strcpy(typestr[n], "object");
00303 break;
00304
00305 case oqmlATOM_NODE:
00306 strcpy(typestr[n], "node");
00307 break;
00308
00309 case oqmlATOM_SELECT:
00310 strcpy(typestr[n], "select");
00311 break;
00312
00313 case oqmlATOM_NULL:
00314 strcpy(typestr[n], NullString);
00315 break;
00316
00317 case oqmlATOM_NIL:
00318 strcpy(typestr[n], "nil");
00319 break;
00320
00321 default:
00322 strcpy(typestr[n], "<unknown>");
00323 break;
00324 }
00325
00326 return typestr[n++];
00327 }
00328
00329
00330
00331
00332
00333
00334
00335 oqmlNode::oqmlNode(oqmlTYPE _type)
00336 {
00337 type = _type;
00338 eval_type.type = (oqmlATOMTYPE)0;
00339 eval_type.cls = 0;
00340 eval_type.comp = oqml_False;
00341 cst_list = 0;
00342 loc.from = -1;
00343 loc.to = -1;
00344 locked = oqml_False;
00345 is_statement = oqml_False;
00346 back = 0;
00347
00348 registerNode(this);
00349 }
00350
00351 void
00352 oqmlNode::registerNode(oqmlNode *node)
00353 {
00354 node_list.insertObjectLast(node);
00355 }
00356
00357 void oqmlNode::locate(int from, int to)
00358 {
00359 loc.from = from;
00360 loc.to = to;
00361 }
00362
00363 static int __garb_guardian__;
00364
00365 void
00366 oqmlNode::garbageNodes()
00367 {
00368 __garb_guardian__ = 1;
00369
00370 oqmlNode *node;
00371 #if 0
00372 LinkedListCursor c1(node_list);
00373 while (c1.getNext((void *&)node)) {
00374 if (!node->isLocked())
00375 printf("freeing node '%s'\n", node->toString().c_str());
00376 else
00377 printf("node '%s' is locked\n", node->toString().c_str());
00378 }
00379 #endif
00380
00381 LinkedListCursor c(node_list);
00382
00383 while (c.getNext((void *&)node))
00384 if (!node->isLocked())
00385 delete node;
00386
00387 node_list.empty();
00388 __garb_guardian__ = 0;
00389 }
00390
00391 oqmlSymbolTable oqmlContext::stsymtab;
00392
00393 #define CTX_REENTRANT
00394
00395 oqmlStatus *oqmlNode::realize(Database *db, oqmlAtomList **al)
00396 {
00397 #ifdef CTX_REENTRANT
00398 oqmlContext oqml_ctx_st;
00399 oqmlContext *oqml_ctx = &oqml_ctx_st;
00400 #else
00401 static oqmlContext *oqml_ctx;
00402
00403 oqmlContext *ctx_sv = oqml_ctx;
00404 if (!oqml_ctx)
00405 oqml_ctx = new oqmlContext();
00406 #endif
00407
00408 oqmlStatus *s = compile(db, oqml_ctx);
00409
00410 if (!s)
00411 s = eval(db, oqml_ctx, al);
00412
00413 #ifndef CTX_REENTRANT
00414 if (!ctx_sv)
00415 delete oqml_ctx;
00416
00417 oqml_ctx = ctx_sv;
00418 #endif
00419 return s;
00420 }
00421
00422 oqmlStatus *
00423 oqmlNode::evalLeft(Database *db, oqmlContext *ctx, oqmlAtom **a,
00424 int &idx)
00425 {
00426 oqmlAtomList *alist;
00427 oqmlStatus *s = eval(db, ctx, &alist);
00428 if (s) return s;
00429
00430 idx = -1;
00431
00432 if (alist->cnt == 1 && alist->first->as_ident()) {
00433 *a = alist->first->as_ident();
00434 return oqmlSuccess;
00435 }
00436
00437 if (alist->cnt == 1)
00438 return new oqmlStatus(this, "%s is not a left value.",
00439 alist->first->getString());
00440
00441 return new oqmlStatus(this, "not a left value.");
00442 }
00443
00444 void oqmlNode::requalifyType(oqmlTYPE _type)
00445 {
00446
00447 type = _type;
00448 }
00449
00450 oqmlNode::~oqmlNode()
00451 {
00452
00453 assert(__garb_guardian__);
00454
00455 }
00456
00457 oqmlStatus *oqmlNode::compEval(Database *db, oqmlContext *ctx,
00458 oqmlAtomType *at)
00459 {
00460 oqmlStatus *s;
00461 s = compile(db, ctx);
00462
00463 if (s)
00464 return s;
00465
00466 evalType(db, ctx, at);
00467
00468 return oqmlSuccess;
00469 }
00470
00471
00472
00473
00474
00475
00476
00477 oqmlComp::oqmlComp(oqmlTYPE _type, oqmlNode *_qleft, oqmlNode *_qright,
00478 const char *_opstr) : oqmlNode(_type)
00479 {
00480 iter = 0;
00481 cst_atom = 0;
00482 opstr = strdup(_opstr);
00483 qleft = _qleft;
00484 qright = _qright;
00485 locked = oqml_False;
00486 }
00487
00488 oqmlComp::~oqmlComp()
00489 {
00490
00491
00492 delete iter;
00493 free(opstr);
00494 }
00495
00496
00497
00498
00499
00500
00501
00502 oqml_List::oqml_List()
00503 {
00504 cnt = 0;
00505 first = last = 0;
00506 }
00507
00508 oqml_List::~oqml_List()
00509 {
00510 oqml_Link *l = first;
00511 while (l) {
00512 oqml_Link *next = l->next;
00513 delete l;
00514 l = next;
00515 }
00516 }
00517
00518 oqmlBool
00519 oqml_List::hasIdent(const char *_ident)
00520 {
00521 oqml_Link *l = first;
00522 while (l) {
00523 if (l->ql->hasIdent(_ident))
00524 return oqml_True;
00525 l = l->next;
00526 }
00527
00528 return oqml_False;
00529 }
00530
00531 void
00532 oqmlNode::lock()
00533 {
00534 locked = oqml_True;
00535 oqmlLock(cst_list, oqml_True);
00536 }
00537
00538 void
00539 oqmlNode::unlock()
00540 {
00541 locked = oqml_False;
00542 oqmlLock(cst_list, oqml_False);
00543
00544 if (node_list.getPos(this) < 0) {
00545
00546 registerNode(this);
00547 }
00548 }
00549
00550 void
00551 oqml_List::lock()
00552 {
00553 oqml_Link *l = first;
00554 while (l) {
00555 l->ql->lock();
00556 l = l->next;
00557 }
00558 }
00559
00560 void
00561 oqml_List::unlock()
00562 {
00563 oqml_Link *l = first;
00564 while (l) {
00565 l->ql->unlock();
00566 l = l->next;
00567 }
00568 }
00569
00570 std::string
00571 oqml_List::toString() const
00572 {
00573 std::string s = "";
00574 oqml_Link *l = first;
00575
00576 for (int n = 0; l; n++) {
00577 if (n) s += ",";
00578 s += l->ql->toString();
00579 l = l->next;
00580 }
00581
00582 return s;
00583 }
00584
00585 oqml_Link::oqml_Link(oqmlNode *_ql)
00586 {
00587 ql = _ql;
00588 next = 0;
00589 }
00590
00591 oqml_Link::~oqml_Link()
00592 {
00593
00594 }
00595
00596 void oqml_List::add(oqmlNode *ql)
00597 {
00598 oqml_Link *l = new oqml_Link(ql);
00599 if (last) {
00600 last->next = l;
00601 last = l;
00602 }
00603 else
00604 first = last = l;
00605
00606 cnt++;
00607 }
00608
00609 oqml_IdentLink::oqml_IdentLink(const char *_ident, oqmlNode *_ql)
00610 {
00611 ident = _ident ? strdup(_ident) : 0;
00612 ql = _ql;
00613 left = 0;
00614 next = 0;
00615 skipIdent = oqml_False;
00616 requalified = oqml_False;
00617 cls = 0;
00618 }
00619
00620 void
00621 oqml_IdentLink::lock()
00622 {
00623 if (ql) ql->lock();
00624 if (left) left->lock();
00625 }
00626
00627 void
00628 oqml_IdentLink::unlock()
00629 {
00630 if (ql) ql->unlock();
00631 if (left) left->unlock();
00632 }
00633
00634 oqml_IdentLink::oqml_IdentLink(oqmlNode *_left, oqmlNode *_right)
00635 {
00636 ident = 0;
00637 left = _left;
00638 ql = _right;
00639 next = 0;
00640 }
00641
00642 oqml_IdentLink::~oqml_IdentLink()
00643 {
00644 free(ident);
00645 }
00646
00647 oqml_IdentList::oqml_IdentList()
00648 {
00649 cnt = 0;
00650 first = last = 0;
00651 }
00652
00653 void
00654 oqml_IdentList::lock()
00655 {
00656 oqml_IdentLink *l = first;
00657 while (l) {
00658 l->lock();
00659 l = l->next;
00660 }
00661 }
00662
00663 void
00664 oqml_IdentList::unlock()
00665 {
00666 oqml_IdentLink *l = first;
00667 while (l) {
00668 l->unlock();
00669 l = l->next;
00670 }
00671 }
00672
00673 oqml_IdentList::~oqml_IdentList()
00674 {
00675 oqml_IdentLink *l = first;
00676 while (l) {
00677 oqml_IdentLink *next = l->next;
00678 delete l;
00679 l = next;
00680 }
00681 }
00682
00683 void oqml_IdentList::add(const char *ident, oqmlNode *ql)
00684 {
00685 oqml_IdentLink *l = new oqml_IdentLink(ident, ql);
00686 if (last) {
00687 last->next = l;
00688 last = l;
00689 }
00690 else
00691 first = last = l;
00692
00693 cnt++;
00694 }
00695
00696 void oqml_IdentList::add(oqmlNode *left, oqmlNode *right)
00697 {
00698 oqml_IdentLink *l = new oqml_IdentLink(left, right);
00699 if (last) {
00700 last->next = l;
00701 last = l;
00702 }
00703 else
00704 first = last = l;
00705
00706 cnt++;
00707 }
00708
00709
00710
00711
00712
00713
00714
00715 oqmlAtom *
00716 oqmlAtom::make_atom(const IteratorAtom &atom, Class *cls)
00717 {
00718
00719 switch(atom.type) {
00720 case IteratorAtom_INT16:
00721 return new oqmlAtom_int(atom.i16);
00722
00723 case IteratorAtom_INT32:
00724 return new oqmlAtom_int(atom.i32);
00725
00726 case IteratorAtom_INT64:
00727 return new oqmlAtom_int(atom.i64);
00728
00729 case IteratorAtom_STRING:
00730 return new oqmlAtom_string(atom.str);
00731
00732 case IteratorAtom_OID:
00733 return new oqmlAtom_oid(atom.oid, cls);
00734
00735 case IteratorAtom_CHAR:
00736 return new oqmlAtom_char(atom.c);
00737
00738 case IteratorAtom_DOUBLE:
00739 return new oqmlAtom_double(atom.d);
00740
00741 #ifndef NEW_ITER_ATOM
00742 case IteratorAtom_BOOL:
00743 return new oqmlAtom_bool((oqmlBool)atom.b);
00744
00745 case IteratorAtom_IDENT:
00746 return new oqmlAtom_ident(atom.ident);
00747 #endif
00748
00749 case IteratorAtom_IDR:
00750 default:
00751 assert(0);
00752 return 0;
00753 }
00754 }
00755
00756 static void
00757 incr_ref_count(Object *o)
00758 {
00759 if (!o)
00760 return;
00761
00762 if (o->getMasterObject(false)) {
00763 incr_ref_count(o->getMasterObject(false));
00764 return;
00765 }
00766
00767 o->incrRefCount();
00768 }
00769
00770 oqmlAtom *
00771 oqmlAtom::make_atom(Data data, oqmlATOMTYPE type, const Class *cls)
00772 {
00773 switch(type) {
00774 case oqmlATOM_OID: {
00775 Oid noid;
00776 memcpy(&noid, data, sizeof(Oid));
00777 return new oqmlAtom_oid(noid, (Class *)cls);
00778 }
00779
00780 case oqmlATOM_OBJ: {
00781 Object *o;
00782 mcp(&o, data, sizeof(Object *));
00783
00784 incr_ref_count(o);
00785 return oqmlObjectManager::registerObject(o);
00786 }
00787
00788 case oqmlATOM_STRING:
00789 return new oqmlAtom_string((char *)data);
00790
00791 case oqmlATOM_IDENT:
00792 return new oqmlAtom_ident((char *)data);
00793
00794 case oqmlATOM_INT: {
00795 if (!cls || cls->asInt64Class()) {
00796 eyedblib::int64 ni;
00797 memcpy(&ni, data, sizeof(eyedblib::int64));
00798 return new oqmlAtom_int(ni);
00799 }
00800
00801 if (cls->asInt32Class() || cls->asEnumClass()) {
00802 eyedblib::int32 ni;
00803 memcpy(&ni, data, sizeof(eyedblib::int32));
00804 return new oqmlAtom_int(ni);
00805 }
00806
00807 if (cls->asInt16Class()) {
00808 eyedblib::int16 ni;
00809 memcpy(&ni, data, sizeof(eyedblib::int16));
00810 return new oqmlAtom_int(ni);
00811 }
00812
00813 return new oqmlAtom_int(0);
00814 }
00815
00816 case oqmlATOM_DOUBLE: {
00817 double nd;
00818 memcpy(&nd, data, sizeof(double));
00819 return new oqmlAtom_double(nd);
00820 }
00821
00822 case oqmlATOM_CHAR:
00823 return new oqmlAtom_char((char)data[0]);
00824
00825 default:
00826 assert(0);
00827 }
00828 }
00829
00830 oqmlAtom::oqmlAtom(const oqmlAtom&)
00831 {
00832 abort();
00833 }
00834
00835 oqmlAtom & oqmlAtom::operator =(const oqmlAtom &atom)
00836 {
00837 abort();
00838 return *this;
00839 }
00840
00841 oqmlBool oqmlAtom::makeEntry(int ind, unsigned char *entry, int key_len,
00842 const Class *_class) const
00843 {
00844
00845
00846
00847
00848 x2h_32_cpy(entry, &ind);
00849 memset(entry+sizeof(eyedblib::int32), 0, key_len);
00850 int len;
00851 Data val;
00852 Size size = key_len;
00853 return getData(entry+sizeof(eyedblib::int32), &val, size, len, _class);
00854 }
00855
00856
00857
00858
00859
00860
00861
00862 char *oqmlAtom_oid::makeString(FILE *fd) const
00863 {
00864 if (fd) {
00865 fprintf(fd, "%s", oid.getString());
00866 return 0;
00867 }
00868 else if (string)
00869 return string;
00870 else {
00871 char buf[64];
00872 sprintf(buf, "%s", oid.getString());
00873 ((oqmlAtom *)this)->string = strdup(buf);
00874 return string;
00875 }
00876 }
00877
00878 char *oqmlAtom_int::makeString(FILE *fd) const
00879 {
00880 if (fd) {
00881 fprintf(fd, "%lld", i);
00882 return 0;
00883 }
00884 else if (string)
00885 return string;
00886 else {
00887 char buf[32];
00888 sprintf(buf, "%lld", i);
00889 ((oqmlAtom *)this)->string = strdup(buf);
00890 return string;
00891 }
00892 }
00893
00894 char *oqmlAtom_double::makeString(FILE *fd) const
00895 {
00896 if (fd) {
00897 fprintf(fd, "%f", d);
00898 return 0;
00899 }
00900 else if (string)
00901 return string;
00902 else {
00903 char buf[16];
00904 sprintf(buf, "%f", d);
00905 ((oqmlAtom *)this)->string = strdup(buf);
00906 return string;
00907 }
00908 }
00909
00910 char *oqmlAtom_bool::makeString(FILE *fd) const
00911 {
00912 if (fd) {
00913 fprintf(fd, "%s", (b ? "true" : "false"));
00914 return 0;
00915 }
00916 else if (string)
00917 return string;
00918 else {
00919 char buf[16];
00920 sprintf(buf, "%s", (b ? "true" : "false"));
00921 ((oqmlAtom *)this)->string = strdup(buf);
00922 return string;
00923 }
00924 }
00925
00926 char *oqmlAtom_nil::makeString(FILE *fd) const
00927 {
00928 if (fd) {
00929 fprintf(fd, NilString);
00930 return 0;
00931 }
00932 else if (string)
00933 return string;
00934 else {
00935 ((oqmlAtom *)this)->string = strdup(NilString);
00936 return string;
00937 }
00938 }
00939
00940 char *oqmlAtom_null::makeString(FILE *fd) const
00941 {
00942 if (fd) {
00943 fprintf(fd, NullString);
00944 return 0;
00945 }
00946 else if (string)
00947 return string;
00948 else {
00949 ((oqmlAtom *)this)->string = strdup(NullString);
00950 return string;
00951 }
00952 }
00953
00954 char *oqmlAtom_char::makeString(FILE *fd) const
00955 {
00956 static const char cfmt[] = "'%c'";
00957 static const char ofmt[] = "'\\%03o'";
00958
00959 if (fd) {
00960 if (iswprint(c)) fprintf(fd, cfmt, c);
00961 else fprintf(fd, ofmt, c);
00962 return 0;
00963 }
00964 else if (string)
00965 return string;
00966 else {
00967 char buf[8];
00968 if (iswprint(c)) sprintf(buf, cfmt, c);
00969 else sprintf(buf, ofmt, c);
00970 ((oqmlAtom *)this)->string = strdup(buf);
00971 return string;
00972 }
00973 }
00974
00975 char *oqmlAtom_string::makeString(FILE *fd) const
00976 {
00977 if (fd) {
00978 fprintf(fd, "\"%s\"", shstr->s);
00979 return 0;
00980 }
00981 else if (string)
00982 return string;
00983 else {
00984 char *buf = (char *)malloc(strlen(shstr->s)+3);
00985 sprintf(buf, "\"%s\"", shstr->s);
00986 ((oqmlAtom *)this)->string = buf;
00987 return string;
00988 }
00989 }
00990
00991
00992 char *oqmlAtom_ident::makeString(FILE *fd) const
00993 {
00994 if (fd) {
00995 fprintf(fd, "%s", shstr->s);
00996 return 0;
00997 }
00998 else if (string)
00999 return string;
01000 else {
01001 ((oqmlAtom *)this)->string = strdup(shstr->s);
01002 return string;
01003 }
01004 }
01005
01006 char *oqmlAtom_obj::makeString(FILE *fd) const
01007 {
01008 if (fd) {
01009 fprintf(fd, "%lx:obj", idx);
01010 return 0;
01011 }
01012
01013 if (string)
01014 return string;
01015 else {
01016 char buf[12];
01017 sprintf(buf, "%lx:obj", idx);
01018 ((oqmlAtom *)this)->string = strdup(buf);
01019 return string;
01020 }
01021 }
01022
01023 char *oqmlAtom_node::makeString(FILE *fd) const
01024 {
01025 if (fd) {
01026 fprintf(fd, "%s", node->toString().c_str());
01027 return 0;
01028 }
01029
01030 if (!string)
01031 ((oqmlAtom *)this)->string = strdup(node->toString().c_str());
01032 return string;
01033 }
01034
01035 oqmlBool
01036 oqmlAtom_node::getData(unsigned char[], Data *, Size&, int&,
01037 const Class *) const
01038 {
01039 abort();
01040 return oqml_False;
01041 }
01042
01043 int
01044 oqmlAtom_node::getSize() const
01045 {
01046 abort();
01047 return 0;
01048 }
01049
01050 oqmlBool
01051 oqmlAtom_node::compare(unsigned char *, int, Bool, oqmlTYPE) const
01052 {
01053 abort();
01054 return oqml_False;
01055 }
01056
01057 char *oqmlAtom_select::makeString(FILE *fd) const
01058 {
01059 if (fd) {
01060 fprintf(fd, "%s", (node ? node->toString() : std::string("")).c_str());
01061 return 0;
01062 }
01063
01064 if (!string)
01065 ((oqmlAtom *)this)->string = strdup((node ? node->toString() : std::string("")).c_str());
01066 return string;
01067 }
01068
01069 oqmlBool
01070 oqmlAtom_select::getData(unsigned char[], Data *, Size&, int&,
01071 const Class *) const
01072 {
01073 abort();
01074 return oqml_False;
01075 }
01076
01077 int
01078 oqmlAtom_select::getSize() const
01079 {
01080 abort();
01081 return 0;
01082 }
01083
01084 oqmlBool
01085 oqmlAtom_select::compare(unsigned char *, int, Bool, oqmlTYPE) const
01086 {
01087 abort();
01088 return oqml_False;
01089 }
01090
01091 char *oqmlAtom_coll::makeString(FILE *fd) const
01092 {
01093 if (fd) {
01094 fprintf(fd, getTypeName());
01095 if (list)
01096 list->print(fd);
01097 else
01098 fprintf(fd, "()");
01099 return 0;
01100 }
01101
01102 if (string)
01103 return string;
01104
01105 if (!list) {
01106 ((oqmlAtom_coll *)this)->string = strdup("()");
01107 return string;
01108 }
01109
01110 char *buf = list->getString();
01111 ((oqmlAtom_coll *)this)->string = (char *)malloc(strlen(buf)+20);
01112 sprintf(string, "%s(%s)", getTypeName(), buf);
01113 return string;
01114 }
01115
01116 char *oqmlAtom_struct::makeString(FILE *fd) const
01117 {
01118 if (fd) {
01119 fprintf(fd, "%s", makeString(0));
01120 return 0;
01121 }
01122
01123 if (string)
01124 return string;
01125
01126 std::string s = "struct(";
01127
01128 for (int i = 0; i < attr_cnt; i++) {
01129 if (i) s += ", ";
01130 s += attr[i].name;
01131 s += ": ";
01132 s += (attr[i].value ? attr[i].value->makeString(0) : "");
01133 }
01134
01135 s += ")";
01136 ((oqmlAtom *)this)->string = strdup(s.c_str());
01137 return string;
01138 }
01139
01140 oqmlBool
01141 oqmlAtom_struct::getData(unsigned char[], Data *, Size&, int&,
01142 const Class *) const
01143 {
01144 abort();
01145 return oqml_False;
01146 }
01147
01148 int
01149 oqmlAtom_struct::getSize() const
01150 {
01151 abort();
01152 return 0;
01153 }
01154
01155 oqmlBool
01156 oqmlAtom_struct::compare(unsigned char *, int, Bool, oqmlTYPE) const
01157 {
01158 abort();
01159 return oqml_False;
01160 }
01161
01162 oqmlStatus *
01163 oqmlAtom_struct::setAtom(oqmlAtom *a, int idx, oqmlNode *)
01164 {
01165 assert (idx >= 0 && idx < attr_cnt);
01166 attr[idx].value = (a ? a->copy() : 0);
01167 return oqmlSuccess;
01168 }
01169
01170 oqmlAtom *
01171 oqmlAtom_struct::getAtom(const char *name, int &idx)
01172 {
01173 for (int i = 0; i < attr_cnt; i++)
01174 if (!strcmp(attr[i].name, name)) {
01175 idx = i;
01176 return attr[i].value;
01177 }
01178
01179 idx = -1;
01180 return 0;
01181 }
01182
01183 oqmlAtom *
01184 oqmlAtom_struct::getAtom(unsigned int idx)
01185 {
01186 return (idx < 0 || idx >= attr_cnt) ? 0 : attr[idx].value;
01187 }
01188
01189 oqmlBool oqmlAtom_string::makeEntry(int ind, unsigned char *entry, int key_len,
01190 const Class *) const
01191 {
01192 if (key_len < strlen(shstr->s))
01193 return oqml_False;
01194
01195 x2h_32_cpy(entry, &ind);
01196 memset(entry+sizeof(eyedblib::int32), 0, key_len);
01197 strcpy((char *)entry+sizeof(eyedblib::int32), shstr->s);
01198 return oqml_True;
01199 }
01200
01201 oqmlBool
01202 oqmlAtom_int::getData(unsigned char data[], Data *val,
01203 Size &size, int &len, const Class *cls) const
01204 {
01205 unsigned int psize;
01206
01207 if (!cls || cls->asInt64Class()) {
01208 psize = sizeof(eyedblib::int64);
01209
01210 eyedblib::int64 v = i;
01211 memcpy(data, &v, psize);
01212 }
01213 else if (cls->asInt32Class() || cls->asEnumClass()) {
01214 psize = sizeof(eyedblib::int32);
01215 eyedblib::int32 v;
01216 if (i >= INT_MAX)
01217 v = INT_MAX;
01218 else if (i <= INT_MIN)
01219 v = INT_MIN;
01220 else
01221 v = (eyedblib::int32)i;
01222 memcpy(data, &v, psize);
01223 }
01224 else if (cls->asInt16Class()) {
01225 psize = sizeof(eyedblib::int16);
01226 eyedblib::int16 v;
01227 if (i >= SHRT_MAX)
01228 v = SHRT_MAX;
01229 else if (i <= SHRT_MIN)
01230 v = SHRT_MIN;
01231 else
01232 v = (eyedblib::int16)i;
01233
01234 memcpy(data, &v, psize);
01235 }
01236 else
01237 psize = ~0;
01238
01239 if (size < psize)
01240 return oqml_False;
01241
01242 *val = 0;
01243 len = 1;
01244 size = psize;
01245
01246 return oqml_True;
01247 }
01248
01249 int oqmlAtom_int::getSize() const
01250 {
01251 return sizeof(eyedblib::int64);
01252 }
01253
01254 oqmlBool oqmlAtom_bool::getData(unsigned char data[], Data *val,
01255 Size &size, int &len,
01256 const Class *) const
01257 {
01258 if (size < sizeof(oqmlBool))
01259 return oqml_False;
01260
01261 *val = 0;
01262 size = sizeof(oqmlBool);
01263 len = 1;
01264 memcpy(data, &b, size);
01265 return oqml_True;
01266 }
01267
01268 int oqmlAtom_bool::getSize() const
01269 {
01270 return sizeof(oqmlBool);
01271 }
01272
01273 oqmlBool oqmlAtom_nil::getData(unsigned char data[], Data *val,
01274 Size &size, int &len,
01275 const Class *) const
01276 {
01277 *val = 0;
01278 memset(data, 0, size);
01279 len = 1;
01280 return oqml_True;
01281 }
01282
01283 int oqmlAtom_nil::getSize() const
01284 {
01285 return 0;
01286 }
01287
01288 oqmlBool oqmlAtom_null::getData(unsigned char data[], Data *val,
01289 Size &size, int &len,
01290 const Class *) const
01291 {
01292 *val = 0;
01293 memset(data, 0, size);
01294 len = 1;
01295 return oqml_True;
01296 }
01297
01298 int oqmlAtom_null::getSize() const
01299 {
01300 return 0;
01301 }
01302
01303 oqmlBool oqmlAtom_double::getData(unsigned char data[], Data *val,
01304 Size &size, int &len,
01305 const Class *) const
01306 {
01307 if (size < sizeof(double))
01308 return oqml_False;
01309
01310 *val = 0;
01311 size = sizeof(double);
01312 len = 1;
01313 memcpy(data, &d, size);
01314 return oqml_True;
01315 }
01316
01317 int oqmlAtom_double::getSize() const
01318 {
01319 return sizeof(double);
01320 }
01321
01322 oqmlBool oqmlAtom_char::getData(unsigned char data[], Data *val,
01323 Size &size, int &len,
01324 const Class *) const
01325 {
01326 if (size < sizeof(char))
01327 return oqml_False;
01328
01329 *val = 0;
01330 size = sizeof(char);
01331 len = 1;
01332 memcpy(data, &c, size);
01333 return oqml_True;
01334 }
01335
01336 int oqmlAtom_char::getSize() const
01337 {
01338 return sizeof(char);
01339 }
01340
01341 oqmlBool oqmlAtom_string::getData(unsigned char data[], Data *val,
01342 Size &size, int &len,
01343 const Class *) const
01344 {
01345 size = strlen(shstr->s) + 1;
01346 len = strlen(shstr->s) + 1;
01347 *val = (Data)shstr->s;
01348 return oqml_True;
01349 }
01350
01351 int oqmlAtom_string::getSize() const
01352 {
01353 return strlen(shstr->s)+1;
01354 }
01355
01356 oqmlStatus *
01357 oqmlAtom_string::setAtom(oqmlAtom *a, int idx, oqmlNode *node)
01358 {
01359 if (!a->as_char())
01360 return new oqmlStatus(node, "invalid right "
01361 "operand: character expected, got "
01362 "%s.", a->type.getString());
01363
01364 assert (idx >= 0 && idx < strlen(shstr->s));
01365 shstr->s[idx] = a->as_char()->c;
01366 return oqmlSuccess;
01367 }
01368
01369 oqmlBool oqmlAtom_ident::getData(unsigned char data[], Data *val,
01370 Size &size, int &len,
01371 const Class *) const
01372 {
01373 size = strlen(shstr->s);
01374 len = strlen(shstr->s);
01375 *val = (Data)shstr->s;
01376 return oqml_True;
01377 }
01378
01379 int oqmlAtom_ident::getSize() const
01380 {
01381 return strlen(shstr->s)+1;
01382 }
01383
01384 oqmlBool
01385 oqmlAtom_oid::getData(unsigned char data[], Data *val, Size &size,
01386 int &len, const Class *) const
01387 {
01388 if (size < sizeof(Oid))
01389 return oqml_False;
01390
01391 *val = 0;
01392 size = sizeof(Oid);
01393 len = 1;
01394 memcpy(data, &oid, size);
01395 return oqml_True;
01396 }
01397
01398 int oqmlAtom_oid::getSize() const
01399 {
01400 return sizeof(Oid);
01401 }
01402
01403 oqmlBool
01404 oqmlAtom_obj::getData(unsigned char data[], Data *val, Size &size,
01405 int &len, const Class *) const
01406 {
01407 size = sizeof(Object *);
01408 len = 1;
01409 size = sizeof(Object *);
01410 *val = 0;
01411 memcpy(data, &o, size);
01412 return oqml_True;
01413 }
01414
01415 int oqmlAtom_obj::getSize() const
01416 {
01417 return sizeof(Object *);
01418 }
01419
01420 oqmlBool oqmlAtom_coll::getData(unsigned char data[], Data *val,
01421 Size &size, int &len,
01422 const Class *) const
01423 {
01424 *val = 0;
01425 return oqml_False;
01426 }
01427
01428 int oqmlAtom_coll::getSize() const
01429 {
01430 return 0;
01431 }
01432
01433 oqmlStatus *
01434 oqmlAtom_coll::setAtom(oqmlAtom *a, int idx, oqmlNode *node)
01435 {
01436 assert (idx >= 0 && idx < list->cnt);
01437 oqmlStatus *s = list->setAtom((a ? a->copy() : 0), idx, node);
01438 if (!s && as_set())
01439 suppressDoubles();
01440 return s;
01441 }
01442
01443 oqmlAtom_coll *
01444 oqmlAtom_coll::suppressDoubles()
01445 {
01446 if (!list->cnt)
01447 return this;
01448
01449 list->suppressDoubles();
01450 return this;
01451 }
01452
01453 #ifdef NEW_SUPPRESS_DOUBLES
01454 struct oqmlAtom_x {
01455 oqmlAtom_x(oqmlAtom *a) : a(a) {}
01456 oqmlAtom *a;
01457 };
01458
01459 struct less_atom {
01460 bool operator() (const oqmlAtom_x& x, const oqmlAtom_x& y) const {
01461 return strcmp(x.a->getString(), y.a->getString()) < 0;
01462 }
01463 };
01464 #endif
01465
01466 void
01467 oqmlAtomList::suppressDoubles()
01468 {
01469 #ifdef NEW_SUPPRESS_DOUBLES
01470 std::set<oqmlAtom_x, less_atom> set;
01471
01472 oqmlAtom *a = first;
01473 while (a) {
01474 set.insert(a);
01475 a = a->next;
01476 }
01477
01478 if (set.size() == cnt)
01479 return;
01480
01481 first = last = 0;
01482 cnt = 0;
01483 std::set<oqmlAtom_x, less_atom>::iterator begin = set.begin();
01484 std::set<oqmlAtom_x, less_atom>::iterator end = set.end();
01485 while (begin != end) {
01486 append((*begin).a, false);
01487 ++begin;
01488 }
01489 #else
01490 int n, i, j;
01491 oqmlBool noDoubles = oqml_True;
01492 oqmlAtom **arr = new oqmlAtom*[cnt];
01493 oqmlAtom *a = first;
01494
01495 n = 0;
01496 while (a) {
01497 arr[n++] = a;
01498 a = a->next;
01499 }
01500
01501 for (i = 0; i < cnt; i++)
01502 for (j = 0; j < i; j++)
01503 if (arr[j] && arr[i] && arr[j]->isEqualTo(*arr[i])) {
01504 arr[i] = 0;
01505 noDoubles = oqml_False;
01506 }
01507
01508 if (noDoubles) {
01509 delete [] arr;
01510 return;
01511 }
01512
01513 first = last = 0;
01514 int xcnt = cnt;
01515 cnt = 0;
01516
01517 for (i = 0; i < xcnt; i++)
01518 if (arr[i])
01519 append(arr[i], false);
01520
01521 delete [] arr;
01522 #endif
01523 }
01524
01525
01526
01527
01528
01529
01530
01531 static oqmlBool
01532 checkNull(oqmlAtom *aleft, oqmlAtom *aright, oqmlTYPE type)
01533 {
01534 if (aleft->type.type == oqmlATOM_NULL) {
01535 if (aright->type.type == oqmlATOM_OID) {
01536 if (!((oqmlAtom_oid *)aright)->oid.isValid())
01537 return (type == oqmlEQUAL ? oqml_True : oqml_False);
01538 return (type == oqmlEQUAL ? oqml_False : oqml_True);
01539 }
01540
01541 if (aright->type.type == oqmlATOM_NULL)
01542 return (type == oqmlEQUAL ? oqml_True : oqml_False);
01543
01544 return (type == oqmlEQUAL ? oqml_False : oqml_True);
01545 }
01546
01547 return checkNull(aright, aleft, type);
01548 }
01549
01550 static oqmlBool
01551 compare_double_int(oqmlAtom *a_int, oqmlAtom *a_double, oqmlTYPE type)
01552 {
01553 unsigned char data[16];
01554 Size size;
01555 int len;
01556 Data val;
01557 size = sizeof(data);
01558
01559 if (a_int->getData(data, &val, size, len)) {
01560 eyedblib::int64 i;
01561 memcpy(&i, data, sizeof(eyedblib::int64));
01562 double d = (double)i;
01563 memcpy(data, &d, sizeof(double));
01564 return a_double->compare(data, sizeof(double), False, type);
01565 }
01566 return oqml_False;
01567 }
01568
01569 static oqmlBool
01570 compare_atoms(oqmlAtom *aleft, oqmlAtom *aright, oqmlTYPE type)
01571 {
01572 if (type == oqmlEQUAL)
01573 return aleft->isEqualTo(*aright);
01574
01575 unsigned char data[32];
01576 Size size;
01577 int len;
01578 Data val;
01579 size = sizeof(data);
01580
01581 if (aleft->getData(data, &val, size, len))
01582 return aright->compare((val ? val : data), size, False, type);
01583
01584 return oqml_False;
01585 }
01586
01587 oqmlStatus *
01588 oqmlAtomList::compare(oqmlNode *node, oqmlContext *ctx, oqmlAtomList *al,
01589 const char *opstr, oqmlTYPE type, oqmlBool &b) const
01590 {
01591 oqmlStatus *s;
01592
01593 if (type == oqmlDIFF) {
01594 s = compare(node, ctx, al, opstr, oqmlEQUAL, b);
01595 if (!s) b = (oqmlBool)!b;
01596 return s;
01597 }
01598
01599 if (al->cnt != cnt && type == oqmlEQUAL) {
01600 b = oqml_False;
01601 return oqmlSuccess;
01602 }
01603
01604 oqmlAtom *aleft = first, *aright = al->first;
01605 if (!aleft && !aright) {
01606 b = oqml_True;
01607 return oqmlSuccess;
01608 }
01609 else if (!aleft || !aright) {
01610 b = oqml_False;
01611 return oqmlSuccess;
01612 }
01613
01614 oqmlATOMTYPE left_type = aleft->type.type;
01615 oqmlATOMTYPE right_type = aright->type.type;
01616
01617 if (left_type == oqmlATOM_RANGE)
01618 left_type = aleft->as_range()->from->type.type;
01619
01620 if (right_type == oqmlATOM_RANGE)
01621 right_type = aright->as_range()->from->type.type;
01622
01623 for (int i = 0; i < cnt && i < al->cnt; i++) {
01624 if (left_type == oqmlATOM_NIL &&
01625 right_type == oqmlATOM_NIL) {
01626 b = ((type == oqmlEQUAL || type == oqmlINFEQ || type == oqmlSUPEQ) ?
01627 oqml_True : oqml_False);
01628 if (!b)
01629 return oqmlSuccess;
01630 }
01631 else if (left_type == oqmlATOM_NULL ||
01632 right_type == oqmlATOM_NULL) {
01633 b = checkNull(aleft, aright, type);
01634 if (!b)
01635 return oqmlSuccess;
01636 }
01637 else if (OQML_IS_SET(aleft) || OQML_IS_BAG(aleft)) {
01638 extern oqmlStatus *
01639 oqml_set_compare(oqmlNode *node, oqmlTYPE type, const char *,
01640 oqmlAtom *aleft, oqmlAtom *aright, oqmlBool &b);
01641 s = oqml_set_compare(node, type, opstr, aleft, aright, b);
01642 if (s || !b)
01643 return s;
01644 }
01645 else if (left_type != right_type) {
01646 if (left_type == oqmlATOM_DOUBLE &&
01647 right_type == oqmlATOM_INT) {
01648 if (type == oqmlSUPEQ)
01649 type = oqmlINFEQ;
01650 else if (type == oqmlSUP)
01651 type = oqmlINF;
01652 else if (type == oqmlINFEQ)
01653 type = oqmlSUPEQ;
01654 else if (type == oqmlINF)
01655 type = oqmlSUP;
01656
01657 b = compare_double_int(aright, aleft, type);
01658 if (!b)
01659 return oqmlSuccess;
01660 }
01661
01662 else if (right_type == oqmlATOM_DOUBLE &&
01663 left_type == oqmlATOM_INT) {
01664 b = compare_double_int(aleft, aright, type);
01665 if (!b)
01666 return oqmlSuccess;
01667 }
01668 #define TRUSS_JOIN
01669 #define JOIN_TRACE
01670 else if (ctx->isWhereContext() &&
01671 (OQML_IS_COLL(aleft) || OQML_IS_COLL(aright))) {
01672
01673
01674
01675 b = oqml_False;
01676 if (OQML_IS_COLL(aleft)) {
01677 oqmlAtom *left = OQML_ATOM_COLLVAL(aleft)->first;
01678 while (left) {
01679 if (compare_atoms(left, aright, type)) {
01680 b = oqml_True;
01681 break;
01682 }
01683 left = left->next;
01684 }
01685
01686 }
01687 else {
01688 oqmlAtom *right = OQML_ATOM_COLLVAL(aright)->first;
01689 while (right) {
01690 if (compare_atoms(right, aleft, type)) {
01691 b = oqml_True;
01692 break;
01693 }
01694 right = right->next;
01695 }
01696 }
01697
01698 if (!b)
01699 return oqmlSuccess;
01700 }
01701 else {
01702 if (type == oqmlEQUAL) {
01703 b = oqml_False;
01704 return oqmlSuccess;
01705 }
01706
01707 if (type != oqmlDIFF)
01708 return new oqmlStatus(node,
01709 "operation '%s %s %s' is not valid",
01710 aleft->type.getString(), opstr,
01711 aright->type.getString());
01712 }
01713 }
01714 else if (OQML_IS_LIST(aleft) || OQML_IS_ARRAY(aleft)) {
01715 oqmlTYPE xtype;
01716 if (type == oqmlSUP) xtype = oqmlSUPEQ;
01717 else if (type == oqmlINF) xtype = oqmlINFEQ;
01718 else xtype = type;
01719
01720 if (left_type != right_type && type == oqmlDIFF) {
01721 b = oqml_True; return oqmlSuccess;
01722 }
01723
01724 if (left_type != right_type && type == oqmlEQUAL) {
01725 b = oqml_False; return oqmlSuccess;
01726 }
01727
01728 s = OQML_ATOM_COLLVAL(aleft)->
01729 compare(node, ctx, OQML_ATOM_COLLVAL(aright), opstr, xtype, b);
01730
01731 if (s || !b)
01732 return s;
01733
01734 if (type == oqmlSUP || type == oqmlINF) {
01735 s = OQML_ATOM_COLLVAL(aleft)->
01736 compare(node, ctx, OQML_ATOM_COLLVAL(aright), opstr, oqmlDIFF, b);
01737
01738 if (s || !b)
01739 return s;
01740 }
01741 }
01742 else if (!compare_atoms(aleft, aright, type)) {
01743 b = oqml_False;
01744 return oqmlSuccess;
01745 }
01746
01747 aleft = aleft->next;
01748 aright = aright->next;
01749 }
01750
01751 if (al->cnt != cnt) {
01752 int c = al->cnt < cnt;
01753 int d = (type == oqmlSUP || type == oqmlSUPEQ);
01754
01755 if ((c && d) || (!c && !d)) {
01756 b = oqml_True;
01757 return oqmlSuccess;
01758 }
01759
01760 b = oqml_False;
01761 return oqmlSuccess;
01762 }
01763
01764 b = oqml_True;
01765 return oqmlSuccess;
01766 }
01767
01768 oqmlStatus *
01769 invalidBinop(oqmlNode *node, const char *opstr, const oqmlAtomType *at_left,
01770 const oqmlAtomType *at_right)
01771 {
01772 return new oqmlStatus(node,
01773 "operation '%s %s %s' is not valid.",
01774 at_left->getString(), opstr, at_right->getString());
01775 }
01776
01777
01778
01779
01780
01781 oqmlStatus *
01782 oqmlNode::binopCompile(Database *db, oqmlContext *ctx,
01783 const char *opstr, oqmlNode *qleft,
01784 oqmlNode *qright, oqmlAtomType &_eval_type,
01785 oqmlBinopType binopType,
01786 oqmlBool &iscts)
01787 {
01788
01789 oqmlStatus *s;
01790 oqmlAtomType at_left, at_right;
01791 oqmlBool cstleft, cstright;
01792
01793 s = qleft->compile(db, ctx);
01794 if (s)
01795 return s;
01796
01797 qleft->evalType(db, ctx, &at_left);
01798
01799 cstleft = qleft->isConstant();
01800 s = qright->compile(db, ctx);
01801 if (s)
01802 return s;
01803
01804 qright->evalType(db, ctx, &at_right);
01805
01806 cstright = qright->isConstant();
01807
01808 oqmlATOMTYPE type = at_left.type;
01809
01810 _eval_type.type = oqmlATOM_UNKNOWN_TYPE;
01811
01812 if (type != oqmlATOM_UNKNOWN_TYPE &&
01813 at_right.type != oqmlATOM_UNKNOWN_TYPE &&
01814 type != oqmlATOM_IDENT && at_right.type != oqmlATOM_IDENT) {
01815 if (!(binopType & oqmlDoubleOK) &&
01816 (type == oqmlATOM_DOUBLE || at_right.type == oqmlATOM_DOUBLE))
01817 return invalidBinop(this, opstr, &at_left, &at_right);
01818
01819 if (!(binopType & oqmlConcatOK) &&
01820 (type == oqmlATOM_STRING || at_right.type == oqmlATOM_STRING ||
01821 type == oqmlATOM_LIST || at_right.type == oqmlATOM_LIST ||
01822 type == oqmlATOM_SET || at_right.type == oqmlATOM_SET ||
01823 type == oqmlATOM_BAG || at_right.type == oqmlATOM_BAG ||
01824 type == oqmlATOM_ARRAY || at_right.type == oqmlATOM_ARRAY))
01825 return invalidBinop(this, opstr, &at_left, &at_right);
01826
01827 if (type == oqmlATOM_INT && at_right.type == oqmlATOM_DOUBLE) {
01828 _eval_type = at_right;
01829 iscts = OQMLBOOL(cstleft && cstright);
01830 return oqmlSuccess;
01831 }
01832 else if (type == oqmlATOM_DOUBLE &&
01833 (at_right.type == oqmlATOM_INT ||
01834 at_right.type == oqmlATOM_CHAR)) {
01835 _eval_type = at_left;
01836 iscts = OQMLBOOL(cstleft && cstright);
01837 return oqmlSuccess;
01838 }
01839 else if (at_right.type == oqmlATOM_DOUBLE &&
01840 (type == oqmlATOM_INT ||
01841 type == oqmlATOM_CHAR)) {
01842 _eval_type = at_right;
01843 iscts = OQMLBOOL(cstleft && cstright);
01844 return oqmlSuccess;
01845 }
01846 else if (type == oqmlATOM_INT && at_right.type == oqmlATOM_CHAR) {
01847 _eval_type = at_left;
01848 iscts = OQMLBOOL(cstleft && cstright);
01849 return oqmlSuccess;
01850 }
01851 else if (at_right.type == oqmlATOM_INT && type == oqmlATOM_CHAR) {
01852 _eval_type = at_right;
01853 iscts = OQMLBOOL(cstleft && cstright);
01854 return oqmlSuccess;
01855 }
01856
01857 else if (type != oqmlATOM_INT && type != oqmlATOM_CHAR &&
01858 type != oqmlATOM_DOUBLE &&
01859 type != oqmlATOM_STRING &&
01860 type != oqmlATOM_LIST &&
01861 type != oqmlATOM_BAG &&
01862 type != oqmlATOM_SET &&
01863 type != oqmlATOM_ARRAY)
01864 return invalidBinop(this, opstr, &at_left, &at_right);
01865 _eval_type = at_left;
01866 }
01867
01868 iscts = OQMLBOOL(cstleft && cstright);
01869 return oqmlSuccess;
01870 }
01871
01872 oqmlStatus *
01873 oqmlNode::binopEval(Database *db, oqmlContext *ctx, const char *opstr,
01874 const oqmlAtomType &_eval_type,
01875 oqmlNode *qleft, oqmlNode *qright, oqmlBinopType binopType,
01876 oqmlAtomList **al_left, oqmlAtomList **al_right)
01877 {
01878
01879 oqmlStatus *s;
01880 oqmlBool cstleft, cstright;
01881
01882 s = qleft->eval(db, ctx, al_left);
01883 if (s)
01884 return s;
01885
01886 s = qright->eval(db, ctx, al_right);
01887 if (s)
01888 return s;
01889
01890
01891
01892
01893
01894
01895 if (!(*al_left)->cnt) (*al_left)->append(new oqmlAtom_nil());
01896 if (!(*al_right)->cnt) (*al_right)->append(new oqmlAtom_nil());
01897
01898 oqmlAtom *aleft = (*al_left)->first, *aright = (*al_right)->first;
01899
01900 if (!(binopType & oqmlDoubleOK) &&
01901 (aleft->type.type == oqmlATOM_DOUBLE ||
01902 aright->type.type == oqmlATOM_DOUBLE))
01903 return invalidBinop(this, opstr, &aleft->type, &aright->type);
01904
01905 if (!(binopType & oqmlConcatOK) &&
01906 (aleft->type.type == oqmlATOM_STRING ||
01907 aright->type.type == oqmlATOM_STRING ||
01908 OQML_IS_COLL(aleft) ||
01909 OQML_IS_COLL(aright)))
01910 return invalidBinop(this, opstr, &aleft->type, &aright->type);
01911
01912 if ((binopType & oqmlConcatOK) &&
01913 (OQML_IS_COLL(aleft) || OQML_IS_COLL(aright)))
01914 return oqmlSuccess;
01915
01916 if ((aleft->type.type == oqmlATOM_INT &&
01917 aright->type.type == oqmlATOM_INT) ||
01918 (aleft->type.type == oqmlATOM_DOUBLE &&
01919 aright->type.type == oqmlATOM_DOUBLE) ||
01920 (aleft->type.type == oqmlATOM_CHAR &&
01921 aright->type.type == oqmlATOM_CHAR) ||
01922 (aleft->type.type == oqmlATOM_STRING &&
01923 aright->type.type == oqmlATOM_STRING) ||
01924 (OQML_IS_COLL(aleft) &&
01925 OQML_IS_COLL(aright)))
01926 return oqmlSuccess;
01927
01928
01929 if (OQML_IS_INT(aleft) && OQML_IS_DOUBLE(aright)) {
01930 (*al_left)->setAtom(new oqmlAtom_double(OQML_ATOM_INTVAL(aleft)), 0, this);
01931 return oqmlSuccess;
01932 }
01933
01934 if (OQML_IS_DOUBLE(aleft) && OQML_IS_INT(aright)) {
01935 (*al_right)->setAtom(new oqmlAtom_double(OQML_ATOM_INTVAL(aright)), 0, this);
01936 return oqmlSuccess;
01937 }
01938
01939
01940 if (OQML_IS_DOUBLE(aleft) && OQML_IS_CHAR(aright)) {
01941 (*al_right)->setAtom(new oqmlAtom_double(OQML_ATOM_CHARVAL(aright)), 0, this);
01942 return oqmlSuccess;
01943 }
01944
01945 if (OQML_IS_CHAR(aleft) && OQML_IS_DOUBLE(aright)) {
01946 (*al_left)->setAtom(new oqmlAtom_double(OQML_ATOM_CHARVAL(aleft)), 0, this);
01947 return oqmlSuccess;
01948 }
01949
01950
01951 if (OQML_IS_INT(aleft) && OQML_IS_CHAR(aright)) {
01952 (*al_right)->setAtom(new oqmlAtom_int(OQML_ATOM_CHARVAL(aright)), 0, this);
01953 return oqmlSuccess;
01954 }
01955
01956 if (OQML_IS_CHAR(aleft) && OQML_IS_INT(aright)) {
01957 (*al_left)->setAtom(new oqmlAtom_int(OQML_ATOM_CHARVAL(aleft)), 0, this);
01958 return oqmlSuccess;
01959 }
01960
01961 return invalidBinop(this, opstr, &aleft->type, &aright->type);
01962 }
01963
01964 void
01965 oqmlNode::swap(oqmlComp *comp, oqmlNode *&qleft, oqmlNode *&qright)
01966 {
01967 oqmlTYPE comp_type = comp->getType();
01968 oqmlNode *tql = qleft;
01969 qleft = qright;
01970 qright = tql;
01971
01972
01973 if (comp_type == oqmlSUP) comp->requalifyType(oqmlINF);
01974 else if (comp_type == oqmlSUPEQ) comp->requalifyType(oqmlINFEQ);
01975 else if (comp_type == oqmlINF) comp->requalifyType(oqmlSUP);
01976 else if (comp_type == oqmlINFEQ) comp->requalifyType(oqmlSUPEQ);
01977 }
01978
01979 oqmlStatus *
01980 oqmlNode::compCompile(Database *db, oqmlContext *ctx, const char *opstr,
01981 oqmlNode *&qleft, oqmlNode *&qright,
01982 oqmlComp *comp, oqmlAtom **cst_atom,
01983 oqmlAtomType *_eval_type)
01984 {
01985 oqmlStatus *s;
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996 comp->evalDone = oqml_False;
01997 comp->needReinit = oqml_False;
01998
01999 s = qleft->compile(db, ctx);
02000 if (s) return s;
02001
02002 s = qright->compile(db, ctx);
02003 if (s) return s;
02004
02005 if (!qleft->asDot() && qright->asDot())
02006 swap(comp, qleft, qright);
02007
02008 oqmlSelect *sel = ctx->getHiddenSelectContext();
02009 if (sel) {
02010
02011
02012
02013
02014
02015 if (sel->usesFromIdent(qright) && !sel->usesFromIdent(qleft))
02016 swap(comp, qleft, qright);
02017 }
02018
02019 oqmlAtomType at_right;
02020 qright->evalType(db, ctx, &at_right);
02021
02022 oqmlAtomType at;
02023 qleft->evalType(db, ctx, &at);
02024
02025 if (at.type != oqmlATOM_UNKNOWN_TYPE &&
02026 at_right.type != oqmlATOM_UNKNOWN_TYPE && !at.cmp(at_right, True)) {
02027
02028
02029
02030
02031 if (comp->getType() != oqmlEQUAL && comp->getType() != oqmlDIFF &&
02032 comp->getType() != oqmlBETWEEN &&
02033 comp->getType() != oqmlNOTBETWEEN)
02034 return new oqmlStatus(this, "operation '%s %s %s' "
02035 "is not valid",
02036 at.getString(), opstr, at_right.getString());
02037 }
02038
02039 if (qleft->asDot()) {
02040 oqmlDot *dot = (oqmlDot *)qleft;
02041
02042 if (dot->boolean_dot)
02043 _eval_type->type = oqmlATOM_BOOL;
02044 else {
02045 if (ctx->isSelectContext()) {
02046 _eval_type->type = oqmlATOM_OID;
02047 oqmlDotContext *dot_ctx = qleft->asDot()->getDotContext();
02048 _eval_type->cls = (dot_ctx ? (Class *)dot_ctx->desc[0].cls : 0);
02049 }
02050 else
02051 _eval_type->type = oqmlATOM_UNKNOWN_TYPE;
02052 }
02053 }
02054 else
02055 _eval_type->type = oqmlATOM_BOOL;
02056
02057 *cst_atom = 0;
02058
02059 return oqmlSuccess;
02060 }
02061
02062 static void
02063 oqml_append_realize(oqmlAtomList *alist, oqmlAtomList *list)
02064 {
02065 oqmlAtom *a = alist->first;
02066
02067 if (a->as_coll())
02068 a = a->as_coll()->list->first;
02069
02070 while (a) {
02071 oqmlAtom *next = a->next;
02072 list->append(a);
02073 a = next;
02074 }
02075 }
02076
02077 oqmlStatus *
02078 oqmlNode::compEval(Database *db, oqmlContext *ctx, const char *opstr,
02079 oqmlNode *qleft, oqmlNode *qright,
02080 oqmlAtomList **alist, oqmlComp *comp, oqmlAtom *cst_atom)
02081 {
02082 oqmlStatus *s;
02083
02084 if (!ctx->isSelectContext()) {
02085 oqmlAtomList *al_left = 0, *al_right = 0;
02086
02087 if (comp->evalDone) {
02088 *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
02089 return oqmlSuccess;
02090 }
02091
02092 if (comp->needReinit) {
02093 s = comp->reinit(db, ctx);
02094 if (s) return s;
02095 comp->needReinit = oqml_False;
02096 }
02097
02098 s = qleft->eval(db, ctx, &al_left);
02099 if (s) return s;
02100
02101 s = qright->eval(db, ctx, &al_right);
02102 if (s) return s;
02103
02104 s = comp->compare(db, ctx, al_left, al_right, alist);
02105 #ifdef SYNC_GARB
02106 OQL_DELETE(al_left);
02107 OQL_DELETE(al_right);
02108 #endif
02109 return s;
02110 }
02111
02112 oqmlBool done;
02113 unsigned int cnt;
02114 return comp->preEvalSelectRealize(db, ctx, 0, done, alist, oqml_True);
02115 }
02116
02117 oqmlBool
02118 oqmlComp::hasDotIdent(const char *_ident)
02119 {
02120
02121 if (qleft->asDot() && qright->asDot())
02122 return OQMLBOOL(qleft->hasIdent(_ident) || qright->hasIdent(_ident));
02123
02124 if (qleft->asDot())
02125 return qleft->hasIdent(_ident);
02126
02127
02128 if (qright->asDot())
02129 return qright->hasIdent(_ident);
02130
02131 return oqml_False;
02132 }
02133
02134 oqmlStatus *
02135 oqmlComp::reinit(Database *db, oqmlContext *ctx)
02136 {
02137 assert(qleft->asDot());
02138 oqmlStatus *s = qleft->asDot()->reinit(db, ctx);
02139 if (s) return s;
02140
02141 if (qright->asDot()) {
02142 s = qright->asDot()->reinit(db, ctx);
02143 return s;
02144 }
02145
02146 return oqmlSuccess;
02147 }
02148
02149 oqmlStatus *
02150 oqmlComp::preEvalSelect(Database *db, oqmlContext *ctx,
02151 const char *ident, oqmlBool &done,
02152 unsigned int &cnt, oqmlBool firstPass)
02153 {
02154
02155
02156 if (hasDotIdent(ident)) {
02157 oqmlAtomList *al;
02158 oqmlStatus *s = preEvalSelectRealize(db, ctx, ident, done, &al,
02159 firstPass);
02160 if (s) return s;
02161 cnt = (al && al->first &&
02162 al->first->as_coll() ?
02163 al->first->as_coll()->list->cnt : 0);
02164
02165 return firstPass ? reinit(db, ctx) : oqmlSuccess;
02166 }
02167
02168 done = oqml_False;
02169 cnt = 0;
02170 return oqmlSuccess;
02171 }
02172
02173 oqmlStatus *
02174 oqmlComp::optimize(Database *db, oqmlContext *ctx)
02175 {
02176 oqmlBool idx_right = oqml_False, idx_left = oqml_False;
02177 oqmlStatus *s;
02178
02179 if (qleft->asDot()) {
02180 s = qleft->asDot()->hasIndex(db, ctx, idx_left);
02181 if (s) return s;
02182 }
02183
02184 if (qright->asDot()) {
02185 s = qright->asDot()->hasIndex(db, ctx, idx_right);
02186 if (s) return s;
02187 }
02188
02189 if (idx_left)
02190 qleft->asDot()->setIndexHint(ctx, oqml_True);
02191
02192 if (idx_right)
02193 qright->asDot()->setIndexHint(ctx, oqml_True);
02194
02195 if (idx_right && !idx_left)
02196 swap(this, qleft, qright);
02197
02198 return oqmlSuccess;
02199 }
02200
02201 oqmlStatus *
02202 oqmlComp::preEvalSelectRealize(Database *db, oqmlContext *ctx,
02203 const char *ident, oqmlBool &done,
02204 oqmlAtomList **alist,
02205 oqmlBool firstPass)
02206 {
02207 assert(ctx->isSelectContext());
02208
02209 #if 0
02210 oqmlAtom *xx = 0;
02211 if (ident && ctx->getSymbol(ident, 0, &xx) && xx)
02212 printf("preEvalSelectRealize symbol %s is of type %s [%s]\n",
02213 ident, xx->type.getString(), (const char *)xx->getString());
02214 #endif
02215 oqmlStatus *s;
02216
02217
02218
02219 if (!needReinit && ctx->getSelectContext()->usesFromIdent(qright)) {
02220 if (firstPass) {
02221 s = optimize(db, ctx);
02222 if (s) return s;
02223
02224 *alist = new oqmlAtomList();
02225 done = oqml_False;
02226 return oqmlSuccess;
02227 }
02228
02229 s = reinit(db, ctx);
02230 if (s) return s;
02231 needReinit = oqml_True;
02232 }
02233
02234 oqmlAtomList *al;
02235 oqmlAtomList *al_left = 0;
02236
02237 oqmlNode *qright_x, *qleft_x;
02238
02239 if (ident && qright->hasIdent(ident)) {
02240 qleft_x = qright;
02241 qright_x = qleft;
02242 }
02243 else {
02244 qleft_x = qleft;
02245 qright_x = qright;
02246 }
02247
02248 s = qright_x->eval(db, ctx, &al);
02249 if (s) return s;
02250 cst_atom = al->first;
02251 #ifdef SYNC_GARB
02252 if (al && !al->refcnt) {
02253 al->first = 0;
02254 OQL_DELETE(al);
02255 }
02256 #endif
02257 s = complete(db, ctx, cst_atom);
02258 if (s) return s;
02259 s = qleft_x->eval(db, ctx, &al_left, this, cst_atom);
02260 if (s) return s;
02261 #ifdef SYNC_GARB
02262 if (al_left && !al_left->refcnt) {
02263 al_left->first = 0;
02264 OQL_DELETE(al_left);
02265 }
02266 #endif
02267
02268 if (iter) {
02269 s = iter->eval(this, ctx, alist);
02270 if (s) return s;
02271
02272 if (ctx->isOverMaxAtoms())
02273 return oqmlSuccess;
02274
02275 if (qleft_x->asDot()) {
02276 s = qleft_x->asDot()->populate(db, ctx, *alist,
02277 OQMLBOOL(!firstPass));
02278
02279 if (s) return s;
02280 }
02281
02282
02283 if (firstPass)
02284 evalDone = oqml_True;
02285 done = oqml_True;
02286 return oqmlSuccess;
02287 }
02288
02289
02290
02291 return new oqmlStatus(this, "invalid comparison");
02292 }
02293
02294 oqmlStatus *
02295 oqmlComp::estimate(Database *, oqmlContext *, unsigned int &r)
02296 {
02297 r = oqml_ESTIM_MAX;
02298 return oqmlSuccess;
02299 }
02300
02301 oqmlStatus *
02302 estimate_realize(Database *db, oqmlContext *ctx, oqmlNode *qleft,
02303 unsigned int r0, unsigned int &r)
02304 {
02305
02306 if (qleft->asDot()) {
02307 oqmlBool hasOne;
02308 oqmlStatus *s = qleft->asDot()->hasIndex(db, ctx, hasOne);
02309 if (s) return s;
02310
02311 if (hasOne) {
02312 r = r0;
02313 return oqmlSuccess;
02314 }
02315 }
02316
02317 r = oqml_ESTIM_MAX;
02318 return oqmlSuccess;
02319 }
02320
02321
02322
02323 oqmlStatus *
02324 oqmlInf::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02325 {
02326 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02327 }
02328
02329 oqmlStatus *
02330 oqmlInfEq::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02331 {
02332 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02333 }
02334
02335 oqmlStatus *
02336 oqmlSup::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02337 {
02338 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02339 }
02340
02341 oqmlStatus *
02342 oqmlSupEq::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02343 {
02344 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02345 }
02346
02347 oqmlStatus *
02348 oqmlDiff::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02349 {
02350 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02351 }
02352
02353 oqmlStatus *
02354 oqmlRegex::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02355 {
02356 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02357 }
02358
02359 oqmlStatus *
02360 oqmlEqual::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02361 {
02362
02363
02364
02365
02366
02367 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIN, r);
02368 }
02369
02370 oqmlStatus *
02371 oqmlBetween::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02372 {
02373 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIN, r);
02374 }
02375
02376 oqmlStatus *
02377 oqmlNotBetween::estimate(Database *db, oqmlContext *ctx, unsigned int &r)
02378 {
02379 return estimate_realize(db, ctx, qleft, oqml_ESTIM_MIDDLE, r);
02380 }
02381
02382 oqmlStatus *
02383 oqmlComp::compare(Database *, oqmlContext *ctx, oqmlAtomList *al_left,
02384 oqmlAtomList *al_right, oqmlAtomList **alist)
02385 {
02386 oqmlBool b;
02387 oqmlStatus *s = al_left->compare(this, ctx, al_right, opstr, type, b);
02388
02389 if (s) return s;
02390
02391 if (b) {
02392 *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
02393 return oqmlSuccess;
02394 }
02395
02396 *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_False));
02397 return oqmlSuccess;
02398 }
02399
02400 void
02401 oqmlComp::lock()
02402 {
02403 oqmlNode::lock();
02404 if (qleft) qleft->lock();
02405 if (qright) qright->lock();
02406 }
02407
02408 void
02409 oqmlComp::unlock()
02410 {
02411 oqmlNode::unlock();
02412 if (qleft) qleft->unlock();
02413 if (qright) qright->unlock();
02414 }
02415
02416 oqmlStatus *
02417 oqmlNode::requalify(Database *, oqmlContext *, const char *ident, oqmlNode *node, oqmlBool &done)
02418 {
02419 return new oqmlStatus(this, "cannot requalify node for ident '%s', "
02420 "node '%s'", ident, node->toString().c_str());
02421 }
02422
02423 oqmlStatus *
02424 oqmlNode::requalify_back(Database *, oqmlContext *)
02425 {
02426 return new oqmlStatus(this, "cannot requalify back node '%s'",
02427 toString().c_str());
02428 }
02429
02430 oqmlStatus *
02431 oqmlNode::requalify(Database *, oqmlContext *, const Attribute **attrs, int attr_cnt,
02432 const char *ident)
02433 {
02434 return new oqmlStatus(this, "cannot requalify node for ident '%s'",
02435 ident);
02436 }
02437
02438 oqmlStatus *
02439 oqmlNode::requalify_node(Database *db, oqmlContext *ctx,
02440 oqmlNode *&ql, const char *ident, oqmlNode *node,
02441 oqmlBool &done)
02442 {
02443 if (!ql)
02444 return oqmlSuccess;
02445
02446
02447
02448
02449
02450
02451 if (ql->asIdent()) {
02452 if (!strcmp(ql->asIdent()->getName(), ident)) {
02453 done = oqml_True;
02454 node->back = ql;
02455 ql = node;
02456 if (isLocked())
02457 ql->lock();
02458 }
02459
02460 return oqmlSuccess;
02461 }
02462
02463 ql->back = ql;
02464
02465 if (ql->asDot()) {
02466 const char *dotident = ql->asDot()->getLeftIdent();
02467 if (dotident && !strcmp(dotident, ident))
02468 ql->asDot()->replaceLeftIdent(ident, node, done);
02469 return oqmlSuccess;
02470 }
02471
02472 return ql->requalify(db, ctx, ident, node, done);
02473 }
02474
02475 oqmlStatus *
02476 oqmlNode::requalify_node_back(Database *db, oqmlContext *ctx,
02477 oqmlNode *&ql)
02478 {
02479
02480
02481
02482
02483
02484
02485 if (!ql || !ql->back)
02486 return oqmlSuccess;
02487
02488 ql = ql->back;
02489
02490 if (ql->asIdent())
02491 return oqmlSuccess;
02492
02493 return ql->requalify_back(db, ctx);
02494 }
02495
02496 oqmlStatus *
02497 oqmlNode::requalify_node(Database *db, oqmlContext *ctx,
02498 oqmlNode *&ql, const Attribute **attrs,
02499 int attr_cnt, const char *ident)
02500 {
02501 if (!ql)
02502 return oqmlSuccess;
02503
02504 const char *xident = 0;
02505
02506 if (ql->asIdent())
02507 xident = ql->asIdent()->getName();
02508 else if (ql->asDot())
02509 xident = ql->asDot()->getLeftIdent();
02510 else
02511 return ql->requalify(db, ctx, attrs, attr_cnt, ident);
02512
02513 if (xident)
02514 for (int i = 0; i < attr_cnt; i++)
02515 if (!strcmp(xident, attrs[i]->getName())) {
02516 ql = new oqmlDot(new oqmlIdent(ident), ql, oqml_False);
02517 if (isLocked()) ql->lock();
02518 return oqmlSuccess;
02519 }
02520
02521 return oqmlSuccess;
02522 }
02523
02524 std::string
02525 oqmlComp::toString(void) const
02526 {
02527 return oqml_binop_string(qleft, qright, opstr, is_statement);
02528 }
02529
02530
02531
02532 void
02533 oqmlLock(oqmlAtomList *l, oqmlBool lock, oqmlBool rm)
02534 {
02535 if (!l || l->recurs)
02536 return;
02537
02538 l->recurs = oqml_True;
02539 bool donotdel = false;
02540
02541 #ifdef LOCK_TRACE
02542 printf("oqmlLock list(%p, %d) -> ", l, lock);
02543 #endif
02544 if (lock)
02545 l->refcnt++;
02546 else {
02547 if (l->refcnt > 0)
02548 l->refcnt--;
02549 else
02550 donotdel = true;
02551 }
02552
02553 #ifdef LOCK_TRACE
02554 printf("refcnt=%d\n", l->refcnt);
02555 #endif
02556
02557 oqmlAtom *a = l->first;
02558 while (a) {
02559 oqmlLock(a, lock, oqml_False);
02560 a = a->next;
02561 }
02562
02563 l->recurs = oqml_False;
02564
02565
02566 if (!donotdel) {
02567 if (!lock && rm && !l->refcnt) {
02568
02569 delete l;
02570
02571 }
02572 }
02573 }
02574
02575 void
02576 oqmlLock(oqmlAtom *a, oqmlBool lock, oqmlBool rm)
02577 {
02578 if (!a || a->recurs)
02579 return;
02580
02581 bool donotdel = false;
02582
02583 a->recurs = oqml_True;
02584
02585 #ifdef LOCK_TRACE
02586 printf("oqmlLock atom(%p, %d) -> ", a, lock);
02587 #endif
02588 if (lock)
02589 a->refcnt++;
02590 else {
02591 if (a->refcnt > 0)
02592 a->refcnt--;
02593 else
02594 donotdel = true;
02595 }
02596
02597 #ifdef LOCK_TRACE
02598 printf("refcnt=%d\n", a->refcnt);
02599 #endif
02600
02601 if (OQML_IS_COLL(a))
02602 oqmlLock(OQML_ATOM_COLLVAL(a), lock,
02603
02604 oqml_False);
02605 else if (OQML_IS_IDENT(a) && a->as_ident()->entry)
02606 oqmlLock(a->as_ident()->entry->at, lock,
02607
02608 oqml_False);
02609 else if (OQML_IS_STRUCT(a)) {
02610 oqmlAtom_struct *sa = a->as_struct();
02611 for (int i = 0; i < sa->attr_cnt; i++)
02612 oqmlLock(sa->attr[i].value, lock,
02613
02614 oqml_False);
02615 }
02616
02617 a->recurs = oqml_False;
02618
02619
02620 if (!donotdel) {
02621 if (!lock && rm && !a->refcnt) {
02622
02623 delete a;
02624 }
02625 }
02626 }
02627
02628 const char oqml_global_scope[] = "::";
02629 const int oqml_global_scope_len = strlen(oqml_global_scope);
02630
02631 static oqmlBool
02632 oqml_is_global_ident(const char *ident)
02633 {
02634 return !strncmp(ident, oqml_global_scope, oqml_global_scope_len) ?
02635 oqml_True : oqml_False;
02636 }
02637
02638 static oqmlAtomType st_atom_type;
02639
02640 oqmlSymbolEntry::oqmlSymbolEntry(oqmlContext *ctx, const char *_ident,
02641 oqmlAtomType *_type,
02642 oqmlAtom *_at, oqmlBool _global,
02643 oqmlBool _system)
02644 {
02645 at = 0;
02646 ident = strdup(_ident);
02647 global = _global;
02648 level = global ? 0 : ctx->getLocalDepth();
02649 set(_type, _at, oqml_True);
02650 prev = next = 0;
02651 system = _system;
02652 if (global && oqml_is_global_ident(ident))
02653 oqml_append(OQML_ATOM_COLLVAL(oqml_variables), ident);
02654
02655 if (!global && ctx->getLocalTable())
02656 ctx->getLocalTable()->insertObjectLast(this);
02657
02658 list = new oqmlAtomList();
02659 oqmlLock(list, oqml_True);
02660
02661 popped = oqml_False;
02662 }
02663
02664
02665
02666
02667 #ifdef SYNC_SYM_GARB
02668 static void a2vect(oqmlAtom *a, std::vector<oqmlAtom *> &v)
02669 {
02670 if (OQML_IS_COLL(a)) {
02671 oqmlAtom *ta = OQML_ATOM_COLLVAL(a)->first;
02672 while (ta) {
02673 oqmlAtom *next = ta->next;
02674 a2vect(ta, v);
02675 ta = next;
02676 }
02677 }
02678 else
02679 v.push_back(a);
02680 }
02681
02682 static void checkAutoAssign(oqmlAtom *at1, oqmlAtom *at2)
02683 {
02684 if (!at1 || !at2)
02685 return;
02686
02687 if (!OQML_IS_COLL(at1) || !OQML_IS_COLL(at2))
02688 return;
02689
02690 std::vector<oqmlAtom *> v1;
02691 std::vector<oqmlAtom *> v2;
02692 a2vect(at1, v1);
02693 a2vect(at2, v2);
02694
02695 std::vector<oqmlAtom *>::iterator b1 = v1.begin();
02696 std::vector<oqmlAtom *>::iterator e1 = v1.end();
02697 while (b1 != e1) {
02698 std::vector<oqmlAtom *>::iterator b2 = v2.begin();
02699 std::vector<oqmlAtom *>::iterator e2 = v2.end();
02700 bool found = false;
02701 while (b2 != e2) {
02702 if ((*b1) == (*b2)) {
02703 assert(!found);
02704 oqmlLock(*b1, oqml_True, oqml_False);
02705 found = true;
02706
02707 }
02708 ++b2;
02709 }
02710 ++b1;
02711 }
02712 }
02713 #endif
02714
02715 #ifdef SYNC_SYM_GARB_1
02716 static bool possibleAutoAssign(oqmlAtom *at1, oqmlAtom *at2)
02717 {
02718 return at1 && at2 && ((OQML_IS_COLL(at1) && OQML_IS_COLL(at2)) ||
02719 at1 == at2);
02720 }
02721 #endif
02722
02723 void oqmlSymbolEntry::set(oqmlAtomType *_type, oqmlAtom *_at, oqmlBool force,
02724 oqmlBool tofree)
02725 {
02726 #ifdef SYMB_TRACE
02727 printf("setting symbol '%s' to %p, [old=%p] force %d\n",
02728 ident, _at, at, force);
02729 #endif
02730
02731 type = (_type ? *_type : st_atom_type);
02732 if (_at || force) {
02733 #ifdef SYNC_SYM_GARB_1
02734 if (at) {
02735 if (tofree && possibleAutoAssign(_at, at))
02736 tofree = oqml_False;
02737 oqmlLock(at, oqml_False, tofree);
02738 }
02739
02740 #elif defined(SYNC_SYM_GARB)
02741 if (at) {
02742 if (tofree)
02743 checkAutoAssign(_at, at);
02744 oqmlLock(at, oqml_False, tofree);
02745 }
02746 #else
02747 if (at) {
02748 oqmlLock(at, oqml_False);
02749 }
02750 #endif
02751 at = _at;
02752 oqmlLock(at, oqml_True);
02753 }
02754 }
02755
02756 void oqmlSymbolEntry::addEntry(oqmlAtom_ident *x)
02757 {
02758 list->append(x);
02759 }
02760
02761 void oqmlSymbolEntry::releaseEntries()
02762 {
02763 oqmlAtom *x = list->first;
02764 while(x) {
02765 x->as_ident()->releaseEntry();
02766 x = x->next;
02767 }
02768 }
02769
02770 oqmlSymbolEntry::~oqmlSymbolEntry()
02771 {
02772 #ifdef SYMB_TRACE
02773 printf("deleting entry %s %p\n", ident, this);
02774 #endif
02775 if (global && oqml_is_global_ident(ident))
02776 oqml_suppress(OQML_ATOM_COLLVAL(oqml_variables), ident);
02777 releaseEntries();
02778
02779 oqmlLock(list, oqml_False);
02780
02781 #ifdef SYNC_GARB
02782 OQL_DELETE(list);
02783 #endif
02784
02785 oqmlLock(at, oqml_False);
02786 free(ident);
02787 }
02788
02789 oqmlContext::oqmlContext(oqmlSymbolTable *_symtab)
02790 {
02791 symtab = (_symtab ? _symtab : &stsymtab);
02792 dot_ctx = 0;
02793 and_list_ctx = 0;
02794 select_ctx_cnt = 0;
02795 hidden_select_ctx_cnt = 0;
02796 and_ctx = 0;
02797 or_ctx = 0;
02798 preval_ctx = 0;
02799 where_ctx = 0;
02800 lastTempSymb = 0;
02801 overMaxAtoms = oqml_False;
02802 maxatoms = oqml_INFINITE;
02803 oneatom = oqml_False;
02804 arg_level = 0;
02805 local_cnt = 0;
02806 local_alloc = 0;
02807 locals = 0;
02808 is_popping = oqml_False;
02809 cpatom_cnt = 0;
02810 for (int n = 0; n < OQML_MAX_CPS; n++)
02811 cpatoms[n] = 0;
02812 }
02813
02814
02815
02816
02817
02818
02819
02820 oqmlStatus *
02821 oqmlContext::pushLocalTable()
02822 {
02823 #if defined(SYMB_TRACE) || defined(LOCAL_TRACE)
02824 printf("pushLocalTable(level=#%d)\n", local_cnt);
02825 #endif
02826 if (local_cnt >= local_alloc) {
02827 local_alloc += 64;
02828 locals = (LinkedList **)
02829 realloc(locals, local_alloc * sizeof(LinkedList *));
02830 }
02831
02832 locals[local_cnt++] = new LinkedList();
02833 return oqmlSuccess;
02834 }
02835
02836 oqmlStatus *
02837 oqmlContext::popLocalTable()
02838 {
02839 assert(local_cnt > 0);
02840
02841 LinkedListCursor c(locals[local_cnt-1]);
02842 oqmlSymbolEntry *symb;
02843 oqmlStatus *s;
02844
02845 #if defined(SYMB_TRACE) || defined(LOCAL_TRACE)
02846 printf("popLocalTable(level=#%d) starting\n", local_cnt-1);
02847 #endif
02848 is_popping = oqml_True;
02849 while (c.getNext((void *&)symb)) {
02850 assert(!symb->global);
02851 if (symb->popped)
02852 delete symb;
02853 else if (symb->ident) {
02854 s = popSymbolRealize(symb->ident, oqml_False);
02855 if (s) return s;
02856 }
02857 }
02858
02859 is_popping = oqml_False;
02860 #if defined(SYMB_TRACE) || defined(LOCAL_TRACE)
02861 printf("popLocalTable(level=#%d) ending\n", local_cnt-1);
02862 #endif
02863 delete locals[local_cnt-1];
02864 local_cnt--;
02865 return oqmlSuccess;
02866 }
02867
02868 oqmlStatus *
02869 oqmlContext::setSymbolRealize(const char *ident, oqmlAtomType *type,
02870 oqmlAtom *at, oqmlBool global,
02871 oqmlBool system, oqmlBool tofree)
02872 {
02873 oqmlSymbolEntry *s = (global ? symtab->sfirst : symtab->slast);
02874
02875 #ifdef SYMB_TRACE
02876 printf("setSymbolRealize(\"%s\", %s, level=#%d)\n", ident,
02877 (global ? "global" : "local"), local_cnt-1);
02878 #endif
02879
02880
02881
02882 while (s) {
02883
02884
02885
02886
02887
02888 if (!strcmp(s->ident, ident) &&
02889 (s->global ||
02890 (!global && !s->global && s->level == local_cnt))) {
02891 if (s->system && !system)
02892 return new oqmlStatus("'%s' is a system variable: "
02893 "it cannot be modified.", ident);
02894
02895 s->set(type, at, oqml_True, tofree);
02896
02897 return oqmlSuccess;
02898 }
02899
02900 s = (global ? s->next : s->prev);
02901 }
02902
02903 return pushSymbolRealize(ident, type, at, global, system);
02904 }
02905
02906 #ifdef SYMB_TRACE
02907 void oqml_stop_here() { }
02908 #endif
02909
02910 oqmlStatus *
02911 oqmlContext::pushSymbolRealize(const char *ident, oqmlAtomType *type,
02912 oqmlAtom *at, oqmlBool global,
02913 oqmlBool system)
02914 {
02915 #ifdef SYMB_TRACE
02916 printf("pushSymbolRealize(\"%s\", %s, type=%d:%d, value=%s, level=#%d)\n",
02917 ident,
02918 (global ? "global" : "local"), (type ? type->type : -1),
02919 (at ? at->type.type : -1), (at ? at->getString() : "<nil>"),
02920 local_cnt-1);
02921 if (at && OQML_IS_OID(at) && OQML_ATOM_OIDVAL(at).getDbid() == 572)
02922 oqml_stop_here();
02923 #endif
02924 oqmlSymbolEntry *s = new oqmlSymbolEntry(this, ident, type, at, global, system);
02925
02926 if (symtab->slast) {
02927 symtab->slast->next = s;
02928 s->prev = symtab->slast;
02929 symtab->slast = s;
02930 }
02931 else
02932 symtab->slast = symtab->sfirst = s;
02933
02934 return oqmlSuccess;
02935 }
02936
02937 oqmlStatus *
02938 oqmlContext::popSymbolRealize(const char *ident, oqmlBool global)
02939 {
02940 oqmlSymbolEntry *s = symtab->slast;
02941
02942 #ifdef SYMB_TRACE
02943 printf("popSymbolRealize(\"%s\", %s, level=#%d, %p)\n", ident,
02944 (global ? "global" : "local"), local_cnt-1, this);
02945 #endif
02946
02947 while (s) {
02948 if (!strcmp(s->ident, ident) && s->global == global &&
02949 (s->global || s->level == local_cnt)) {
02950 #ifdef SYNC_SYM_GARB_2
02951 oqmlLock(s->at, oqml_False, oqml_True);
02952 s->at = 0;
02953 #endif
02954 if (s->prev)
02955 s->prev->next = s->next;
02956 if (s->next)
02957 s->next->prev = s->prev;
02958
02959 if (s == symtab->slast)
02960 symtab->slast = s->prev;
02961 if (s == symtab->sfirst)
02962 symtab->sfirst = s->next;
02963
02964 if (getLocalTable() && !is_popping)
02965 s->popped = oqml_True;
02966 else
02967 delete s;
02968 return oqmlSuccess;
02969 }
02970 s = s->prev;
02971 }
02972
02973 assert(0);
02974 return new oqmlStatus(oqml_uninit_fmt, ident);
02975 }
02976
02977
02978
02979
02980
02981
02982
02983 oqmlStatus *
02984 oqmlContext::setSymbol(const char *ident, oqmlAtomType *type, oqmlAtom *at,
02985 oqmlBool global, oqmlBool system)
02986 {
02987 oqmlBool tofree = oqml_True;
02988 if (global) {
02989 oqmlStatus *s;
02990 if (oqml_is_global_ident(ident)) {
02991 s = setSymbolRealize(&ident[oqml_global_scope_len], type, at,
02992 oqml_True, system, oqml_True);
02993 if (s) return s;
02994 tofree = oqml_False;
02995 }
02996 else if (!getLocalTable()) {
02997 s = setSymbolRealize((std::string(oqml_global_scope) + ident).c_str(), type, at,
02998 oqml_True, system, oqml_True);
02999 if (s) return s;
03000 tofree = oqml_False;
03001 }
03002 else
03003 global = oqml_False;
03004 }
03005
03006 return setSymbolRealize(ident, type, at, global, system, oqml_True);
03007 }
03008
03009 oqmlStatus *
03010 oqmlContext::pushSymbol(const char *ident, oqmlAtomType *type, oqmlAtom *at,
03011 oqmlBool global, oqmlBool system)
03012 {
03013 if (global) {
03014 oqmlStatus *s;
03015 if (oqml_is_global_ident(ident)) {
03016 s = pushSymbolRealize(&ident[oqml_global_scope_len], type, at,
03017 oqml_True, system);
03018 if (s) return s;
03019 }
03020 else if (!getLocalTable()) {
03021 s = pushSymbolRealize((std::string(oqml_global_scope) + ident).c_str(), type, at,
03022 oqml_True, system);
03023 if (s) return s;
03024 }
03025 else
03026 global = oqml_False;
03027 }
03028
03029 return pushSymbolRealize(ident, type, at, global, system);
03030 }
03031
03032 oqmlStatus *
03033 oqmlContext::popSymbol(const char *ident, oqmlBool global)
03034 {
03035 if (global) {
03036 oqmlStatus *s;
03037 if (oqml_is_global_ident(ident)) {
03038 s = popSymbolRealize(&ident[oqml_global_scope_len], oqml_True);
03039 if (s) return s;
03040 }
03041 else if (!getLocalTable()) {
03042 s = popSymbolRealize((std::string(oqml_global_scope) + ident).c_str(),
03043 oqml_True);
03044 if (s) return s;
03045 }
03046 else
03047 global = oqml_False;
03048 }
03049
03050 return popSymbolRealize(ident, global);
03051 }
03052
03053 oqmlBool
03054 oqmlContext::getSymbol(const char *ident, oqmlAtomType *type, oqmlAtom **at,
03055 oqmlBool *global, oqmlBool *system)
03056 {
03057 oqmlSymbolEntry *s = getSymbolEntry(ident);
03058
03059 if (!s)
03060 return oqml_False;
03061
03062 if (type)
03063 *type = s->type;
03064 if (at)
03065 *at = s->at;
03066 if (global)
03067 *global = s->global;
03068
03069 return oqml_True;
03070 }
03071
03072 oqmlSymbolEntry *
03073 oqmlContext::getSymbolEntry(const char *ident)
03074 {
03075 #ifdef SYMB_TRACE
03076 printf("getSymbol(%s arg_level %d local_cnt %d)\n",
03077 ident, arg_level, local_cnt);
03078 #endif
03079 oqmlSymbolEntry *s = symtab->slast;
03080
03081 while (s) {
03082 #ifdef SYMB_TRACE
03083 printf("s->ident %s global %d level %d\n",
03084 s->ident, s->global, s->level);
03085 #endif
03086 if (!strcmp(s->ident, ident) &&
03087 (s->global || s->level == local_cnt ||
03088 (arg_level && s->level < local_cnt))) {
03089 #ifdef SYMB_TRACE
03090 printf("symbol %s found\n", ident);
03091 #endif
03092 return s;
03093 }
03094
03095 s = s->prev;
03096 }
03097
03098 #ifdef SYMB_TRACE
03099 printf("symbol %s *not* found\n", ident);
03100 #endif
03101 return 0;
03102 }
03103
03104 void
03105 oqmlContext::displaySymbols()
03106 {
03107 oqmlSymbolEntry *s = symtab->slast;
03108
03109 while (s) {
03110 printf("%s [%d, value=%s, %s]\n",
03111 s->ident, s->type.type, (s->at ? s->at->getString() : ""),
03112 s->global ? "global" : "local");
03113 s = s->prev;
03114 }
03115 }
03116
03117 void oqmlContext::setDotContext(oqmlDotContext *pc)
03118 {
03119 dot_ctx = pc;
03120 }
03121
03122 oqmlDotContext *oqmlContext::getDotContext()
03123 {
03124 return dot_ctx;
03125 }
03126
03127 void oqmlContext::setAndContext(oqmlAtomList *al)
03128 {
03129 and_list_ctx = al;
03130 }
03131
03132 oqmlAtomList *oqmlContext::getAndContext()
03133 {
03134 return and_list_ctx;
03135 }
03136
03137 std::string
03138 oqmlContext::makeTempSymb(int idx)
03139 {
03140 return std::string("__oqml__tmp__var__") + str_convert((long long)idx) + "__";
03141 }
03142
03143 std::string
03144 oqmlContext::getTempSymb()
03145 {
03146 return makeTempSymb(lastTempSymb++);
03147 }
03148
03149
03150
03151 void
03152 oqmlContext::incrSelectContext(oqmlSelect *select)
03153 {
03154 assert(select_ctx_cnt < sizeof(select_ctx)/sizeof(select_ctx[0]));
03155 select_ctx[select_ctx_cnt++] = select;
03156 }
03157
03158 void
03159 oqmlContext::decrSelectContext()
03160 {
03161 assert(select_ctx_cnt > 0);
03162 select_ctx_cnt--;
03163 }
03164
03165 void
03166 oqmlContext::incrHiddenSelectContext(oqmlSelect *select)
03167 {
03168 assert(hidden_select_ctx_cnt < sizeof(hidden_select_ctx)/sizeof(hidden_select_ctx[0]));
03169 hidden_select_ctx[hidden_select_ctx_cnt++] = select;
03170 }
03171
03172 void
03173 oqmlContext::decrHiddenSelectContext()
03174 {
03175 assert(hidden_select_ctx_cnt > 0);
03176 hidden_select_ctx_cnt--;
03177 }
03178
03179 oqmlStatus *
03180 oqmlContext::pushCPAtom(oqmlNode *node, oqmlAtom *a)
03181 {
03182 if (cpatom_cnt >= OQML_MAX_CPS)
03183 return new oqmlStatus(node, "maximum joins (%d) exceeded", OQML_MAX_CPS);
03184
03185 cpatoms[cpatom_cnt++] = a;
03186 return oqmlSuccess;
03187 }
03188
03189 oqmlStatus *
03190 oqmlContext::popCPAtom(oqmlNode *node)
03191 {
03192 if (!cpatom_cnt)
03193 return new oqmlStatus(node, "internal error: cannot pop joins");
03194 cpatom_cnt--;
03195 return oqmlSuccess;
03196 }
03197
03198 oqmlContext::~oqmlContext()
03199 {
03200 for (int i = 0; i < lastTempSymb; i++)
03201 popSymbol(makeTempSymb(i).c_str());
03202
03203 for (int j = 0; j < local_cnt; j++)
03204 delete locals[j];
03205
03206 free(locals);
03207 }
03208
03209 oqmlAtom *
03210 oqmlAtomList::getAtom(unsigned int idx)
03211 {
03212 oqmlAtom *a = first;
03213
03214 for (int _cnt = 0; _cnt < idx && a; _cnt++)
03215 a = a->next;
03216
03217 return a;
03218 }
03219
03220 static oqmlStatus *
03221 checkRecursion(oqmlNode *node, oqmlAtomList *list, oqmlAtomList *this_list)
03222 {
03223 if (list == this_list)
03224 return new oqmlStatus(node, "invalid recursive assignation in list.");
03225
03226 oqmlStatus *s;
03227 oqmlAtom *a = list->first;
03228 while (a) {
03229 if (a->as_list() && (s = checkRecursion(node, a->as_list()->list, this_list)))
03230 return s;
03231 a = a->next;
03232 }
03233
03234 return oqmlSuccess;
03235 }
03236
03237 static oqmlBool
03238 set_atom(oqmlAtom *olda, oqmlAtom *newa)
03239 {
03240 if (olda == newa)
03241 return oqml_True;
03242
03243 if (olda) {
03244 for (int i = 0; i < olda->refcnt; i++)
03245 oqmlLock(newa, oqml_True);
03246
03247 oqmlLock(olda, oqml_False);
03248 }
03249
03250 return oqml_False;
03251 }
03252
03253 oqmlStatus *
03254 oqmlAtomList::setAtom(oqmlAtom *ia, int idx, oqmlNode *node)
03255 {
03256 if (ia && ia->as_list()) {
03257 oqmlStatus *s = checkRecursion(node, ia->as_list()->list, this);
03258 if (s) return s;
03259 }
03260
03261 if (idx == 0) {
03262 if (!ia) {
03263 if (last == first)
03264 last = first = first->next;
03265 else
03266 first = first->next;
03267 cnt--;
03268 return oqmlSuccess;
03269 }
03270
03271 if (set_atom(first, ia))
03272 return oqmlSuccess;
03273
03274 if (last == first)
03275 last = ia;
03276
03277 oqmlAtom *next = first->next;
03278 first = ia;
03279 ia->next = next;
03280 return oqmlSuccess;
03281 }
03282
03283 oqmlAtom *a = first;
03284 for (int i = 0; i < idx-1; i++)
03285 a = a->next;
03286
03287 oqmlAtom *next = a->next;
03288
03289 if (!ia) {
03290 if (last == next) {
03291 a->next = 0;
03292 last = a;
03293 }
03294 else
03295 a->next = next->next;
03296
03297 cnt--;
03298 return oqmlSuccess;
03299 }
03300
03301 if (set_atom(next, ia))
03302 return oqmlSuccess;
03303
03304 a->next = ia;
03305
03306 if (last == next) {
03307 ia->next = 0;
03308 last = ia;
03309 }
03310 else
03311 ia->next = next->next;
03312
03313 return oqmlSuccess;
03314 }
03315
03316 oqmlBool oqmlAtomList::isIn(oqmlAtom *x)
03317 {
03318
03319 oqmlAtom *a = first;
03320
03321 while (a) {
03322
03323
03324
03325
03326 if (a->isEqualTo(*x))
03327 return oqml_True;
03328 a = a->next;
03329 }
03330
03331 return oqml_False;
03332 }
03333
03334 oqmlStatus *oqmlAtomList::suppress(oqmlAtom *x)
03335 {
03336 const char *sx = x->getString();
03337 oqmlAtom *a = first, *prev = 0;
03338
03339 while (a) {
03340 if (!strcmp(sx, a->getString())) {
03341 if (prev)
03342 prev->next = a->next;
03343 else
03344 first = a->next;
03345
03346 if (a == last)
03347 last = prev;
03348
03349 return oqmlSuccess;
03350 }
03351
03352 prev = a;
03353 a = a->next;
03354 }
03355
03356 return new oqmlStatus("atom %s not found in list", x->getString());
03357 }
03358
03359 void oqmlAtomList::empty()
03360 {
03361 cnt = 0;
03362 first = last = 0;
03363 }
03364
03365 oqmlAtomList *
03366 oqmlAtomList::copy()
03367 {
03368 oqmlAtomList *list = new oqmlAtomList();
03369 oqmlAtom *a = first;
03370
03371 while (a) {
03372 if (a->as_coll())
03373 list->append(a->as_coll()->list->copy());
03374 else
03375 list->append(a->copy());
03376 a = a->next;
03377 }
03378
03379 return list;
03380 }
03381
03382 oqmlAtom **
03383 oqmlAtomList::toArray()
03384 {
03385 oqmlAtom **arr = new oqmlAtom*[cnt];
03386 oqmlAtom *a = first;
03387 int n = 0;
03388
03389 while(a) {
03390 arr[n++] = a;
03391 a = a->next;
03392 }
03393
03394 return arr;
03395 }
03396
03397
03398 #define NEW_AND_OIDS
03399
03400 oqmlAtomList *oqmlAtomList::andOids(oqmlAtomList *l1, oqmlAtomList *l2)
03401 {
03402 #ifdef NEW_AND_OIDS
03403 if (l1 && OQML_IS_COLL(l1->first))
03404 l1 = OQML_ATOM_COLLVAL(l1->first);
03405
03406 if (l2 && OQML_IS_COLL(l2->first))
03407 l2 = OQML_ATOM_COLLVAL(l2->first);
03408
03409 if (!l1) return l2;
03410 if (!l2) return l1;
03411
03412 oqmlAtom *aleft, *aright;
03413 oqmlAtomList *alist = new oqmlAtomList();
03414
03415 aleft = l1->first;
03416 while (aleft) {
03417 if (OQML_IS_OID(aleft)) {
03418 Oid oid = OQML_ATOM_OIDVAL(aleft);
03419 aright = l2->first;
03420 while (aright) {
03421 oqmlAtom *next = aright->next;
03422 if (OQML_IS_OID(aright))
03423 if (oid.compare(OQML_ATOM_OIDVAL(aright)))
03424 alist->append(aright);
03425 aright = next;
03426 }
03427 }
03428 aleft = aleft->next;
03429 }
03430
03431 return alist;
03432 #else
03433 if (!l1) return l2 ? OQML_ATOM_COLLVAL(l2->first) : 0;
03434 if (!l2) return OQML_ATOM_COLLVAL(l1->first);
03435
03436 oqmlAtomList *ll1 = OQML_ATOM_COLLVAL(l1->first);
03437 if (!ll1) return OQML_ATOM_COLLVAL(l2->first);
03438
03439 oqmlAtomList *ll2 = OQML_ATOM_COLLVAL(l2->first);
03440 if (!ll2) return ll1;
03441
03442 oqmlAtom *aleft, *aright;
03443 oqmlAtomList *alist = new oqmlAtomList();
03444
03445 aleft = ll1->first;
03446 while (aleft) {
03447 if (OQML_IS_OID(aleft)) {
03448 Oid oid = OQML_ATOM_OIDVAL(aleft);
03449 aright = ll2->first;
03450 while (aright) {
03451 oqmlAtom *next = aright->next;
03452 if (OQML_IS_OID(aright))
03453 if (oid.compare(OQML_ATOM_OIDVAL(aright)))
03454 alist->append(aright);
03455 aright = next;
03456 }
03457 }
03458 aleft = aleft->next;
03459 }
03460
03461 return alist;
03462 #endif
03463 }
03464
03465 oqmlNode *
03466 oqmlAtom_nil::toNode()
03467 {
03468 return new oqmlNil();
03469 }
03470
03471 oqmlNode *
03472 oqmlAtom_null::toNode()
03473 {
03474 return new oqmlNull();
03475 }
03476
03477 oqmlNode *
03478 oqmlAtom_bool::toNode()
03479 {
03480 if (b)
03481 return new oqmlTrue();
03482
03483 return new oqmlFalse();
03484 }
03485
03486 oqmlNode *
03487 oqmlAtom_oid::toNode()
03488 {
03489 return new oqmlOid(oid);
03490 }
03491
03492 oqmlNode *
03493 oqmlAtom_obj::toNode()
03494 {
03495 return new oqmlObject(o, idx);
03496 }
03497
03498 oqmlNode *
03499 oqmlAtom_int::toNode()
03500 {
03501 return new oqmlInt(i);
03502 }
03503
03504 oqmlNode *
03505 oqmlAtom_char::toNode()
03506 {
03507 return new oqmlChar(c);
03508 }
03509
03510 oqmlNode *
03511 oqmlAtom_double::toNode()
03512 {
03513 return new oqmlFloat(d);
03514 }
03515
03516 oqmlNode *
03517 oqmlAtom_string::toNode()
03518 {
03519 return new oqmlString(shstr->s);
03520 }
03521
03522 oqmlNode *
03523 oqmlAtom_ident::toNode()
03524 {
03525 return new oqmlIdent(shstr->s);
03526 }
03527
03528 static oqml_List *
03529 make_list(oqmlAtomList *list)
03530 {
03531 oqml_List *l = new oqml_List();
03532 oqmlAtom *a = list->first;
03533 while (a) {
03534 l->add(a->toNode());
03535 a = a->next;
03536 }
03537 return l;
03538 }
03539
03540 oqmlNode *
03541 oqmlAtom_list::toNode()
03542 {
03543 return new oqmlListColl(make_list(list));
03544 }
03545
03546 oqmlNode *
03547 oqmlAtom_bag::toNode()
03548 {
03549 return new oqmlBagColl(make_list(list));
03550 }
03551
03552 oqmlNode *
03553 oqmlAtom_set::toNode()
03554 {
03555 return new oqmlSetColl(make_list(list));
03556 }
03557
03558 oqmlNode *
03559 oqmlAtom_array::toNode()
03560 {
03561 return new oqmlArrayColl(make_list(list));
03562 }
03563
03564 oqmlNode *
03565 oqmlAtom_struct::toNode()
03566 {
03567 return 0;
03568 }
03569
03570 oqmlNode *
03571 oqmlAtom_node::toNode()
03572 {
03573 return node;
03574 }
03575
03576 oqmlNode *
03577 oqmlAtom_select::toNode()
03578 {
03579 return node;
03580 }
03581
03582 void
03583 oqmlAtom_select::setCP(oqmlContext *ctx)
03584 {
03585 cpcnt = ctx->getCPAtomCount();
03586 if (!cpcnt) return;
03587
03588 for (int i = 0; i < cpcnt; i++)
03589 if (!cplists[i]) cplists[i] = new oqmlAtomList();
03590
03591 oqmlAtom **cpatoms = ctx->getCPAtoms();
03592 oqmlAtomList *rlist = list;
03593 if (OQML_IS_COLL(rlist->first))
03594 rlist = OQML_ATOM_COLLVAL(rlist->first);
03595
03596 oqmlAtom *a = rlist->first;
03597 while (a) {
03598 for (int i = 0; i < cpcnt; i++)
03599 cplists[i]->append(cpatoms[i]->copy());
03600 a = a->next;
03601 }
03602 }
03603
03604 void
03605 oqmlAtom_select::appendCP(oqmlContext *ctx)
03606 {
03607 cpcnt = ctx->getCPAtomCount();
03608 if (!cpcnt) return;
03609
03610 oqmlAtom **cpatoms = ctx->getCPAtoms();
03611 for (int i = 0; i < cpcnt; i++) {
03612 if (!cplists[i]) cplists[i] = new oqmlAtomList();
03613 cplists[i]->append(cpatoms[i]->copy());
03614 }
03615 }
03616
03617
03618 oqmlAtom_range::oqmlAtom_range(oqmlAtom *_from, oqmlBool _from_incl,
03619 oqmlAtom *_to, oqmlBool _to_incl)
03620 {
03621 type.type = oqmlATOM_RANGE;
03622 type.cls = 0;
03623 from = _from;
03624 from_incl = _from_incl;
03625 to = _to;
03626 to_incl = _to_incl;
03627 assert(from->type.type == to->type.type);
03628 }
03629
03630 oqmlNode *
03631 oqmlAtom_range::toNode()
03632 {
03633 return new oqmlRange(from->toNode(), from_incl, to->toNode(), to_incl);
03634 }
03635
03636 char *
03637 oqmlAtom_range::makeString(FILE *fd) const
03638 {
03639 const char *sf = from_incl ? "[" : "]";
03640 const char *st = to_incl ? "]" : "[";
03641
03642 if (fd) {
03643 fprintf(fd, sf);
03644 from->makeString(fd);
03645 fprintf(fd, ",");
03646 to->makeString(fd);
03647 fprintf(fd, st);
03648 return 0;
03649 }
03650 else if (string)
03651 return string;
03652 else {
03653 const char *f = from->makeString(fd);
03654 const char *t = to->makeString(fd);
03655 char *buf = (char *)malloc(strlen(f) + strlen(t) + 4);
03656 sprintf(buf, "%s%s,%s%s", sf, f, t, st);
03657 ((oqmlAtom *)this)->string = buf;
03658 return string;
03659 }
03660 }
03661
03662 oqmlBool oqmlAtom_range::getData(unsigned char[], Data *val, Size&, int&,
03663 const Class *) const
03664 {
03665 assert(0);
03666 *val = 0;
03667 return oqml_False;
03668 }
03669
03670 int oqmlAtom_range::getSize() const
03671 {
03672 assert(0);
03673 return 0;
03674 }
03675
03676 oqmlAtom *oqmlAtom_range::copy()
03677 {
03678 return new oqmlAtom_range(from, from_incl, to, to_incl);
03679 }
03680
03681 oqmlBool oqmlAtom_range::compare(unsigned char *data, int len_data, Bool isnull, oqmlTYPE type) const
03682 {
03683 if (type == oqmlBETWEEN)
03684 return OQMLBOOL(from->compare(data, len_data, isnull,
03685 (from_incl ? oqmlSUPEQ : oqmlSUP)) &&
03686 to->compare(data, len_data, isnull,
03687 (to_incl ? oqmlINFEQ : oqmlINF)));
03688
03689 return OQMLBOOL(from->compare(data, len_data, isnull,
03690 (from_incl ? oqmlINF : oqmlINFEQ)) ||
03691 to->compare(data, len_data, isnull,
03692 (to_incl ? oqmlSUP : oqmlSUPEQ)));
03693 }
03694
03695 Value *oqmlAtom_range::toValue() const
03696 {
03697 return 0;
03698 }
03699
03700 oqmlAtom_list *oqml_variables;
03701 oqmlAtom_list *oqml_functions;
03702 oqmlAtom_string *oqml_status;
03703 #ifdef SUPPORT_OQLRESULT
03704 oqmlSymbolEntry *oqml_result_entry;
03705 #endif
03706 oqmlSymbolEntry *oqml_db_entry;
03707 oqmlBool oqml_auto_persist = oqml_True;
03708 OqlCtbDatabase *oqml_default_db;
03709
03710 void oqml_initialize()
03711 {
03712 oqml_variables = new oqmlAtom_list(new oqmlAtomList());
03713 oqmlContext ctx;
03714
03715 ctx.setSymbol("oql$variables", &oqml_variables->type,
03716 oqml_variables, oqml_True, oqml_True);
03717
03718 oqml_functions = new oqmlAtom_list(new oqmlAtomList());
03719 ctx.setSymbol("oql$functions", &oqml_functions->type,
03720 oqml_functions, oqml_True, oqml_True);
03721
03722 oqml_status = new oqmlAtom_string("");
03723 ctx.setSymbol("oql$status", &oqml_status->type,
03724 oqml_status, oqml_True, oqml_True);
03725
03726 #ifdef SUPPORT_OQLRESULT
03727 ctx.setSymbol("oql$result", 0, 0, oqml_True, oqml_True);
03728 oqml_result_entry = ctx.getSymbolEntry("oql$result");
03729 #endif
03730
03731 ctx.setSymbol("oql$db", 0, 0, oqml_True, oqml_True);
03732 oqml_db_entry = ctx.getSymbolEntry("oql$db");
03733
03734 oqmlAtom *x;
03735
03736 x = new oqmlAtom_int(oqml_ESTIM_MIN);
03737 ctx.setSymbol("oql$ESTIM_MIN", &x->type, x, oqml_True, oqml_True);
03738
03739 x = new oqmlAtom_int(oqml_ESTIM_MIDDLE);
03740 ctx.setSymbol("oql$ESTIM_MIDDLE", &x->type, x, oqml_True, oqml_True);
03741
03742 x = new oqmlAtom_int(oqml_ESTIM_MAX);
03743 ctx.setSymbol("oql$ESTIM_MAX", &x->type, x, oqml_True, oqml_True);
03744
03745 x = new oqmlAtom_string(oqmlLAnd::getDefaultRule());
03746 ctx.setSymbol("oql$default_and_rule", &x->type, x, oqml_True, oqml_True);
03747 }
03748
03749 static Database *curdb;
03750
03751 void oqml_reinit(Database *db)
03752 {
03753 if (curdb == db)
03754 curdb = 0;
03755 }
03756
03757 void oqml_initialize(Database *db)
03758 {
03759 if (!db)
03760 return;
03761
03762 if (!db->isOQLInit()) {
03763 Bool isInTrans = True;
03764 if (!db->isInTransaction()) {
03765 db->transactionBegin();
03766 isInTrans = False;
03767 }
03768
03769 db->setOQLInit();
03770 oqmlContext ctx;
03771 oqmlIdent::initEnumValues(db, &ctx);
03772 (void)OQL::initDatabase(db);
03773 if (!isInTrans)
03774 db->transactionAbort();
03775 }
03776
03777 if (curdb != db) {
03778 const Class *clsdb = db->getSchema()->getClass("database");
03779 if (clsdb) {
03780 OqlCtbDatabase *tdb;
03781
03782 if (!oqml_default_db) {
03783 tdb = new OqlCtbDatabase(db);
03784 tdb->setDbname(db->getName());
03785 tdb->setDbid(db->getDbid());
03786 tdb->setDbmdb(db->getDBMDB());
03787 tdb->xdb = db;
03788 db->setOQLInfo(tdb);
03789 }
03790 else
03791 tdb = oqml_default_db;
03792
03793 oqmlAtom *adb = oqmlObjectManager::registerObject(tdb);
03794 oqml_db_entry->set(&adb->type, adb, oqml_True);
03795 }
03796
03797 curdb = db;
03798 }
03799 }
03800
03801 void oqml_release()
03802 {
03803 }
03804
03805 oqmlBool
03806 oqml_suppress(oqmlAtomList *list, const char *ident)
03807 {
03808 oqmlAtom *prev = 0;
03809 oqmlAtom *r = list->first;
03810
03811 while (r) {
03812 if (r->as_ident() && !strcmp(OQML_ATOM_IDENTVAL(r), ident)) {
03813 if (!prev)
03814 list->first = r->next;
03815 else
03816 prev->next = r->next;
03817
03818 if (list->last == r)
03819 list->last = prev;
03820
03821
03822 oqmlLock(r, oqml_False);
03823 return oqml_True;
03824 }
03825
03826 prev = r;
03827 r = r->next;
03828 }
03829
03830 return oqml_False;
03831 }
03832
03833 void
03834 oqml_append(oqmlAtomList *list, const char *ident)
03835 {
03836 oqmlAtom *x = new oqmlAtom_ident(ident);
03837 oqmlLock(x, oqml_True);
03838 list->append(x);
03839 }
03840
03841 oqmlStatus *
03842 oqml_manage_postactions(Database *db, oqmlStatus *s, oqmlAtomList **alist)
03843 {
03844
03845
03846 if (s) return s;
03847
03848
03849
03850
03851
03852
03853
03854
03855
03856
03857 #if !defined(SUPPORT_OQLRESULT) && !defined(SUPPORT_POSTACTIONS)
03858
03859 return s;
03860 #endif
03861
03862 oqmlAtom *ra = s || !*alist ? 0 : (*alist)->first;
03863
03864
03865 #if 0
03866 if (!ra)
03867 oqmlLock(oqml_result_entry->at, oqml_False);
03868 #endif
03869
03870 #ifdef SUPPORT_OQLRESULT
03871 oqml_result_entry->set((ra ? &ra->type : 0), ra, oqml_True);
03872 #endif
03873
03874 #ifdef SUPPORT_POSTACTIONS
03875 oqmlBool global;
03876 oqmlAtom *action_list;
03877 oqmlContext ctx;
03878
03879 if (!ctx.getSymbol("oql$postactions", 0, &action_list, &global) || !global)
03880 return s;
03881
03882 if (!OQML_IS_LIST(action_list))
03883 return new oqmlStatus("postactions: list expected in oql$postactions, "
03884 "got %s.", action_list->type.getString());
03885
03886 oqmlAtomList *list = OQML_ATOM_LISTVAL(action_list);
03887 oqmlAtom *action = list->first;
03888 oqmlAtom_string *statstr = new oqmlAtom_string(s ? s->msg : "");
03889
03890 while (action) {
03891 oqmlAtom *next = action->next;
03892
03893 if (!OQML_IS_IDENT(action))
03894 return new oqmlStatus("postactions: ident expected in "
03895 "oql$postactions list, "
03896 "got %s.", action->type.getString());
03897
03898 oqmlStatus *rs;
03899 rs = oqml_realize_postaction(db, &ctx, OQML_ATOM_IDENTVAL(action),
03900 statstr, ra, alist);
03901 if (rs) return rs;
03902 action = next;
03903 }
03904
03905 #endif
03906 return oqmlSuccess;
03907 }
03908
03909 void
03910 oqmlObjectManager::addToFreeList(Object *o)
03911 {
03912 freeList.insertObjectFirst(o);
03913 }
03914
03915 void
03916 oqmlObjectManager::releaseObject(Object *o, oqmlBool inFreeList)
03917 {
03918 if (!o)
03919 return;
03920
03921 if (inFreeList)
03922 freeList.deleteObject(o);
03923 o->release();
03924 }
03925
03926 void
03927 oqmlObjectManager::garbageObjects()
03928 {
03929 LinkedListCursor c(freeList);
03930 Object *o;
03931
03932 while (c.getNext((void *&)o))
03933 o->release();
03934
03935
03936 freeList.empty();
03937 }
03938
03939 oqmlStatus *
03940 oqmlObjectManager::getObject(oqmlNode *node, Database *db,
03941 const Oid *oid, Object *&o,
03942 oqmlBool add_to_free_list,
03943 oqmlBool errorIfNull)
03944 {
03945 if (!oid->isValid()) {
03946 if (errorIfNull)
03947 return new oqmlStatus(node, "invalid null oid");
03948 o = 0;
03949 return oqmlSuccess;
03950 }
03951
03952 Status is = db->loadObject(oid, &o);
03953
03954 if (is)
03955 return new oqmlStatus(node, is);
03956
03957 if (add_to_free_list)
03958 addToFreeList(o);
03959 return oqmlSuccess;
03960 }
03961
03962 oqmlStatus *
03963 oqmlObjectManager::getObject(oqmlNode *node, Database *db,
03964 const Oid &oid, Object *&o,
03965 oqmlBool add_to_free_list,
03966 oqmlBool errorIfNull)
03967 {
03968 return getObject(node, db, &oid, o, add_to_free_list, errorIfNull);
03969 }
03970
03971 static Oid IDX2OID(pointer_int_t idx)
03972 {
03973 Oid oid;
03974 memcpy(&oid, &idx, sizeof(idx));
03975
03976 return oid;
03977 }
03978
03979 static Oid OBJ2OID(const Object *o)
03980 {
03981 Oid oid;
03982 memcpy(&oid, &o, sizeof(o));
03983
03984 return oid;
03985 }
03986
03987 oqmlStatus *
03988 oqmlObjectManager::getObject(oqmlNode *node, const char *s,
03989 Object *&o, pointer_int_t &idx)
03990 {
03991 if (sscanf(s, "%lx:obj", &idx) != 1)
03992 return new oqmlStatus(node, "invalid object format '%s'", s);
03993
03994 if (!idx) {
03995 o = 0;
03996 return oqmlSuccess;
03997 }
03998
03999 o = (Object *)objCacheIdx->getObject(IDX2OID(idx));
04000 if (!o)
04001 return new oqmlStatus(node, "invalid object '%s'", s);
04002 return oqmlSuccess;
04003 }
04004
04005 oqmlStatus *
04006 oqmlObjectManager::getIndex(oqmlNode *node, const Object *o,
04007 pointer_int_t &idx)
04008 {
04009 if (!o) {
04010 idx = 0;
04011 return oqmlSuccess;
04012 }
04013
04014 idx = (pointer_int_t)objCacheObj->getObject(OBJ2OID(o));
04015
04016 if (!idx)
04017 return new oqmlStatus(node, "invalid object '0x%lx:obj'", o);
04018
04019 return oqmlSuccess;
04020 }
04021
04022 oqmlStatus *oqmlAtom_obj::checkObject()
04023 {
04024 pointer_int_t i;
04025
04026 if (oqmlObjectManager::isRegistered(o, i)) {
04027
04028 return oqmlSuccess;
04029 }
04030
04031
04032 #if 0
04033 oqmlStatus *s = new oqmlStatus(0, "object released %lx -> set to null'", o);
04034 o = 0;
04035 return s;
04036 #else
04037
04038 o = 0;
04039 return oqmlSuccess;
04040 #endif
04041 }
04042
04043 oqmlBool
04044 oqmlObjectManager::isRegistered(const Object *o, pointer_int_t &idx)
04045 {
04046 if (!o)
04047 return oqml_True;
04048
04049 idx = (pointer_int_t)objCacheObj->getObject(OBJ2OID(o));
04050 return OQMLBOOL(idx);
04051 }
04052
04053 struct OnRelease : public gbxObject::OnRelease {
04054
04055 static OnRelease *instance;
04056
04057 static OnRelease *getInstance() {
04058 if (!instance)
04059 instance = new OnRelease();
04060 return instance;
04061 }
04062
04063 virtual void perform(gbxObject *o) {
04064 #ifdef GARB_TRACE_DETAIL
04065 printf("OQL releasing %p %s\n", o, ((Object *)o)->getOid().toString());
04066 #endif
04067 oqmlStatus *s = oqmlObjectManager::unregisterObject(0, (Object *)o, true);
04068 }
04069 };
04070
04071 OnRelease *OnRelease::instance;
04072
04073 oqmlAtom *
04074 oqmlObjectManager::registerObject(Object *o)
04075 {
04076 if (!o)
04077 return new oqmlAtom_obj(o, 0);
04078
04079 pointer_int_t idx = (pointer_int_t)objCacheObj->getObject(OBJ2OID(o), true);
04080 #ifdef GARB_TRACE_DETAIL
04081 std::cout << "REGISTER -> " << (void *)o << " " << idx << '\n';
04082 #endif
04083 if (idx) {
04084
04085 (void)objCacheIdx->getObject(IDX2OID(idx), true);
04086 return new oqmlAtom_obj(o, idx, o->getClass());
04087 }
04088
04089 static pointer_int_t stidx = 1000;
04090
04091 #ifdef GARB_TRACE_DETAIL
04092 std::cout << "REGISTER: " << (void *)o << " " << stidx << " " << OBJ2OID(o).getNX() << '\n';
04093 #endif
04094 objCacheIdx->insertObject(IDX2OID(stidx), o);
04095 objCacheObj->insertObject(OBJ2OID(o), (void *)stidx);
04096
04097 o->setOnRelease(OnRelease::getInstance());
04098
04099 return new oqmlAtom_obj(o, stidx++, o->getClass());
04100 }
04101
04102 oqmlStatus *
04103 oqmlObjectManager::unregisterObject(oqmlNode *node, Object *o, bool force)
04104 {
04105 if (!o)
04106 return oqmlSuccess;
04107
04108 static const char fmt1[] = "object '%p' is not registered #1";
04109 static const char fmt2[] = "object '%p' is not registered #2";
04110 static const char fmt3[] = "object '%p' is not registered #3";
04111 pointer_int_t idx = (pointer_int_t)objCacheObj->getObject(OBJ2OID(o));
04112
04113 #ifdef GARB_TRACE_DETAIL
04114 std::cout << "UNREGISTER: " << (void *)o << " " << idx << " " << OBJ2OID(o).getNX() << '\n';
04115 #endif
04116 if (!idx)
04117 return new oqmlStatus(node, fmt1, o);
04118
04119 if (!objCacheObj->deleteObject(OBJ2OID(o), force))
04120 return new oqmlStatus(node, fmt2, o);
04121
04122 if (!objCacheIdx->deleteObject(IDX2OID(idx), force))
04123 return new oqmlStatus(node, fmt3, o);
04124
04125 return oqmlSuccess;
04126 }
04127
04128 oqmlStatus *
04129 oqmlObjectManager::getObject(oqmlNode *node, Database *db,
04130 oqmlAtom *x, Object *&o,
04131 oqmlBool add_to_free_list,
04132 oqmlBool errorIfNull)
04133 {
04134 if (x) {
04135 if (OQML_IS_OID(x))
04136 return getObject(node, db, OQML_ATOM_OIDVAL(x), o, add_to_free_list,
04137 errorIfNull);
04138
04139 if (OQML_IS_OBJ(x)) {
04140 OQL_CHECK_OBJ(x);
04141 o = OQML_ATOM_OBJVAL(x);
04142 if (o)
04143 o->incrRefCount();
04144 return oqmlSuccess;
04145 }
04146 }
04147
04148 return oqmlStatus::expected(node, "oid or object", x->type.getString());
04149 }
04150
04151 void
04152 OqlCtbDatabase::userInitialize()
04153 {
04154 xdb = 0;
04155 }
04156
04157 void
04158 OqlCtbDatabase::userCopy(const Object &)
04159 {
04160 xdb = 0;
04161 }
04162
04163 void
04164 OqlCtbConnection::userInitialize()
04165 {
04166 conn = 0;
04167 }
04168
04169 void
04170 OqlCtbConnection::userCopy(const Object &)
04171 {
04172 conn = 0;
04173 }
04174
04175 void
04176 OqlCtbDatafile::userInitialize()
04177 {
04178 xdatfile = 0;
04179 }
04180
04181 void
04182 OqlCtbDatafile::userCopy(const Object &)
04183 {
04184 xdatfile = 0;
04185 }
04186
04187 void
04188 OqlCtbDataspace::userInitialize()
04189 {
04190 xdataspace = 0;
04191 }
04192
04193 void
04194 OqlCtbDataspace::userCopy(const Object &)
04195 {
04196 xdataspace = 0;
04197 }
04198
04199 Value *oqmlAtom::toValue() const
04200 {
04201 return 0;
04202 }
04203
04204 Value *oqmlAtom_null::toValue() const
04205 {
04206 return new Value(True, True);
04207 }
04208
04209 Value *oqmlAtom_bool::toValue() const
04210 {
04211 return new Value((Bool)b);
04212 }
04213
04214 Value *oqmlAtom_oid::toValue() const
04215 {
04216 return new Value(oid);
04217 }
04218
04219 Value *oqmlAtom_obj::toValue() const
04220 {
04221 return new Value(const_cast<const Object *>(o), idx);
04222 }
04223
04224 Value *oqmlAtom_int::toValue() const
04225 {
04226 return new Value(i);
04227 }
04228
04229 Value *oqmlAtom_char::toValue() const
04230 {
04231 return new Value(c);
04232 }
04233
04234 Value *oqmlAtom_double::toValue() const
04235 {
04236 return new Value(d);
04237 }
04238
04239 Value *oqmlAtom_string::toValue() const
04240 {
04241 return new Value(shstr->s);
04242 }
04243
04244 Value *oqmlAtom_ident::toValue() const
04245 {
04246 return new Value(shstr->s, True);
04247 }
04248
04249 Value::Type
04250 oqmlAtom_coll::getValueType() const
04251 {
04252 return Value::tNil;
04253 }
04254
04255 Value::Type
04256 oqmlAtom_list::getValueType() const
04257 {
04258 return Value::tList;
04259 }
04260
04261 Value::Type
04262 oqmlAtom_set::getValueType() const
04263 {
04264 return Value::tSet;
04265 }
04266
04267 Value::Type
04268 oqmlAtom_array::getValueType() const
04269 {
04270 return Value::tArray;
04271 }
04272
04273 Value::Type
04274 oqmlAtom_bag::getValueType() const
04275 {
04276 return Value::tBag;
04277 }
04278
04279 Value *oqmlAtom_coll::toValue() const
04280 {
04281 LinkedList *l = new LinkedList();
04282 oqmlAtom *x = list->first;
04283
04284 while (x) {
04285 l->insertObjectLast(x->toValue());
04286 x = x->next;
04287 }
04288
04289 return new Value(l, getValueType());
04290 }
04291
04292 Value *oqmlAtom_struct::toValue() const
04293 {
04294 Value::Struct *stru = new Value::Struct(attr_cnt);
04295
04296 for (int i = 0; i < attr_cnt; i++)
04297 stru->attrs[i] = new Value::Attr(attr[i].name,
04298 attr[i].value->toValue());
04299
04300 return new Value(stru);
04301 }
04302
04303 static oqmlStatus *
04304 oqml_get_location_db(Database *db, oqmlContext *ctx, oqmlNode *location,
04305 oqmlAtom *a, Database *&xdb)
04306 {
04307 Object *o = 0;
04308 oqmlStatus *s = oqmlObjectManager::getObject(location, db, a, o, oqml_True, oqml_True);
04309 if (s) return s;
04310
04311 if (strcmp(o->getClass()->getName(), "database"))
04312 return new oqmlStatus(location, "database object expected, got object "
04313 "of class '%s'", o->getClass()->getName());
04314
04315 OqlCtbDatabase *tdb = (OqlCtbDatabase *)o;
04316
04317 if (!tdb->xdb)
04318 return new oqmlStatus(location, "database is not opened");
04319
04320 xdb = tdb->xdb;
04321 return oqmlSuccess;
04322 }
04323
04324 oqmlStatus *oqml_get_location(Database *&db, oqmlContext *ctx,
04325 oqmlNode *location, oqmlBool *mustDeferred)
04326 {
04327 if (mustDeferred) *mustDeferred = oqml_False;
04328
04329 if (!location)
04330 return oqmlSuccess;
04331
04332 oqmlStatus *s;
04333 oqmlAtomList *al;
04334
04335 s = location->compile(db, ctx);
04336 if (s) return s;
04337
04338 s = location->eval(db, ctx, &al);
04339 if (s) return s;
04340
04341
04342 if (!al->cnt && mustDeferred) {
04343 *mustDeferred = oqml_True;
04344 return oqmlSuccess;
04345 }
04346
04347
04348 if (!al->cnt || !OQML_IS_OBJECT(al->first)) {
04349
04350 if (location->getType() == oqmlIDENT &&
04351 !strcmp(((oqmlIdent *)location)->getName(), "oql$db"))
04352 return oqmlSuccess;
04353 return new oqmlStatus(location,
04354 (std::string("database expected")+
04355 (al->first ? std::string(", got ") + al->first->type.getString() : std::string(""))).c_str());
04356 }
04357 #if 1
04358 return oqml_get_location_db(db, ctx, location, al->first, db);
04359 #else
04360 Object *o = 0;
04361 s = oqmlObjectManager::getObject(location, db, al->first, o,
04362 oqml_True, oqml_True);
04363 if (s) return s;
04364
04365 if (strcmp(o->getClass()->getName(), "database"))
04366 return new oqmlStatus(location, "database object expected, got object "
04367 "of class '%s'", o->getClass()->getName());
04368
04369 OqlCtbDatabase *tdb = (OqlCtbDatabase *)o;
04370
04371 if (!tdb->xdb)
04372 return new oqmlStatus(location, "database is not opened");
04373
04374 db = tdb->xdb;
04375
04376 return oqmlSuccess;
04377 #endif
04378 }
04379
04380 oqmlStatus *
04381 oqml_get_locations(Database *db, oqmlContext *ctx,
04382 oqmlNode *location, Database *xdb[], int &xdb_cnt)
04383 {
04384 xdb_cnt = 0;
04385 if (!location) {
04386 xdb[xdb_cnt++] = db;
04387 return oqmlSuccess;
04388 }
04389
04390 oqmlStatus *s;
04391 oqmlAtomList *al;
04392
04393 s = location->compile(db, ctx);
04394 if (s) return s;
04395
04396 s = location->eval(db, ctx, &al);
04397 if (s) return s;
04398
04399 if (!al->cnt)
04400 return new oqmlStatus(location,
04401 (std::string("database expected")+
04402 (al->first ? std::string(", got ") + al->first->type.getString() : std::string(""))).c_str());
04403
04404
04405 if (OQML_IS_OBJECT(al->first)) {
04406 oqmlStatus *s = oqml_get_location_db(db, ctx, location, al->first, xdb[xdb_cnt]);
04407 if (!s) xdb_cnt++;
04408 #ifdef SYNC_GARB
04409 if (al && !al->refcnt) {
04410 al->first = 0;
04411 OQL_DELETE(al);
04412 }
04413 #endif
04414 return s;
04415 }
04416
04417 if (OQML_IS_COLL(al->first)) {
04418 oqmlAtom *a = OQML_ATOM_COLLVAL(al->first)->first;
04419 while (a) {
04420 oqmlStatus *s = oqml_get_location_db(db, ctx, location, a, xdb[xdb_cnt]);
04421 if (s) return s;
04422 xdb_cnt++;
04423 a = a->next;
04424 }
04425 #ifdef SYNC_GARB
04426 if (al && !al->refcnt) {
04427 al->first = 0;
04428 OQL_DELETE(al);
04429 }
04430 #endif
04431 return oqmlSuccess;
04432 }
04433
04434
04435 if (location->getType() == oqmlIDENT &&
04436 !strcmp(((oqmlIdent *)location)->getName(), "oql$db")) {
04437 return oqmlSuccess;
04438 }
04439
04440 return new oqmlStatus(location,
04441 (std::string("database expected")+
04442 (al->first ? std::string(", got ") + al->first->type.getString() : std::string(""))).c_str());
04443 }
04444
04445 void stop_in_1()
04446 {
04447 }
04448
04449 void stop_in_2()
04450 {
04451 }
04452
04453 oqmlBool oqmlAtom::isEqualTo(oqmlAtom &atom)
04454 {
04455 assert(0);
04456 return oqml_False;
04457 }
04458
04459 oqmlBool oqmlAtom_nil::isEqualTo(oqmlAtom &atom)
04460 {
04461 return OQMLBOOL(atom.as_nil());
04462 }
04463
04464 oqmlBool oqmlAtom_null::isEqualTo(oqmlAtom &atom)
04465 {
04466 return OQMLBOOL(atom.as_null());
04467 }
04468
04469 oqmlBool oqmlAtom_bool::isEqualTo(oqmlAtom &atom)
04470 {
04471 return OQMLBOOL(atom.as_bool() && OQML_ATOM_BOOLVAL(&atom) == OQML_ATOM_BOOLVAL(this));
04472 }
04473
04474 oqmlBool oqmlAtom_oid::isEqualTo(oqmlAtom &atom)
04475 {
04476 return OQMLBOOL(atom.as_oid() && OQML_ATOM_OIDVAL(&atom) == oid);
04477 }
04478
04479 oqmlBool oqmlAtom_obj::isEqualTo(oqmlAtom &atom)
04480 {
04481 return OQMLBOOL(atom.as_obj() && OQML_ATOM_OBJVAL(&atom) == o);
04482 }
04483
04484 oqmlBool oqmlAtom_int::isEqualTo(oqmlAtom &atom)
04485 {
04486 return OQMLBOOL(atom.as_int() && OQML_ATOM_INTVAL(&atom) == i);
04487 }
04488
04489 oqmlBool oqmlAtom_char::isEqualTo(oqmlAtom &atom)
04490 {
04491 return OQMLBOOL(atom.as_char() && OQML_ATOM_CHARVAL(&atom) == c);
04492 }
04493
04494 oqmlBool oqmlAtom_double::isEqualTo(oqmlAtom &atom)
04495 {
04496 return OQMLBOOL(atom.as_double() && OQML_ATOM_DBLVAL(&atom) == d);
04497 }
04498
04499 oqmlBool oqmlAtom_string::isEqualTo(oqmlAtom &atom)
04500 {
04501 return OQMLBOOL(atom.as_string() &&
04502 !strcmp(OQML_ATOM_STRVAL(&atom), OQML_ATOM_STRVAL(this)));
04503 }
04504
04505 oqmlBool oqmlAtom_ident::isEqualTo(oqmlAtom &atom)
04506 {
04507 return OQMLBOOL(atom.as_ident() &&
04508 !strcmp(OQML_ATOM_IDENTVAL(&atom), OQML_ATOM_IDENTVAL(this)));
04509 }
04510
04511 oqmlBool oqmlAtom_range::isEqualTo(oqmlAtom &atom)
04512 {
04513 return OQMLBOOL(atom.as_ident() &&
04514 !strcmp(OQML_ATOM_IDENTVAL(&atom), OQML_ATOM_IDENTVAL(this)));
04515 }
04516
04517 oqmlBool oqmlAtom_coll::isEqualTo(oqmlAtom &atom)
04518 {
04519 if (atom.type.type != type.type)
04520 return oqml_False;
04521 return list->isEqualTo(*OQML_ATOM_COLLVAL(&atom));
04522 }
04523
04524 oqmlBool oqmlAtom_struct::isEqualTo(oqmlAtom &atom)
04525 {
04526 if (!atom.as_struct() || atom.as_struct()->attr_cnt != attr_cnt)
04527 return oqml_False;
04528
04529 for (int i = 0; i < attr_cnt; i++)
04530 if (!attr[i].value->isEqualTo(*atom.as_struct()->attr[i].value))
04531 return oqml_False;
04532
04533 return oqml_True;
04534 }
04535
04536 oqmlBool oqmlAtomList::isEqualTo(oqmlAtomList &list)
04537 {
04538 if (list.cnt != cnt)
04539 return oqml_False;
04540
04541 oqmlAtom *a = list.first;
04542 oqmlAtom *x = first;
04543 while (a) {
04544 if (!a->isEqualTo(*x))
04545 return oqml_False;
04546 a = a->next;
04547 x = x->next;
04548 }
04549
04550 return oqml_True;
04551 }
04552
04553 int BR_CND;
04554 int GB_COUNT;
04555
04556 oqmlBool
04557 oqml_is_symbol(oqmlContext *ctx, const char *sym)
04558 {
04559 oqmlAtom *x = 0;
04560 return (ctx->getSymbol(sym, 0, &x) && x &&
04561 ((OQML_IS_INT(x) && OQML_ATOM_INTVAL(x)) ||
04562 (OQML_IS_BOOL(x) && OQML_ATOM_BOOLVAL(x)))) ? oqml_True : oqml_False;
04563 }
04564
04565 void break_now() { }
04566 }