oqlbase.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021   Author: Eric Viara <viara@sysra.com>
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 //#define SUPPORT_OQLRESULT
00036 //#define SUPPORT_POSTACTIONS
00037 
00038 // work, but very slow !
00039 //#define SYNC_SYM_GARB
00040 #define SYNC_SYM_GARB_1
00041 #define SYNC_SYM_GARB_2
00042 
00043 //#define GARB_TRACE
00044 //#define GARB_TRACE_DETAIL
00045 
00046 #define NEW_SUPPRESS_DOUBLES
00047 
00048 #include "oql_p.h"
00049 
00050 namespace eyedb {
00051 
00052   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00053   //
00054   // static declarations
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   // oqmlGarbManager methods
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   // oqmlNode methods
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     //  back = this;
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     //printf("requalify from %d to %d\n", type, _type);
00447     type = _type;
00448   }
00449 
00450   oqmlNode::~oqmlNode()
00451   {
00452     //printf("deleting node %p\n", this);
00453     assert(__garb_guardian__);
00454     //  delete cst_list;
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   // oqmlComp methods
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     // delete qleft;
00491     // delete qright;
00492     delete iter;
00493     free(opstr);
00494   }
00495 
00496   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00497   //
00498   // oqml_List methods
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       //printf("registering object %p while unlocking\n", this);
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     // delete ql;
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   // oqmlAtom methods
00712   //
00713   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00714 
00715   oqmlAtom *
00716   oqmlAtom::make_atom(const IteratorAtom &atom, Class *cls)
00717   {
00718     // 12/09/05: for backward compatibility !
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       // added the 5/11/99
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       memset(&entry->data, 0, key_len);
00846       entry->ind = ind;
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   // oqmlAtom derived class methods
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       //eyedblib::int64 v = (eyedblib::int64)i;
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   // 13/03/99 ... continue comments ...
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           // this has been added to support construction in
01673           // where clause such as: xxx.y[?].ss == "soso"
01674           // 27/09/99
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   // TODO: clarifier promotion char -> int
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     //if (!strcmp(opstr, "%")) opstr = "%%";
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     //if (!strcmp(opstr, "%")) opstr = "%%";
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       if ((*al_left)->cnt != 1 || (*al_right)->cnt != 1)
01892       return new oqmlStatus(this, "invalid operand.");
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     // (int -> double) promotion
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     // (char -> double) promotion
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     // (char -> int) promotion
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     //printf("oqmlNode::SWAP\n");
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       printf("compiling oqmlComp => %s context='%s %s %s' [iterator %d]\n",
01989       (const char *)comp->toString(),
01990       ctx->isSelectContext() ? "select" : "not select",
01991       ctx->isPrevalContext() ? "preval" : "not preval",
01992       ctx->isWhereContext() ? "where" : "not where",
01993       comp->getIterator());
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         printf("WE ARE IN A HIDDEN SELECT CONTEXT left=%d right=%d\n",
02012         sel->usesFromIdent(qleft),
02013         sel->usesFromIdent(qright));
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       // changed 12/03/99:
02028       //      if (comp->getType() != oqmlEQUAL && comp->getType() != oqmlDIFF)
02029 
02030       // changed 24/02/00
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     // added the 27/02/00
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     // added the 27/02/00
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     // JE PENSE que ce n'est pas le bon test!
02155     // le bon test est 'ctx->getSelectContext()->usesFromIdent(this))'
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     // CE N'EST PAS LE BON TEST!
02217     // le bon test est:
02218     // if (qright->hasIdent(one of the from list!) && !needReinit)
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       // 8/3/00: commented the following line!
02283       if (firstPass) 
02284         evalDone = oqml_True;
02285       done = oqml_True;
02286       return oqmlSuccess;
02287     }
02288   
02289     // the following query come here: select class = "User"
02290     //assert(0);
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     //printf("making estimation of %s\n", (const char *)qleft->toString());
02306     if (qleft->asDot()) {
02307       oqmlBool hasOne;
02308       oqmlStatus *s = qleft->asDot()->hasIndex(db, ctx, hasOne);
02309       if (s) return s;
02310       //printf("has %s index\n", hasOne ? "an" : "NO");
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       printf("oqmlEqual::estimate(%s, %s)\n",
02364       (const char *)qleft->toString(),
02365       (const char *)qright->toString());
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       printf("requalifying ident '%s' to '%s' (%s)\n", ident,
02448       (const char *)node->toString(), (const char *)ql->toString());
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       if (ql)
02481       printf("requalifying back node %s to %s\n", (const char *)ql->toString(),
02482       ql->back ? (const char *)ql->back->toString() : "nil");
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   //#define LOCK_TRACE
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     // 8/02/06
02566     if (!donotdel) {
02567       if (!lock && rm && !l->refcnt) {
02568         //printf("before deleting LIST\n");
02569         delete l;
02570         //printf("after deleting LIST\n");
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                //rm && !donotdel ? oqml_True : oqml_False);
02604                oqml_False);
02605     else if (OQML_IS_IDENT(a) && a->as_ident()->entry)
02606       oqmlLock(a->as_ident()->entry->at, lock,
02607                //rm && !donotdel ? oqml_True : oqml_False);
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                  //rm && !donotdel ? oqml_True : oqml_False);
02614                  oqml_False);
02615     }
02616 
02617     a->recurs = oqml_False;
02618 
02619     // 8/02/06
02620     if (!donotdel) {
02621       if (!lock && rm && !a->refcnt) {
02622         //printf("deleting atom\n");
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   //#define SYMB_TRACE
02665   //#define LOCAL_TRACE
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           // should done a insert
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); // 8/02/06
02738       }
02739 
02740 #elif defined(SYNC_SYM_GARB)
02741       if (at) {
02742         if (tofree)
02743           checkAutoAssign(_at, at);
02744         oqmlLock(at, oqml_False, tofree); // 8/02/06
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     //    printf("~oqmlSymbolEntry(%s)\n", ident);
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   // private symbol management methods.
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     // 29/12/99
02880     // I guess that this loop should occurs if and only if symbol
02881     // is global!
02882     while (s) {
02883       // changed test the 19/06/01
02884       /*
02885         if (!strcmp(s->ident, ident) && s->global == global &&
02886         s->level == local_cnt)
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   // public symbol management methods.
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   // changed incr and decr SelectContext the 9/may/99
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     //const char *sx = x->getString();
03319     oqmlAtom *a = first;
03320 
03321     while (a) {
03322       /*
03323         if (!strcmp(sx, a->getString()))
03324         return oqml_True;
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   // flag set the 2/3/00
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   // range atom
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         //printf("suppressed! %s\n", ident);
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     // changed the 21/01/03 :
03845     // added :
03846     if (s) return s;
03847 
03848     // suppressed :
03849     /*
03850       if (!s)
03851       oqmlStatus::purge();
03852     */
03853     // end of change
03854 
03855     // DISCONNECTED the 19/06/01 because of memory bugs!
03856     // reconnected the 21/01/03 ... 
03857 #if !defined(SUPPORT_OQLRESULT) && !defined(SUPPORT_POSTACTIONS)
03858     //  printf("warning oqml_manage_postactions disconnected\n");
03859     return s;
03860 #endif
03861 
03862     oqmlAtom *ra = s || !*alist ? 0 : (*alist)->first;
03863 
03864     // disconnected the 21/05/01 cecause of an obscur memory bug.
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     //printf("garbaging freelist -> cnt=%d\n", freeList.getCount());
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     //printf("IDX2OID %u.%d.%d %lld\n", oid.getNX(), oid.getDbid(), oid.getUnique(), idx);
03976     return oid;
03977   }
03978 
03979   static Oid OBJ2OID(const Object *o)
03980   {
03981     Oid oid;
03982     memcpy(&oid, &o, sizeof(o));
03983     //printf("OBJ2OID %u.%d.%d %llx\n", oid.getNX(), oid.getDbid(), oid.getUnique(), o);
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       //printf("check object %o %lld ok\n", o, i);
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     //printf("setting %lx to null\n", o);
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       // to increase reference count
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     // should be there ?
04342     if (!al->cnt && mustDeferred) {
04343       *mustDeferred = oqml_True;
04344       return oqmlSuccess;
04345     }
04346 
04347     // or there ?
04348     if (!al->cnt || !OQML_IS_OBJECT(al->first)) {
04349       // kludge for old databases!
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     // or there ?
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     // kludge for old databases!
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 }

Generated on Mon Dec 22 18:16:01 2008 for eyedb by  doxygen 1.5.3