oqldot.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 "oql_p.h"
00030 #include "Attribute_p.h"
00031 
00032 // flag added the 28/02/00
00033 #define NEW_IDX_CHOICE
00034 
00035 // flag added the 28/02/00
00036 #define NEW_SELECT
00037 
00038 #define OBJ_SUPPORT
00039 
00040 namespace eyedb {
00041 
00042 void stop_oql() { }
00043 
00044 #define OPTIM_TVALUE
00045 //#define SUPPORT_CSTRING
00046 
00047 static inline oqmlBool
00048 oqml_is_subclass(const Class *cls1, const Class *cls2)
00049 {
00050   if (!cls1 || !cls2)
00051     return oqml_False;
00052 
00053   Bool is;
00054   cls1->isSubClassOf(cls2, &is);
00055   return OQMLBOOL(is);
00056 }
00057 
00058 #define DBG_LEVEL 0
00059 //#define SKIP_ATTR_ERR
00060 
00061 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00062 //
00063 // private utility methods
00064 //
00065 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00066 
00067 Status
00068 oqml_check_vardim(Database *db, const Attribute *attr, Oid *oid,
00069                   oqmlBool& enough, int from, int &nb)
00070 {
00071   enough = oqml_True;
00072 
00073   Size size;
00074   Status is = attr->getSize(db, oid, size);
00075       
00076   if (is)
00077     return is;
00078 
00079   if (from + nb > size)
00080     enough = oqml_False;
00081 
00082   return Success;
00083 }
00084 
00085 Status
00086 oqml_check_vardim(const Attribute *attr, Object *o, oqmlBool set,
00087                   oqmlBool& enough, int from, int &nb, int pdims,
00088                   oqmlBool isComplete)
00089 {
00090   if (nb < 0)
00091     return Exception::make(IDB_ERROR, "cannot set to NULL");
00092 
00093   enough = oqml_True;
00094 
00095   if (attr->isVarDim())
00096     {
00097       Size size;
00098       Status is = attr->getSize((Agregat *)o, size);
00099 
00100       if (is)
00101         return is;
00102 
00103       int wanted = from + nb;
00104       if (set)
00105         {
00106           if ((isComplete && wanted != size * pdims) ||
00107               (!isComplete && wanted > size * pdims)) {
00108             is = attr->setSize((Agregat *)o, ((wanted-1) / pdims) + 1);
00109             if (is)
00110               return is;
00111           }
00112         }
00113       else if (wanted > size * pdims)
00114         enough = oqml_False;
00115     }
00116 
00117   return Success;
00118 }
00119 
00120 static oqmlStatus *
00121 oqml_getclass(oqmlNode *node, Database *db, oqmlContext *ctx,
00122               oqmlAtom *a, Class **cls, const char *varname = 0)
00123 {
00124   if (a && OQML_IS_OBJECT(a))
00125     {
00126 #ifdef OPTIM_TVALUE
00127       if (OQML_IS_OBJ(a))
00128         {
00129           OQL_CHECK_OBJ(a);
00130           if (!OQML_ATOM_OBJVAL(a))
00131             return new oqmlStatus(node, "invalid null object");
00132           *cls = (Class *)OQML_ATOM_OBJVAL(a)->getClass();
00133           return oqmlSuccess;
00134         }
00135 
00136       if (!OQML_ATOM_OIDVAL(a).isValid() && ctx->isWhereContext()) {
00137         *cls = 0;
00138         return oqmlSuccess;
00139       }
00140 
00141       /*
00142       // 9/07/06
00143       if (!OQML_ATOM_OIDVAL(a).isValid()) {
00144         *cls = 0;
00145         return oqmlSuccess;
00146       }
00147       */
00148 
00149       Status is = db->getObjectClass(OQML_ATOM_OIDVAL(a), *cls);
00150       if (is)
00151         return new oqmlStatus(node, is);
00152       return oqmlSuccess;
00153 #else
00154       Object *o;
00155       oqmlStatus *s = oqmlObjectManager::getObject(node, db, a, o, oqml_True);
00156       if (s) return s;
00157       if (!o)
00158         return new oqmlStatus(node, "invalid null object");
00159       *cls = o->getClass();
00160       return oqmlSuccess;
00161 #endif
00162     }
00163 
00164   if (a && OQML_IS_STRUCT(a))
00165     {
00166       *cls = 0;
00167       return oqmlSuccess;
00168     }
00169  
00170   // added 28/02/00
00171   if ((OQML_IS_NULL(a) || a->as_nil()) && ctx->isWhereContext()) {
00172     *cls = 0;
00173     return oqmlSuccess;
00174   }
00175 
00176   /*
00177   // 9/07/06
00178   if (OQML_IS_NULL(a) || a->as_nil()) {
00179     *cls = 0;
00180     return oqmlSuccess;
00181   }
00182   */
00183 
00184   if (a)
00185     {
00186       if (varname)
00187         return new oqmlStatus(node, "value of '%s': oid expected, got %s",
00188                               varname, a->type.getString());
00189       return oqmlStatus::expected(node, "oid", a->type.getString());
00190     }
00191 
00192   if (varname)
00193     return new oqmlStatus(node, "value of '%s': oid expected",
00194                           varname);
00195 
00196   return new oqmlStatus(node, "oid expected");
00197 }
00198 
00199 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00200 //
00201 // oqmlDotDesc method
00202 //
00203 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00204 
00205 oqmlStatus *
00206 oqmlDotDesc::evalInd(oqmlNode *node, Database *db, oqmlContext *ctx,
00207                      int &s_ind, int &e_ind, oqmlBool nocheck,
00208                      oqmlBool ignoreColl)
00209 {
00210   if (array)
00211     {
00212       oqmlStatus *s;
00213 #if 0
00214       if (is_coll && ignoreColl)
00215         {
00216           int ind;
00217           s = array->evalCollArray(node, db, ctx, mod, ind);
00218           s_ind = e_ind = ind;
00219           printf("Ignoring Coll => ind = %d\n", s_ind);
00220         }
00221 #endif
00222 
00223       if (is_coll && !ignoreColl)
00224         {
00225           int ind;
00226           s = array->evalCollArray(node, db, ctx, mod, ind);
00227           s_ind = e_ind = ind;
00228           //printf("NOT Ignoring Coll => ind = %d\n", s_ind);
00229           return s;
00230         }
00231 
00232       s = array->eval(node, db, ctx, attr->getClassOwner()->getName(),
00233                       attrname, mod, &s_ind, &e_ind, nocheck);
00234       //printf("Not Call s_ind = %d, e_ind = %d\n", s_ind, e_ind);
00235       return s;
00236     }
00237 
00238   s_ind = 0;
00239   e_ind = 0;
00240 
00241   return oqmlSuccess;
00242 }
00243 
00244 void
00245 oqmlDotDesc::make_key(int size)
00246 {
00247   if (size > key_len)
00248     {
00249       free(s_data);
00250       s_data = (unsigned char *)malloc(size);
00251       free(e_data);
00252       e_data = (unsigned char *)malloc(size);
00253 
00254       key_len = size;
00255     }
00256 }
00257 
00258 oqmlDotDesc::oqmlDotDesc()
00259 {
00260   key = 0;
00261   attrname = 0;
00262   s_data = 0;
00263   e_data = 0;
00264   icurs = 0;
00265   idxs = 0;
00266   idxse = 0;
00267   qlmth = 0;
00268 }
00269 
00270 oqmlDotDesc::~oqmlDotDesc()
00271 {
00272   // DISCONNECTED the 3/07/01
00273   // if (qlmth) qlmth->unlock();
00274 
00275   delete key;
00276   free(attrname);
00277   free(s_data);
00278   free(e_data);
00279   delete icurs;
00280 
00281   // added 2/09/05 ...and disconnected
00282   /*
00283   for (int n = 0; n < idx_cnt; n++) {
00284     delete idxs[n];
00285     delete idxse[n];
00286   }
00287   */
00288 
00289   delete[] idxs;
00290   delete[] idxse;
00291 }
00292 
00293 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00294 //
00295 // oqmlDotContext methods
00296 //
00297 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00298 
00299 oqmlDotContext::oqmlDotContext(oqmlDot *p, const char *n)
00300 {
00301   init(p);
00302   varname = n;
00303 }
00304 
00305 oqmlDotContext::oqmlDotContext(oqmlDot *p, const Class *cls)
00306 {
00307   init(p);
00308   count = 1;
00309   desc[0].cls = cls;
00310   desc[0].cls_orig = cls;
00311   desc[0].isref = True;
00312 }
00313 
00314 oqmlDotContext::oqmlDotContext(oqmlDot *p, oqmlAtom *curatom)
00315 {
00316   init(p);
00317   count = 1;
00318   desc[0].curatom = curatom;
00319 }
00320 
00321 oqmlDotContext::oqmlDotContext(oqmlDot *p, oqmlNode *_oqml)
00322 {
00323   init(p);
00324   oqml = _oqml;
00325 }
00326 
00327 void oqmlDotContext::init(oqmlDot *d)
00328 {
00329   dot = d;
00330   count = 0;
00331   oqml = 0;
00332   tctx = 0;
00333   tlist = 0;
00334   varname = 0;
00335   ident_mode = False;
00336   iscoll = False;
00337   dot_type.type = oqmlATOM_UNKNOWN_TYPE;
00338   dot_type.cls = 0;
00339   dot_type.comp = oqml_False;
00340 
00341   desc = idbNewVect(oqmlDotDesc, oqmlMAXDESC);
00342 }
00343 
00344 void oqmlDotContext::setIdentMode(Bool _iscoll)
00345 {
00346   ident_mode = True;
00347   iscoll = _iscoll;
00348 }
00349 
00350 oqmlStatus *
00351 oqmlDotContext::setAttrName(Database *db,
00352                             const char *_attrname)
00353 {
00354   const char *attrname;
00355   const Class *cls;
00356   oqmlStatus *s = dot->isScope(db, _attrname, attrname, cls);
00357   if (s) return s;
00358 
00359   oqmlDotDesc *d = &desc[count];
00360 
00361   if (attrname)
00362     {
00363       d->attrname = strdup(attrname);
00364       assert(count > 0);
00365       assert(cls);
00366       desc[count-1].cls_orig = desc[count-1].cls = cls;
00367     }
00368   else
00369     d->attrname = (_attrname ? strdup(_attrname) : 0);
00370 
00371   return oqmlSuccess;
00372 }
00373 
00374 static const Class *
00375 get_rootclass(oqmlDotContext *dctx)
00376 {
00377   for (int k = dctx->count-1; k >= 0; k--)
00378     if (dctx->desc[k].isref)
00379       return dctx->desc[k].cls;
00380 
00381   //  assert(0);
00382   return 0;
00383 }
00384 
00385 static void
00386 make_idx_ctx(oqmlDotContext *dctx, AttrIdxContext &idx_ctx)
00387 {
00388   int j;
00389   for (j = dctx->count; j >= 2; j--)
00390     if (dctx->desc[j-1].isref)
00391       break;
00392 
00393   for (int i = j; i <= dctx->count; i++) {
00394     idx_ctx.push(dctx->desc[i].attrname);
00395   }
00396 }
00397 
00398 oqmlStatus *
00399 oqmlDotDesc::getIdx(Database *db, oqmlContext *ctx, oqmlDot *dot)
00400 {  
00401   idx_cnt = 0;
00402 
00403   const Class *rootcls = get_rootclass(dctx);
00404 
00405   if (!rootcls)
00406     return oqmlSuccess;
00407 
00408   unsigned int subclass_cnt;
00409   Class **subclasses;
00410   Status status;
00411   int maxind;
00412   Size size;
00413 
00414 #if DBG_LEVEL > 0
00415   printf("oqmlDotDesc::getMultiIdx(%s, count = %d) {\n", rootcls->getName(),
00416          dctx->count);
00417 #endif
00418   status = rootcls->getSubClasses(subclasses, subclass_cnt);
00419   if (status) return new oqmlStatus(dot, status);
00420 
00421   for (int j = 0; j < subclass_cnt; j++)
00422     {
00423       AttrIdxContext idx_ctx(subclasses[j]);
00424       make_idx_ctx(dctx, idx_ctx);
00425 
00426 #if DBG_LEVEL > 0
00427       printf("\tsubclass #%d = %s [%s] (attr.name = %s, count=%d, name=%s)\n",
00428              j, subclasses[j]->getName(),
00429              (const char *)idx_ctx.getString(), attr->getName(),
00430              dctx->count, dctx->desc[1].attrname);
00431 #endif
00432 
00433       Index *idx = 0;
00434       eyedbsm::Idx *se_idx = 0;
00435       status = attr->getIdx(db, mode, maxind, size, idx_ctx, idx, se_idx);
00436       if (status)
00437         return new oqmlStatus(dot, status);
00438 
00439       if (!idx && !se_idx)
00440         continue;
00441 
00442       if (!idx_cnt)
00443         {
00444           idxs = new Index*[subclass_cnt];
00445           idxse = new eyedbsm::Idx*[subclass_cnt];
00446         }
00447 
00448       //printf("idxs[%d] = %p idxse[%d] = %p\n", idx_cnt, idx, idx_cnt, se_idx);
00449       idxs[idx_cnt] = idx;
00450       idxse[idx_cnt] = se_idx;
00451       idx_cnt++;
00452     }
00453 
00454   //printf("subclass_cnt %d %d\n", subclass_cnt, idx_cnt);
00455 
00456   if (idx_cnt && idx_cnt != subclass_cnt) {
00457     oqmlAtom *a;
00458     static const char varname[] = "oql$subtree$index$force";
00459     if (ctx->getSymbol(varname, 0, &a)) {
00460       if (a && OQML_IS_BOOL(a) && OQML_ATOM_BOOLVAL(a)) {
00461         //printf("does not use index in this case\n");
00462         idx_cnt = 0;
00463         return oqmlSuccess;
00464       }
00465     }
00466 
00467     std::string errmsg = std::string("The inheritance subtree ") +
00468       rootcls->getName() + ".." + attr->getName() +
00469       " is not index consistent:";
00470     std::string missing, existing;
00471     std::string comma = ", ";
00472     for (int j = 0; j < subclass_cnt; j++) {
00473       AttrIdxContext idx_ctx(subclasses[j]);
00474       make_idx_ctx(dctx, idx_ctx);
00475       
00476       Index *idx = 0;
00477       eyedbsm::Idx *se_idx = 0;
00478       status = attr->getIdx(db, mode, maxind, size, idx_ctx, idx, se_idx);
00479       if (status)
00480         return new oqmlStatus(dot, status);
00481       if (!idx) {
00482         if (missing.size()) missing += comma;
00483         missing += std::string(idx_ctx.getAttrName());
00484       } else {
00485         if (existing.size()) existing += comma;
00486         existing += std::string(idx_ctx.getAttrName());
00487       }
00488     }
00489 
00490     errmsg += std::string("\nExisting index: ") + existing;
00491     errmsg += std::string("\nMissing index: ") + missing;
00492     errmsg += std::string("\nCreate the missing index or set the oql variable '")
00493       + varname + "' to true";
00494     return new oqmlStatus(dot, errmsg.c_str());
00495   }
00496 
00497 #if DBG_LEVEL > 0
00498   printf("}\n");
00499 #endif
00500   return oqmlSuccess;
00501 }
00502 
00503 oqmlStatus *
00504 oqmlDotDesc::make(Database *db, oqmlContext *ctx, oqmlDot *dot,
00505                   const Attribute *xattr,
00506                   oqml_ArrayList *_array, const char *_attrname,
00507                   const Class *castcls)
00508 {
00509   assert(!attr);
00510 
00511   if (!xattr)
00512     return new oqmlStatus(dot, "unknown attribute '%s'", _attrname);
00513 
00514   attr = xattr;
00515   mod = &attr->getTypeModifier();
00516 
00517   oqmlStatus *s = dctx->setAttrName(db, _attrname);
00518   if (s)
00519     return s;
00520 
00521   if (oqml_is_getcount(_array)) {
00522     mode = 0;
00523     isref = False;
00524     cls_orig = cls = Int32_Class;
00525     key_len = sizeof(eyedblib::int32);
00526     s_data = (unsigned char *)malloc(sizeof(eyedblib::int32));
00527     e_data = (unsigned char *)malloc(sizeof(eyedblib::int32));
00528     array = _array;
00529     return oqmlSuccess;
00530   }
00531 
00532   array = _array;
00533 
00534   int ndims = mod->ndims;
00535   int array_ndims = (array ? array->count : 0);
00536 
00537   if ((array_ndims > ndims) || (ndims - array_ndims) > 1) {
00538     if (attr->getClass()->asCollectionClass() &&
00539         ((array_ndims <= ndims+1) && (ndims+1 - array_ndims) <= 1)) {
00540       if (s = array->checkCollArray(dot, attr->getClass(),
00541                                     attr->getName()))
00542         return s;
00543 
00544       is_coll = oqml_True;
00545       stop_oql();
00546     }
00547     else if (!ndims)
00548       return new oqmlStatus(dot, "attribute '%s' is not an array",
00549                             attr->getName());
00550     else
00551       return new oqmlStatus(dot, "array attribute '%s': "
00552                             "maximum dimension allowed is %d <got %d>",
00553                             attr->getName(), ndims, array_ndims);
00554   }
00555   
00556   Size sz_comp, inisize;
00557   if (is_coll) {
00558     eyedblib::int16 dim, item_size;
00559     cls = attr->getClass()->asCollectionClass()->getCollClass
00560       (&isref, &dim, &item_size);
00561     cls_orig = (castcls ? castcls : attr->getClass());
00562     mode = 0;
00563     sz_item = item_size*dim;
00564     sz_comp = 0;
00565   }
00566   else {
00567     isref = attr->isIndirect();
00568 
00569     // MIND: test un peu fragile!!
00570     if (ndims - array_ndims == 1)
00571       mode = Attribute::composedMode;
00572     else
00573       mode = 0;
00574 
00575     cls_orig = cls = (castcls ? castcls : attr->getClass());
00576 
00577     // added the 27/11/00, because in some cases db field was not
00578     // set in cls/cls_orig
00579     if (cls && !cls->getDatabase() && db)
00580       cls_orig = cls = db->getSchema()->getClass(cls->getName());
00581 
00582     // added the 6/12/99
00583     // suppressed the 20/12/99
00584     /*
00585       if (dctx->count > 1)
00586       dctx->desc[dctx->count-1].cls_orig = 
00587       dctx->desc[dctx->count-1].cls = attr->getClassOwner();
00588     */
00589     // ...
00590 
00591     Size _sz_item;
00592     Offset off;
00593     attr->getPersistentIDR(off, _sz_item, sz_comp, inisize);
00594       
00595     sz_comp -= inisize;
00596     sz_item = _sz_item;
00597   }
00598       
00599   // skip object collections for indexation
00600   if (!(is_coll && attr->isIndirect())) {
00601     s = getIdx(db, ctx, dot);
00602     if (s) return s;
00603   }
00604 
00605   if (attr->isVarDim() && !idx_cnt &&
00606       (mode == Attribute::composedMode || !cls->asBasicClass()))
00607     make_key(32);
00608   else {
00609     if (attr->isVarDim() && mode == Attribute::composedMode)
00610       sz_comp = sz_item = 0x200;
00611     if (mode == Attribute::composedMode)
00612       key_len = sz_comp;
00613     else {
00614       key_len = sz_item;
00615       // added 6/10/01: in fact, key_len must be at least the size
00616       // of a pointer in case of a direct non basic attribute
00617       if (!attr->isIndirect() && !attr->isBasicOrEnum() &&
00618           key_len < sizeof(void *))
00619         key_len = sizeof(void *);
00620     }
00621           
00622     if (idx_cnt)
00623       key = new eyedbsm::Idx::Key(sizeof(char) + sizeof(eyedblib::int32) +
00624                                   key_len);
00625           
00626     if (idx_cnt && mode != Attribute::composedMode) {
00627       s_data = (unsigned char *)
00628         malloc(sizeof(char) + sizeof(eyedblib::int32) + key_len);
00629       e_data = (unsigned char *)
00630         malloc(sizeof(char) + sizeof(eyedblib::int32) + key_len);
00631     }
00632     else {
00633       s_data = (unsigned char *)malloc(sizeof(char) + key_len);
00634       e_data = (unsigned char *)malloc(sizeof(char) + key_len);
00635     }
00636   }
00637 
00638   return oqmlSuccess;
00639 }
00640 
00641 oqmlStatus *
00642 oqmlDotContext::add(Database *db, oqmlContext *ctx,
00643                     const Attribute *attr,
00644                     oqml_ArrayList *_array,
00645                     char *attrname, oqmlAtom *curatom, Class *castcls,
00646                     oqmlNode *qlmth)
00647 {
00648   if (!attr && !qlmth & !attrname)
00649     return oqmlSuccess;
00650 
00651   oqmlDotDesc *d = &desc[count];
00652   d->dctx = this;
00653 
00654   if (qlmth)
00655     {
00656       d->qlmth = qlmth;
00657       d->isref = True; // !!THIS is not shure!!, in fact we do known
00658       // the return type of the method!!
00659       d->key_len = 256; // in case of this buffer is not large enough,
00660       // an error is thrown at runtime
00661       d->s_data = (unsigned char *)malloc(d->key_len);
00662       d->e_data = (unsigned char *)malloc(d->key_len);
00663       count++;
00664       return oqmlSuccess;
00665     }
00666 
00667   if (attr)
00668     {
00669       oqmlStatus *s = d->make(db, ctx, dot, attr, _array, attrname, castcls);
00670       if (s) return s;
00671       count++;
00672       /*
00673       if (!strcmp(attr->getClass()->getName(), "ostring"))
00674         return add(db, 0, 0, "s", 0, 0, 0);
00675         */
00676       return oqmlSuccess;
00677     }
00678 
00679   if (attrname)
00680     {
00681       oqmlStatus *s = setAttrName(db, attrname);
00682       if (s) return s;
00683       d->curatom = curatom;
00684       count++;
00685       return oqmlSuccess;
00686     }
00687 
00688   return oqmlSuccess;
00689 }
00690 
00691 static const char not_found_fmt[] = "attribute '%s' not found in class '%s'.";
00692 
00693 oqmlStatus *
00694 oqmlDotContext::eval_middle(Database *db, oqmlContext *ctx, Object *o, 
00695                             oqmlAtom *value, int n, oqmlAtomList **alist)
00696 {
00697   oqmlDotDesc *d = &desc[n];
00698   Status is;
00699   oqmlStatus *s;
00700   int s_ind, e_ind, ind;
00701 
00702   s = d->evalInd(dot, db, ctx, s_ind, e_ind, (value ? oqml_False : oqml_True),
00703                  oqml_False);
00704   if (s) return s;
00705   
00706   const Attribute *xattr;
00707   Object *mtho1;
00708   if (d->qlmth) {
00709     oqmlAtom *rmth;
00710     oqmlAtomList *al = new oqmlAtomList();
00711     oqmlStatus *s = ((oqmlMethodCall *)d->qlmth)->
00712       perform(db, ctx, o, o->getOid(), o->getClass(), &al);
00713     if (s) return s;
00714     xattr = 0;
00715 
00716     s = oqmlObjectManager::getObject(dot, db, al->first, mtho1, oqml_True);
00717     if (s) return s;
00718   }
00719   else {
00720     xattr = o->getClass()->getAttribute(d->attrname);
00721 
00722     if (!xattr)
00723       {
00724         if (n > 0 && oqml_is_subclass(desc[n-1].cls, o->getClass()))
00725           return oqmlSuccess;
00726         return new oqmlStatus(dot, not_found_fmt,
00727                               d->attrname, o->getClass()->getName());
00728       }
00729   }
00730 
00731   Data data = d->e_data;
00732 
00733   for (ind = s_ind; ind <= e_ind; ind++) {
00734     OQML_CHECK_INTR();
00735     Object *o1 = 0;
00736       
00737     if (d->qlmth)
00738       o1 = mtho1;
00739     else if (d->isref) {
00740       is = xattr->getValue((Agregat *)o, (Data *)data,
00741                            1, ind);
00742 
00743       if (is)
00744         return oqmlSuccess;
00745           
00746       mcp(&o1, data, sizeof(Object *));
00747       if (!o1) {
00748         is = xattr->getOid((Agregat *)o, (Oid *)data,
00749                            1, ind);
00750         if (is)
00751           return oqmlSuccess;
00752 
00753         s = oqmlObjectManager::getObject(dot, db, (Oid *)data, o1,
00754                                          oqml_True, oqml_False);
00755         if (s) return s;
00756         if (!o1) return oqmlSuccess;
00757       }
00758     }
00759     else if (oqml_is_getcount(d->array))
00760       return new oqmlStatus(dot, "invalid indirection");
00761     else if (xattr->isBasicOrEnum())
00762       return new oqmlStatus(dot, "attribute '%s' in class '%s' is not an "
00763                             "agregat",
00764                             xattr->getName(),
00765                             xattr->getClassOwner()->getName());
00766     else {
00767       oqmlBool enough;
00768       int nb = 1;
00769       is = oqml_check_vardim(xattr, o, OQMLBOOL(value), enough, ind, nb,
00770                              xattr->getTypeModifier().pdims,
00771                              oqml_False); // 23/05/02: changed from OQMLCOMPLETE(value) because non sense in eval_middle
00772 
00773 #if DBG_LEVEL > 2
00774       printf("oqmlDotContext::eval_middle(ind = %d, enough = %d, %p)\n",
00775              ind, enough, is);
00776 #endif
00777 
00778       if (is)
00779         return new oqmlStatus(dot, is);
00780 
00781       if (!enough) {
00782         if (value)
00783           continue;
00784         else
00785           break;
00786       }
00787 
00788       is = xattr->getValue((Agregat *)o, (Data *)data, 1, ind);
00789 
00790       if (is)
00791         return new oqmlStatus(dot, is);
00792 
00793       memcpy(&o1, data, sizeof(Object *));
00794       if (o1)
00795         o1->setDatabase(db);
00796     }
00797       
00798     oqmlStatus *s;
00799     if (d->is_coll) {
00800       if (!o1->asCollection())
00801         return new oqmlStatus(dot, "collection expected, got %s",
00802                               o1->getClass()->getName());
00803 
00804       if (o1->asCollArray()) {
00805         assert(d->array);
00806         oqmlAtomList *al;
00807 
00808         s = oqmlArray::evalMake(db, ctx, o1, d->array, oqml_False, &al);
00809         if (s) return s;
00810         oqmlAtom *x = al->first;
00811         if (!x)
00812           continue;
00813 
00814         if (OQML_IS_COLL(x))
00815           x = OQML_ATOM_COLLVAL(x)->first;
00816 
00817         while (x)       {
00818           Object *coll;
00819           s = oqmlObjectManager::getObject(dot, db, x, coll,
00820                                            oqml_False, oqml_False);
00821           if (s) return s;
00822           s = eval_perform(db, ctx, coll, value, n+1, alist);
00823           oqmlObjectManager::releaseObject(coll, oqml_False);
00824           if (s) return s;
00825           x = x->next;
00826         }
00827 
00828         continue;
00829       }
00830 
00831       ObjectArray obj_arr;
00832       is = o1->asCollection()->getElements(obj_arr);
00833       if (is)
00834         return new oqmlStatus(dot, is);
00835 
00836       for (int i = 0; i < obj_arr.getCount(); i++)  {
00837         s = eval_perform(db, ctx, const_cast<Object *>(obj_arr[i]), value, n+1, alist);
00838         if (s) return s;
00839       }
00840 
00841       continue;
00842     }
00843 
00844     s = eval_perform(db, ctx, o1, value, n+1, alist);
00845 
00846 #if DBG_LEVEL > 2
00847     printf("returning from eval perform -> count = %d\n",
00848            (*alist)->cnt);
00849 #endif
00850 
00851     if (s) return s;
00852 
00853     if (value && !d->isref) {
00854       oqmlBool enough;
00855       int nb = 1;
00856       is = oqml_check_vardim(xattr, o, OQMLBOOL(value), enough, ind, nb,
00857                              xattr->getTypeModifier().pdims,
00858                              oqml_False); // 23/05/02: changed from OQMLCOMPLETE(value) because non sense in eval_middle
00859 
00860       if (is) return new oqmlStatus(dot, is);
00861 
00862       if (!enough) {
00863         if (value)
00864           continue;
00865         else
00866           break;
00867       }
00868 
00869       is = xattr->setValue((Agregat *)o, (Data)&o1, 1, ind);
00870       if (is) return new oqmlStatus(dot, is);
00871     }
00872   }
00873 
00874   return oqmlSuccess;
00875 }
00876 
00877 static oqmlStatus *
00878 make_contents(oqmlDotDesc *d, oqmlNode *dot, Database *db, oqmlContext *ctx,
00879               oqmlAtom *x, oqmlAtomList *alist)
00880 {
00881   oqmlStatus *s;
00882 
00883   Object *coll;
00884   if (OQML_IS_OBJ(x)) {
00885     OQL_CHECK_OBJ(x);
00886     coll = OQML_ATOM_OBJVAL(x);
00887   }
00888   else if (s = oqmlObjectManager::getObject(dot, db, x, coll, oqml_True,
00889                                             oqml_True))
00890     return s;
00891 
00892   if (!coll->asCollection())
00893     return new oqmlStatus(dot, "%s: collection expected, got %s",
00894                           coll->getOid().toString(),
00895                           coll->getClass()->getName());
00896 
00897   if (coll->asCollArray()) {
00898     oqmlAtomList *al;
00899     s = oqmlArray::evalMake(db, ctx, coll, d->array, oqml_True, &al);
00900     if (s) return s;
00901     alist->append(al);
00902     return oqmlSuccess;
00903   }
00904 
00905   OidArray oid_arr;
00906   Status is = coll->asCollection()->getElements(oid_arr);
00907   if (is)
00908     return new oqmlStatus(dot, is);
00909 
00910   for (int i = 0; i < oid_arr.getCount(); i++)
00911     alist->append(new oqmlAtom_oid(oid_arr[i]));
00912 
00913   return oqmlSuccess;
00914 }
00915 
00916 oqmlStatus *
00917 oqmlDotContext::eval_terminal(Database *db, oqmlContext *ctx, Object *o, 
00918                               oqmlAtom *value, int n, oqmlAtomList **alist)
00919 {
00920   oqmlDotDesc *d = &desc[n];
00921   Status is = Success;
00922   oqmlStatus *s;
00923   int s_ind, e_ind, ind;
00924 
00925   if (d->qlmth)
00926     return ((oqmlMethodCall *)d->qlmth)->perform(db, ctx,
00927                                                  o, o->getOid(), o->getClass(),
00928                                                  alist);
00929   const Attribute *xattr;
00930 
00931   xattr = o->getClass()->getAttribute(d->attrname);
00932 
00933   if (!xattr) {
00934     if (n > 0 && oqml_is_subclass(desc[n-1].cls, o->getClass()))
00935       return oqmlSuccess;
00936     return new oqmlStatus(dot, not_found_fmt,
00937                           d->attrname, o->getClass()->getName());
00938   }
00939 
00940   if (!d->attr) {
00941     s = d->make(db, ctx, dot, xattr, d->array, d->attrname, 0);
00942     if (s) return s;
00943     s = dot->check(db, this);
00944     if (s) return s;
00945   }
00946 
00947   int nb;
00948 
00949   d->mod = &xattr->getTypeModifier();
00950 
00951   if (d->mode == Attribute::composedMode)
00952     nb = d->mod->dims[d->mod->ndims-1];
00953   else
00954     nb = 1;
00955 
00956   s = d->evalInd(dot, db, ctx, s_ind, e_ind, (value ? oqml_False : oqml_True),
00957                  (value ? oqml_True : oqml_False));
00958   if (s) return s;
00959 
00960   Data data = d->e_data;
00961 
00962   oqmlATOMTYPE atom_type = dot_type.type;
00963   for (ind = s_ind; ind <= e_ind; ind++) {
00964     OQML_CHECK_INTR();
00965     memset(data, 0, d->key_len);
00966     Bool isnull = False;
00967 
00968     if (value)
00969       {
00970         Data val;
00971         unsigned char buff[16];
00972         Size size;
00973         int len;
00974           
00975 #if 1
00976         if (value->as_oid() &&
00977             !(d->isref || xattr->getClass()->asOidClass() ||
00978               xattr->getClass()->asCollectionClass()))
00979           return new oqmlStatus(dot, "cannot assign an oid to a "
00980                                 "literal attribute");
00981 #endif
00982 
00983         size = sizeof(buff);
00984         if (value->getData(buff, &val, size, len, d->cls)) {
00985           if (val) {
00986             if (nb > 0 && strlen((char *)val) >= nb)
00987               return new oqmlStatus(dot, "out of bound character array"
00988                                     "'%s': "
00989                                     "maximum allowed is %d <got %d>",
00990                                     val, nb, strlen((char *)val));
00991             else {
00992               int len = strlen((char *)val);
00993               if (len >= d->key_len) {
00994                 d->make_key(len+1);
00995                 data = d->e_data;
00996               }
00997 
00998               strcpy((char *)data, (char *)val);
00999             }
01000 
01001             if (nb < 0)
01002               nb = strlen((char *)data) + 1;
01003           }
01004           else
01005             data = buff;
01006               
01007           oqmlBool enough;
01008           is = oqml_check_vardim(xattr, o, OQMLBOOL(value), enough, ind,
01009                                  nb, xattr->getTypeModifier().pdims,
01010                                  OQMLCOMPLETE(value));
01011 
01012           if (is)
01013             return new oqmlStatus(dot, is);
01014 
01015           if (!enough) {
01016             if (value)
01017               continue;
01018             else
01019               break;
01020           }
01021 
01022           if (d->isref && !d->is_coll) {
01023             if (!OQML_IS_OID(value)) {
01024               is = xattr->setValue((Agregat *)o, data, nb, ind);
01025               // added the 17/05/01
01026               if (OQML_IS_NULL(value) && !is) {
01027                 Oid xoid;
01028                 is = xattr->setOid((Agregat *)o, (Oid *)&xoid,
01029                                    nb, ind);
01030               }
01031               atom_type = oqmlATOM_OBJ;
01032             }
01033             else
01034               is = xattr->setOid((Agregat *)o, (Oid *)data, nb, ind);
01035           }
01036           else if (oqml_is_getcount(d->array)) {
01037             if (!xattr->isVarDim())
01038               return new oqmlStatus(dot, "cannot set dimension "
01039                                     "on a non variable dimension "
01040                                     "attribute");
01041 
01042             if (oqml_is_wholecount(d->array))
01043               return new oqmlStatus(dot,
01044                                     "cannot set multiple dimension");
01045               
01046               
01047             if (!OQML_IS_INT(value))
01048               return oqmlStatus::expected(dot, "integer",
01049                                           value->type.getString());
01050 
01051             Size size = OQML_ATOM_INTVAL(value);
01052             Status is = xattr->setSize(o, size);
01053             if (is)
01054               return new oqmlStatus(dot, is);
01055             // test added the 28/12/00 for non persistent object
01056             if (o->getOid().isValid()) {
01057               is = o->realize();
01058               if (is) return new oqmlStatus(dot, is);
01059             }
01060             (*alist)->append(new oqmlAtom_int(size));
01061             continue;
01062           }
01063           else if (d->is_coll) {
01064             Collection *coll = 0;
01065             if (xattr->isIndirect()) {
01066               Oid coll_oid;
01067               is = xattr->getOid((Agregat *)o, &coll_oid, 1, 0);
01068               if (!is)
01069                 is = db->loadObject(coll_oid, (Object *&)coll);
01070             }
01071             else
01072               is = xattr->getValue((Agregat *)o, (Data *)&coll, 1, 0);
01073 
01074             if (!is) {
01075               if (!coll->asCollArray())
01076                 return new oqmlStatus(dot,
01077                                       "array expected, got %s",
01078                                       coll->getClass()->getName());
01079                       
01080               if (value->as_null() ||
01081                   !OQML_ATOM_OIDVAL(value).isValid())
01082                 is = coll->asCollArray()->suppressAt(ind);
01083               else
01084                 is = coll->asCollArray()->insertAt
01085                   (ind, OQML_ATOM_OIDVAL(value));
01086 
01087               if (!is && xattr->isIndirect()) {
01088                 // test added the 28/12/00 for non persistent object
01089                 if (coll->getOid().isValid())
01090                   is = coll->realize();
01091               }
01092             }
01093 
01094             if (xattr->isIndirect() && coll)
01095               coll->release();
01096           }
01097           else {
01098             if (OQML_IS_NULL(value)) {
01099               /*
01100               if (xattr->getClass()->asCollectionClass()) {
01101                 Oid null_oid;
01102                 is = xattr->setOid((Agregat *)o, (Oid *)&null_oid, nb, ind);
01103               }
01104               else
01105               */
01106                 return new oqmlStatus(dot, "cannot set to NULL");
01107             }
01108             else if (value->as_oid()) {
01109               Object *vo = 0;
01110               Oid voi = OQML_ATOM_OIDVAL(value);
01111               s = oqmlObjectManager::getObject(dot, db, &voi, vo, oqml_True, oqml_True);
01112               if (s)
01113                 return s;
01114               is = xattr->setValue((Agregat *)o, (Data)&vo, nb, ind);
01115               atom_type = oqmlATOM_OID;
01116             }
01117             else
01118               is = xattr->setValue((Agregat *)o, data, nb, ind);
01119           }
01120               
01121           if (is)
01122             return new oqmlStatus(dot, is);
01123 
01124           if (desc[n-1].isref) {
01125             // test added the 28/12/00 for non persistent object
01126             if (o->getOid().isValid()) {
01127               is = o->realize();
01128 
01129               if (is)
01130                 return new oqmlStatus(dot, is);
01131             }
01132           }
01133         }
01134       }
01135     else if (oqml_is_getcount(d->array)) {
01136       Size size;
01137       if (xattr->isVarDim()) {
01138         Status is = xattr->getSize(o, size);
01139         if (is)
01140           return new oqmlStatus(dot, is);
01141       }
01142       else if (!d->mod->ndims)
01143         size = 0;
01144       else
01145         size = d->mod->dims[0];
01146 
01147       if (oqml_is_wholecount(d->array)) {
01148         oqmlAtomList *l = new oqmlAtomList();
01149         l->append(new oqmlAtom_int(size));
01150         for (int i = 1; i < d->mod->ndims; i++)
01151           l->append(new oqmlAtom_int(d->mod->dims[i]));
01152 
01153         (*alist)->append(new oqmlAtom_list(l));
01154       }
01155       else
01156         (*alist)->append(new oqmlAtom_int(size));
01157     }
01158     else {
01159       if (d->isref) {
01160         is = xattr->getValue((Agregat *)o, (Data *)data, nb, ind,
01161                              &isnull);
01162         if (!is) {
01163           Object *tmp;
01164           mcp(&tmp, data, sizeof(Object *));
01165           if (tmp)
01166             atom_type = oqmlATOM_OBJ;
01167           else
01168             is = xattr->getOid((Agregat *)o, (Oid *)data,
01169                                nb, ind);
01170         }
01171       }
01172       else if (xattr->isVarDim() && d->mode == Attribute::composedMode)
01173         is = xattr->getValue((Agregat *)o, (Data *)&data,
01174                              Attribute::directAccess, ind, &isnull);
01175       else
01176         is = xattr->getValue((Agregat *)o, (Data *)data, nb, ind,
01177                              &isnull);
01178 
01179       if (is) {
01180         if (xattr->isVarDim()) {
01181           if (value)
01182             continue;
01183           else
01184             break;
01185         }
01186       }
01187 
01188       if (is)
01189         return new oqmlStatus(dot, is);
01190     }
01191       
01192     // && ... added the 16/2/00
01193     if (!is && !oqml_is_getcount(d->array)) {
01194       if (d->is_coll && !value) {
01195         if (!isnull) {
01196           s = make_contents(d, dot, db, ctx,
01197                             oqmlAtom::make_atom
01198                             (data, atom_type,
01199                              (dot_type.cls ? dot_type.cls :
01200                               xattr->getClass())),
01201                             *alist);
01202           if (s) return s;
01203         }
01204       }
01205       else if (isnull)
01206         (*alist)->append(new oqmlAtom_null);
01207       else
01208         (*alist)->append(oqmlAtom::make_atom(data, atom_type,
01209                                              (dot_type.cls ? dot_type.cls :
01210                                               xattr->getClass())));
01211     }
01212   }
01213   
01214   return oqmlSuccess;
01215 }
01216 
01217 #ifdef OPTIM_TVALUE
01218 oqmlStatus *
01219 oqmlDotContext::eval_terminal(Database *db, oqmlContext *ctx,
01220                               const Oid &oid, int n, oqmlAtomList **alist)
01221 {
01222   oqmlDotDesc *d = &desc[n];
01223   Status is;
01224   oqmlStatus *s;
01225   int s_ind, e_ind, ind;
01226 
01227   Class *cls;
01228   is = db->getObjectClass(oid, cls);
01229   if (is) return new oqmlStatus(dot, is);
01230 
01231   const Attribute *xattr;
01232   xattr = cls->getAttribute(d->attrname);
01233 
01234   if (!xattr)
01235     {
01236       if (n > 0 && oqml_is_subclass(desc[n-1].cls, cls))
01237         return oqmlSuccess;
01238       return new oqmlStatus(dot, not_found_fmt,
01239                             d->attrname, cls->getName());
01240     }
01241 
01242   if (!d->attr)
01243     {
01244       s = d->make(db, ctx, dot, xattr, d->array, d->attrname, 0);
01245       if (s) return s;
01246       s = dot->check(db, this);
01247       if (s) return s;
01248     }
01249 
01250   int nb;
01251 
01252   d->mod = &xattr->getTypeModifier();
01253 
01254   if (d->mode == Attribute::composedMode)
01255     nb = d->mod->dims[d->mod->ndims-1];
01256   else
01257     nb = 1;
01258 
01259   //s = d->evalInd(dot, db, ctx, s_ind, e_ind, oqml_True, oqml_False);
01260   s = d->evalInd(dot, db, ctx, s_ind, e_ind, oqml_False, oqml_False);
01261   if (s) return s;
01262 
01263   Data data = d->e_data;
01264 
01265   oqmlATOMTYPE atom_type = dot_type.type;
01266   for (ind = s_ind; ind <= e_ind; ind++)
01267     {
01268       OQML_CHECK_INTR();
01269       memset(data, 0, d->key_len);
01270       Bool isnull = False;
01271 
01272       if (xattr->isVarDim() && d->mode == Attribute::composedMode)
01273         is = xattr->getTValue(db, oid, (Data *)&data,
01274                               Attribute::wholeData, ind, &isnull);
01275       else
01276         is = xattr->getTValue(db, oid, (Data *)data, nb, ind, &isnull);
01277 
01278       // disconnected the 19/06/01
01279       /*
01280       if (is && xattr->isVarDim())
01281         break;
01282       */
01283       
01284       if (is)
01285         return new oqmlStatus(dot, is);
01286       
01287       if (d->is_coll)
01288         {
01289           if (!isnull)
01290             {
01291               s = make_contents(d, dot, db, ctx,
01292                                 oqmlAtom::make_atom
01293                                 (data, atom_type,
01294                                  (dot_type.cls ? dot_type.cls :
01295                                   xattr->getClass())),
01296                                 *alist);
01297               if (s) return s;
01298             }
01299         }
01300       else if (isnull)
01301         (*alist)->append(new oqmlAtom_null);
01302       else
01303         {
01304           (*alist)->append(oqmlAtom::make_atom(data, atom_type,
01305                                                (dot_type.cls ? dot_type.cls :
01306                                                 xattr->getClass())));
01307           if (xattr->isVarDim() && d->mode == Attribute::composedMode)
01308             free(data);
01309         }
01310     }
01311   
01312   return oqmlSuccess;
01313 }
01314 #endif
01315 
01316 oqmlStatus *
01317 oqmlDotContext::eval_perform(Database *db, oqmlContext *ctx, Object *o, 
01318                              oqmlAtom *value, int n, oqmlAtomList **alist)
01319 {
01320   if (!o)
01321     return oqmlSuccess;
01322 
01323   oqmlStatus *s;
01324 
01325   assert(!dot || dot->constructed);
01326 
01327 #if DBG_LEVEL > 1
01328   printf("oqmlDotContext::eval_perform(count = %d, n = %d)\n",
01329          count, n);
01330 #endif
01331 
01332   if (n < count - 1)
01333     {
01334       s = eval_middle(db, ctx, o, value, n, alist);
01335       if (s) return s;
01336       return oqmlSuccess;;
01337     }
01338 
01339   s = eval_terminal(db, ctx, o, value, n, alist);
01340   if (s) return s;
01341 #if DBG_LEVEL > 1
01342   printf("oqmlDotContext::eval_perform -> alist %p\n", *alist);
01343   fflush(stdout);
01344 #endif
01345   return oqmlSuccess;
01346 }
01347 
01348 oqmlStatus *
01349 oqmlDotContext::eval_object(Database *db, oqmlContext *ctx, 
01350                             oqmlAtom *atom, oqmlAtom *value, int from,
01351                             oqmlAtomList **alist)
01352 {
01353   Object *o;
01354   if (OQML_IS_OID(atom))
01355     {
01356       Oid oid = OQML_ATOM_OIDVAL(atom);
01357 
01358       if (!oid.isValid())
01359         return oqmlSuccess;
01360 #ifdef OPTIM_TVALUE
01361       oqmlDotDesc *d = &desc[from];
01362       
01363       if (!value && from >= count - 1 && !d->qlmth &&
01364           !oqml_is_getcount(d->array) &&
01365           (!d->attr || d->attr->isIndirect() ||
01366            d->attr->getClass()->asBasicClass() ||
01367            d->attr->getClass()->asEnumClass()))
01368         return eval_terminal(db, ctx, oid, from, alist);
01369 #endif
01370     }
01371 
01372   oqmlStatus *s = oqmlObjectManager::getObject(dot, db, atom, o, oqml_False);
01373 
01374   if (s) return s;
01375   if (!o) return oqmlSuccess;
01376 
01377   s = eval_perform(db, ctx, o, value, from, alist);
01378   if (!s && value)
01379     {
01380       //printf("Realizing object '%s'\n", o->getOid().toString());
01381       // test added the 28/12/00 for non persistent object
01382       if (o->getOid().isValid())
01383         {
01384           Status is = o->realize();
01385           if (is)
01386             {
01387               oqmlObjectManager::releaseObject(o);
01388               return new oqmlStatus(dot, is);
01389             }
01390         }
01391     }
01392   oqmlObjectManager::releaseObject(o);
01393   return s;
01394 }
01395 
01396 oqmlStatus *
01397 oqmlDotContext::eval_struct(Database *db, oqmlContext *ctx, 
01398                             oqmlAtom_struct *astruct, oqmlAtom *value,
01399                             int from, oqmlAtomList **alist)
01400 {
01401   oqmlDotDesc *d = &desc[from];
01402   int idx;
01403   oqmlAtom *v = astruct->getAtom(d->attrname, idx);
01404 
01405   if (!v)
01406     return new oqmlStatus(dot, "unknown attribute name '%s' in structure "
01407                           "'%s'", d->attrname, astruct->getString());
01408   if (count <= from+1)
01409     {
01410       if (value)
01411         {
01412           astruct->setAtom(value, idx, 0);
01413           (*alist)->append(value);
01414           return oqmlSuccess;
01415         }
01416       
01417       (*alist)->append(v ? v->copy() : (oqmlAtom *)0);
01418       return oqmlSuccess;
01419     }
01420   
01421   if (!v)
01422     return oqmlStatus::expected(dot, "oid or struct", "nil");
01423 
01424   if (OQML_IS_OBJECT(v))
01425     return eval_object(db, ctx, v, value, from+1, alist);
01426 
01427   if (OQML_IS_STRUCT(v))
01428     return eval_struct(db, ctx, v->as_struct(), value, from+1, alist);
01429 
01430   return oqmlStatus::expected(dot, "oid or struct", v->type.getString());
01431 }
01432 
01433 oqmlStatus *
01434 oqmlDotContext::eval(Database *db, oqmlContext *ctx, oqmlAtom *atom,
01435                      oqmlAtom *value, oqmlAtomList **alist)
01436 {
01437   assert(atom);
01438   oqmlStatus *s;
01439 
01440   if (value)
01441     {
01442       if (!value->type.cmp(dot_type) &&
01443           dot_type.type != oqmlATOM_UNKNOWN_TYPE &&
01444           !(dot_type.type == oqmlATOM_OID || dot_type.type == oqmlATOM_OBJ ||
01445             value->type.type == oqmlATOM_NULL))
01446         return new oqmlStatus(dot, "assignation operator: %s expected, got %s.",
01447                               dot_type.getString(), value->type.getString());
01448     }
01449 
01450   if (OQML_IS_OBJECT(atom))
01451     return eval_object(db, ctx, atom, value, 1, alist);
01452 
01453   if (OQML_IS_STRUCT(atom))
01454     return eval_struct(db, ctx, atom->as_struct(), value, 1, alist);
01455 
01456   // added 28/02/00
01457   if ((OQML_IS_NULL(atom) || atom->as_nil()) && ctx->isWhereContext())
01458     return oqmlSuccess;
01459   // ...
01460 
01461   /*
01462   // added 9/07/06
01463   if (OQML_IS_NULL(atom) || atom->as_nil())
01464     return oqmlSuccess;
01465   */
01466 
01467   return oqmlStatus::expected(dot, "oid or struct", atom->type.getString());
01468 }
01469 
01470 oqmlStatus *
01471 oqmlDotContext::eval_terminal(Database *db, oqmlContext *ctx, 
01472                              Oid *data_oid, int offset, Bool isref,
01473                              int n, oqmlAtomList **alist)
01474 {
01475   oqmlDotDesc *d = &desc[n];
01476   Data data = d->e_data;
01477   Status is;
01478   oqmlStatus *s;
01479   int s_ind, e_ind, ind;
01480 
01481   s = d->evalInd(dot, db, ctx, s_ind, e_ind, oqml_True, oqml_False);
01482   if (s) return s;
01483 
01484   const Attribute *xattr = 0;
01485 
01486   if (isref)
01487     {
01488       Class *cls;
01489 
01490       is = db->getObjectClass(*data_oid, cls);
01491       if (is)
01492         {
01493           is->print(utlogFDGet());
01494           return oqmlSuccess;
01495         }
01496 
01497       if (d->attrname)
01498         {
01499           xattr = cls->getAttribute(d->attrname);
01500 
01501           if (!xattr)
01502             {
01503               if (n > 0 && oqml_is_subclass(desc[n-1].cls, cls))
01504                 return oqmlSuccess;
01505               return new oqmlStatus(dot, not_found_fmt,
01506                                     d->attrname, cls->getName());
01507             }
01508         }
01509       else if (d->qlmth)
01510         return ((oqmlMethodCall *)d->qlmth)->perform(db, ctx,
01511                                                      0, *data_oid, cls, alist);
01512     }
01513   else
01514     {
01515       xattr = d->attr;
01516       if (!xattr && d->qlmth)
01517         return new oqmlStatus(dot, "cannot perform method call on non object instances");
01518     }
01519 
01520   d->mod = &xattr->getTypeModifier();
01521   int nb;
01522 
01523   if (d->mode == Attribute::composedMode)
01524     nb = d->mod->maxdims;
01525   else
01526     nb = 1;
01527   
01528 #if DBG_LEVEL > 2
01529   printf("oqmlDotContext::eval_terminal(%s, offset = %d, isref = %d, n = %d)\n",
01530          data_oid->getString(), offset, isref, n);
01531 #endif
01532 
01533   Bool isnull = False;
01534   for (ind = s_ind; ind <= e_ind; ind++)
01535     {
01536       OQML_CHECK_INTR();
01537       printf("!!! oqmlDotContext::getVal !!!\n");
01538       // could it be replaced by getTValue ??
01539       is = xattr->getVal(db, data_oid, data, offset, nb, ind, &isnull);
01540 
01541       if (is && xattr->isVarDim())
01542         continue;
01543 
01544       if (is)
01545         return new oqmlStatus(dot, is);
01546     }
01547   
01548   if (is == Success)
01549     {
01550       if (isnull)
01551         (*alist)->append(new oqmlAtom_null);
01552       else
01553         (*alist)->append(oqmlAtom::make_atom(data, dot_type.type,
01554                                              (dot_type.cls ? dot_type.cls :
01555                                               xattr->getClass())));
01556     }
01557   
01558   return oqmlSuccess;
01559 }
01560 
01561 oqmlDotContext::~oqmlDotContext()
01562 {
01563   idbFreeVect(desc, oqmlDotDesc, oqmlMAXDESC);
01564   delete tctx;
01565 #ifdef SYNC_GARB
01566   //delete tlist;
01567 #endif
01568 }
01569 
01570 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01571 //
01572 // oqmlDot methods
01573 //
01574 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01575 
01576 oqmlDot::oqmlDot(oqmlNode * _qleft, oqmlNode * _qright,
01577                  oqmlBool _isArrow) : oqmlNode(oqmlDOT)
01578 {
01579   qleft = _qleft;
01580   assert(qleft->getType() != oqmlDOT);
01581   qright = _qright;
01582   qlmth = 0;
01583   dot_ctx = 0;
01584   boolean_dot = False;
01585   boolean_node = False;
01586   constructed = oqml_False;
01587   populated = oqml_False;
01588   isArrow = _isArrow;
01589   requal_ident = 0;
01590 }
01591 
01592 oqmlStatus *
01593 oqmlDot::hasIndex(Database *db, oqmlContext *ctx, oqmlBool &hasOne)
01594 {
01595   oqmlBool wasEmpty;
01596   if (!dot_ctx)
01597     {
01598       oqmlStatus *s = complete(db, ctx);
01599       if (s) return s;
01600       wasEmpty = oqml_True;
01601     }
01602   else
01603     wasEmpty = oqml_False;
01604 
01605   // WARNING: in some case, dot_ctx->count == 0 that means that
01606   // one cannot decide whether this has an index or not!
01607   hasOne = dot_ctx->count > 1 ?
01608     OQMLBOOL(dot_ctx->desc[dot_ctx->count-1].idx_cnt) : oqml_False;
01609   return wasEmpty ? reinit(db, ctx) : oqmlSuccess;
01610 }
01611 
01612 oqmlDot::~oqmlDot()
01613 {
01614   delete dot_ctx;
01615   free(requal_ident);
01616 }
01617 
01618 oqmlDotContext *oqmlDot::getDotContext()
01619 {
01620   return dot_ctx;
01621 }
01622 
01623 oqmlStatus *
01624 oqmlDot::getAttrRealize(const Class *cls, const char *name,
01625                         const Attribute **attr)
01626 {
01627   *attr = (Attribute *)cls->getAttribute(name);
01628       
01629   if (*attr)
01630     return oqmlSuccess;
01631 
01632   unsigned int subclass_cnt, i, j;
01633   Class **subclasses;
01634   Status s;
01635   s = cls->getSubClasses(subclasses, subclass_cnt);
01636   if (s) return new oqmlStatus(this, s);
01637   int attr_cnt = 0;
01638   const Attribute **attrs = (const Attribute **)
01639     malloc(subclass_cnt*sizeof(const Attribute *));
01640   
01641   for (i = 0; i < subclass_cnt; i++)
01642     {
01643       const Attribute *xattr = subclasses[i]->getAttribute(name);
01644       if (xattr && xattr->getClassOwner()->compare(subclasses[i]))
01645         attrs[attr_cnt++] = xattr;
01646     }
01647 
01648   if (!attr_cnt)
01649     {
01650       free(attrs);
01651       // disconnected 28/12/00
01652       //return new oqmlStatus(this, not_found_fmt, name, cls->getName());
01653       return oqmlSuccess;
01654     }
01655 
01656   if (attr_cnt == 1)
01657     {
01658       *attr = attrs[0];
01659       free(attrs);
01660       return oqmlSuccess;
01661     }
01662 
01663   for (i = 0; i < attr_cnt; i++)
01664     {
01665       const Class *class_owner = attrs[i]->getClassOwner();
01666       for (j = 0; j < attr_cnt; j++)
01667         {
01668           if (i == j) continue;
01669           Bool is;
01670           s = attrs[j]->getClassOwner()->isSubClassOf(class_owner, &is);
01671           if (s) return new oqmlStatus(this, s);
01672           if (!is)
01673             break;
01674         }
01675 
01676       if (j == attr_cnt)
01677         {
01678           *attr = attrs[i];
01679           break;
01680         }
01681     }
01682 
01683   if (!*attr)
01684     {
01685       std::string x = std::string("ambiguous attribute '") + name + 
01686         "' in class '" + cls->getName() + "', candidates are: ";
01687       for (i = 0; i < attr_cnt; i++)
01688         x += std::string(i ? ", " : "") +
01689           attrs[i]->getClassOwner()->getName() + "::" + attrs[i]->getName();
01690       free(attrs);
01691       return new oqmlStatus(this, x.c_str());
01692     }
01693 
01694   free(attrs);
01695   return oqmlSuccess;
01696 }
01697 
01698 oqmlStatus *
01699 oqmlDot::getAttr(Database *db, oqmlContext *ctx, const Class *cls,
01700                  oqmlAtom *atom, const char *name, const Attribute **attr,
01701                  oqmlAtom **rcuratom)
01702 {
01703   *rcuratom = 0;
01704 
01705   if (atom)
01706     {
01707       if (OQML_IS_STRUCT(atom))
01708         {
01709           int idx;
01710           oqmlAtom *a = atom->as_struct()->getAtom(name, idx);
01711           if (!a)
01712             return new oqmlStatus(this,
01713                                   "unknown attribute name '%s' "
01714                                   "in structure '%s'", name,
01715                                   atom->as_struct()->getString());
01716           *rcuratom = a;
01717         }
01718       else if (OQML_IS_OBJECT(atom))
01719         {
01720           // test added this test 1/03/00
01721           if (!(OQML_IS_OID(atom) && !OQML_ATOM_OIDVAL(atom).isValid() &&
01722                 ctx->isWhereContext()))
01723             {
01724               Object *o;
01725               oqmlStatus *s = oqmlObjectManager::getObject(this, db, atom, o,
01726                                                            oqml_False);
01727               if (s) return s;
01728               cls = o->getClass();
01729               oqmlObjectManager::releaseObject(o);
01730             }
01731         }
01732       // added this test 28/02/00
01733       // added as_nil the 8/3/00
01734       else if (!(ctx->isWhereContext() &&
01735                  (OQML_IS_NULL(atom) || atom->as_nil())))
01736         return new oqmlStatus(this, "invalid item type for left dot part");
01737     }
01738   
01739   const char *attrname;
01740   const Class *attrcls;
01741   oqmlStatus *s = isScope(db, name, attrname, attrcls, attr);
01742   if (s) return s;
01743 
01744   if (attrname)
01745     {
01746       if (cls)
01747         {
01748           Status is;
01749           Bool isSub;
01750           is = attrcls->isSubClassOf(cls, &isSub);
01751           if (is) return new oqmlStatus(this, is);
01752           if (!isSub)
01753             return new oqmlStatus(this, "class '%s' is not a subclass of '%s'",
01754                                   attrcls->getName(), cls->getName());
01755         }
01756     }
01757   else if (cls)
01758     {
01759 #if DBG_LEVEL > 2
01760       printf("cls 0x%x [cnt=%d], *attr 0x%x, clname %s, name %s\n",
01761              cls, cls->getAttributesCount(), *attr, cls->getName(),
01762              name);
01763 #endif
01764       // WARNING: changed the 15/10/99
01765 #if 1
01766       return getAttrRealize(cls, name, attr);
01767 #else
01768       *attr = (Attribute *)cls->getAttribute(name);
01769       
01770       if (!*attr)
01771         return new oqmlStatus(this, not_found_fmt, name, cls->getName());
01772 #endif
01773     }
01774   else
01775     *attr = 0;
01776 
01777   return oqmlSuccess;
01778 }
01779 
01780 oqmlStatus *
01781 oqmlDot::isScope(Database *db, const char* x, const char*& attrname,
01782                  const Class *&cls, const Attribute **attr)
01783 {
01784   attrname = 0;
01785   cls = 0;
01786   if (!x)
01787     return oqmlSuccess;
01788 
01789   const char *r = strchr(x, ':');
01790   if (!r)
01791     return oqmlSuccess;
01792 
01793   const char *s;
01794 
01795   s = strchr(r+1, ':');
01796   if (!OQMLBOOL(s == r+1))
01797     return oqmlSuccess;
01798 
01799   static char clsname[128];
01800 
01801   strncpy(clsname, x, r-x);
01802   clsname[r-x] = 0;
01803   cls = db->getSchema()->getClass(clsname);
01804 
01805   if (!cls)
01806     return new oqmlStatus(this, "unknown class '%s'", clsname);
01807 
01808   attrname = s+1;
01809 
01810   const Attribute *xattr = cls->getAttribute(attrname);
01811   if (!xattr)
01812     return new oqmlStatus(this, "unknown attribute '%s' in class '%s'",
01813                           attrname, clsname);
01814 
01815   if (attr)
01816     *attr = xattr;
01817 
01818   return oqmlSuccess;
01819 }
01820 
01821 
01822 oqmlStatus *
01823 oqmlDot::oqmlDot_left(Database *db, oqmlContext *ctx,
01824                       const Class *cls,
01825                       oqmlAtom *curatom,
01826                       Attribute **attr,
01827                       oqmlAtom **rcuratom,
01828                       Class **castcls,
01829                       char **attrname)
01830 {
01831   const char *name;
01832   *attr = 0;
01833   oqmlStatus *s;
01834   oqmlTYPE type = qright->getType();
01835   *rcuratom = 0;
01836 
01837   /*
01838   printf("oqmlDot::Dot_left [%s [%s | %s]]\n",
01839          (const char *)toString(),
01840          (const char *)qleft->toString(), (const char *)qright->toString());
01841          */
01842 
01843   if (type == oqmlIDENT) {
01844     name = ((oqmlIdent *)qright)->getName();
01845     s = getAttr(db, ctx, cls, curatom, name, (const Attribute **)attr,
01846                 rcuratom);
01847     if (s) return s;
01848     *castcls = 0;
01849     // added 28/12/00
01850     if (!*attr) {
01851       // MIND, the code:
01852       // qlmth = new oqmlMethodCall(name, new oqml_List(), oqml_True);
01853       // *attrname = 0;
01854       // has been added on the 28/12/00 to accept constructs like
01855       // x.y where y is a method with no argument.
01856       // The problem is that, constructs like:
01857       // (select one Person).getDatabase().dbname;
01858       // did not work anymore.
01859       // So I disconnected this code on the 15/05/01
01860       *attrname = (char *)name;
01861     }
01862     else
01863       *attrname = (char *)name;
01864     
01865   }
01866   else if (type == oqmlCASTIDENT) {
01867     const char *modname;
01868     name = ((oqmlCastIdent *)qright)->getName(&modname);
01869     *attr = (Attribute *)cls->getAttribute(name);
01870 
01871     *castcls = db->getSchema()->getClass(modname);
01872     if (!*castcls)
01873       return new oqmlStatus(this, "class '%s' not found", modname);
01874 
01875     if (!*attr)
01876       return new oqmlStatus(this, not_found_fmt,
01877                             name, cls->getName());
01878     *attrname = (char *)name;
01879   }
01880   else if (type == oqmlDOT || type == oqmlARRAY) {
01881     s = qright->compile(db, ctx);
01882     if (s)
01883       return s;
01884     *attr = 0;
01885     *castcls = 0;
01886     *attrname = 0;
01887   }
01888   else if (type == oqmlCALL) {
01889     s = ((oqmlCall *)qright)->preCompile(db, ctx);
01890     if (s) return s;
01891 
01892     // added the 28/05/01 because of a memory leak detected by purify!
01893     if (qlmth) qlmth->unlock();
01894 
01895     qlmth = new oqmlMethodCall(((oqmlCall *)qright)->getName(),
01896                                ((oqmlCall *)qright)->getList());
01897     if (locked)
01898       qlmth->lock();
01899     *attr = 0;
01900     *castcls = 0;
01901     *attrname = 0;
01902   }
01903   else
01904     return new oqmlStatus(this, "invalid item type for left dot part");
01905 
01906   return oqmlSuccess;
01907 }
01908 
01909 oqmlStatus *
01910 oqmlDot::construct(Database *db, oqmlContext *ctx,
01911                    const Class *cls,
01912                    oqmlAtom *curatom,
01913                    oqmlDotContext **pdctx)
01914 {
01915   oqmlDotContext *dctx;
01916   oqmlStatus *s;
01917   Class *castcls;
01918 
01919 #if DBG_LEVEL > 1
01920   printf("oqmlDot::construct(%p)\n", *pdctx);
01921 #endif
01922   if (curatom)
01923     dctx = (*pdctx ? *pdctx : new oqmlDotContext(this, curatom));
01924   else
01925     dctx = (*pdctx ? *pdctx : new oqmlDotContext(this, cls));
01926   ctx->setDotContext(dctx);
01927           
01928   Attribute *attr;
01929   char *attrname;
01930 
01931   oqmlAtom *rcuratom;
01932   s = oqmlDot_left(db, ctx, cls, curatom, (Attribute **)&attr, &rcuratom,
01933                    &castcls, &attrname);
01934           
01935   if (s)
01936     {
01937       if (!*pdctx)
01938         delete dctx;
01939       return s;
01940     }
01941           
01942   s = dctx->add(db, ctx, attr, 0, attrname, rcuratom, castcls, qlmth);
01943           
01944   if (s)
01945     {
01946       if (!*pdctx)
01947         delete dctx;
01948       return s;
01949     }
01950           
01951   ctx->setDotContext(0);
01952 
01953   if (qlmth && !((oqmlMethodCall *)qlmth)->isCompiled())
01954     {
01955       s = qlmth->compile(db, ctx);
01956       if (s)
01957         return s;
01958     }
01959 
01960   *pdctx = dctx;
01961   constructed = oqml_True;
01962   return oqmlSuccess;
01963 }
01964 
01965 oqmlStatus *
01966 oqmlDot::check(Database *db, oqmlDotContext *dctx)
01967 {
01968   oqmlDotDesc *d = &dctx->desc[dctx->count-1];
01969   if (!d->attr) // added 17/02/99
01970     return oqmlSuccess;
01971 
01972   Class *cls = (Class *)d->attr->getClass();
01973 
01974   eval_type.cls = 0;
01975   eval_type.comp = OQMLBOOL(d->mode == Attribute::composedMode);
01976 
01977   Schema *m = db->getSchema();
01978   if (d->isref)
01979     {
01980       eval_type.type = oqmlATOM_OID;
01981       eval_type.cls = cls;
01982     }
01983   else if ((cls->asCharClass() || cls->asByteClass())
01984            && eval_type.comp)
01985     {
01986       eval_type.type = oqmlATOM_STRING;
01987       eval_type.comp = oqml_True;
01988     }
01989   else if (eval_type.comp)
01990     return new oqmlStatus(this,
01991                           "array attribute '%s': use the array operator '[]'",
01992                           d->attr->getName());
01993   else if (cls->asInt32Class() || cls->asInt16Class() ||
01994            cls->asInt64Class() || cls->asEnumClass() ||
01995            oqml_is_getcount(d->array))
01996     eval_type.type = oqmlATOM_INT;
01997   else if (cls->asCharClass() || cls->asByteClass())
01998     eval_type.type = oqmlATOM_CHAR;
01999   else if (!strcmp(cls->getName(), m->Float_Class->getName()))
02000     eval_type.type = oqmlATOM_DOUBLE;
02001   else if (!strcmp(cls->getName(), m->OidP_Class->getName()))
02002     eval_type.type = oqmlATOM_OID;
02003 #ifdef SUPPORT_CSTRING
02004   else if (!strcmp(cls->getName(), "ostring"))
02005     {
02006       eval_type.type = oqmlATOM_STRING;
02007       eval_type.comp = oqml_True;
02008     }
02009 #endif
02010 #ifdef OBJ_SUPPORT
02011   else
02012     eval_type.type = oqmlATOM_OBJ;
02013 #else
02014   else
02015     return new oqmlStatus(this,
02016                           "cannot deal with the literal non basic attribute '%s'",
02017                           d->attr->getName());
02018 #endif
02019 
02020   dctx->dot_type = eval_type;
02021   return oqmlSuccess;
02022 }
02023 
02024 oqmlStatus *
02025 oqmlDot::compile_start(Database *db, oqmlContext *ctx)
02026 {
02027   oqmlStatus *s;
02028 
02029   /*
02030   printf("oqmlDot::compile_start[%s [%s | %s]] -> %p left = %d [%p], right = %d [%p]\n",
02031          (const char *)toString(),
02032          (const char *)qleft->toString(), (const char *)qright->toString(),
02033          this, qleft->getType(), qleft,
02034          qright->getType(), qright);
02035          */
02036 
02037   if (qleft->getType() != oqmlIDENT)
02038     {
02039       if (qleft->getType() != oqmlCALL)
02040         {
02041           s = qleft->compile(db, ctx);
02042           if (s)
02043             return s;
02044         }
02045       dot_ctx = new oqmlDotContext(this, qleft);
02046       return oqmlSuccess;
02047     }
02048   else
02049     {
02050       oqmlDotContext *dctx;
02051       const char *name;
02052       const Class *cls = 0;
02053       oqmlAtomType at;
02054       const Attribute *attr;
02055 
02056       name = ((oqmlIdent *)qleft)->getName();
02057       
02058       oqmlAtom *atom;
02059           
02060       if (ctx->getSymbol(name, &at, &atom))
02061         {
02062           if (at.type == oqmlATOM_SELECT)
02063             {
02064 #if DBG_LEVEL > 1
02065               printf("oqmlDOT #1 '%s' => SYMBOL %s is a select [select_ctx %d]!\n", 
02066                      (const char *)toString(), name,
02067                      ctx->isSelectContext());
02068 #endif
02069               boolean_dot = False;
02070               boolean_node = True;
02071               return oqmlSuccess;
02072             }
02073           else
02074             {
02075               dot_ctx = new oqmlDotContext(this, name);
02076 #if DBG_LEVEL > 1
02077               printf("oqmlDOT #2 '%s' => SYMBOL %s is NOT a select!\n",
02078                      (const char *)toString(), name);
02079 #endif
02080               boolean_dot = True;
02081               boolean_node = False;
02082               return oqmlSuccess;
02083             }
02084         }
02085       else if (ctx->isSelectContext())
02086         {
02087           boolean_dot = False;
02088           cls = db->getSchema()->getClass(name);
02089 #if DBG_LEVEL > 1
02090           printf("oqmlDOT #3 '%s' => SYMBOL %s is a class ?\n",
02091                      (const char *)toString(), name);
02092 #endif
02093         }
02094       else
02095         {
02096           // added the 12/01/00
02097           dot_ctx = new oqmlDotContext(this, name);
02098 #if DBG_LEVEL > 1
02099           printf("oqmlDOT #4 '%s' => assuming SYMBOL %s is NOT a select\n",
02100                      (const char *)toString(), name);
02101 #endif
02102           boolean_dot = True;
02103           boolean_node = False;
02104           // ...
02105           return oqmlSuccess;
02106         }
02107 
02108 #if DBG_LEVEL > 1
02109       printf("oqmlDot::compile_start SelectContext %d, cls = %s <<%s>>\n",
02110              ctx->isSelectContext(), (cls ? cls->getName() : "NO"),
02111              (const char *)toString());
02112 #endif
02113 
02114       if (!cls)
02115         return new oqmlStatus(this, "unknown class '%s'", name);
02116 
02117       dctx = 0;
02118       s = construct(db, ctx, cls, 0, &dctx);
02119 
02120       if (s)
02121         return s;
02122 
02123       dot_ctx = dctx;
02124       return check(db, dot_ctx);
02125     }
02126   
02127 }
02128 
02129 oqmlStatus *
02130 oqmlDot::compile_continue(Database *db, oqmlContext *ctx,
02131                            oqmlDotContext *dctx)
02132 {
02133   oqmlStatus *s;
02134   const char *name;
02135   const Class *cls;
02136   oqmlAtomType at;
02137   const Attribute *attr;
02138   oqmlTYPE t = qleft->getType();
02139   oqmlDotDesc *d;
02140   Class *castcls;
02141 
02142   /*
02143   printf("oqmlDot::compile_continue [%s [%s | %s]]\n",
02144          (const char *)toString(),
02145          (const char *)qleft->toString(), (const char *)qright->toString());
02146   */
02147 
02148   if (t == oqmlIDENT || t == oqmlCASTIDENT)
02149     {
02150       d = &dctx->desc[dctx->count-1];
02151       
02152       cls = d->cls;
02153       attr = d->attr;
02154 
02155       if (t == oqmlCASTIDENT)
02156         {
02157           const char *modname;
02158           name = ((oqmlCastIdent *)qleft)->getName(&modname);
02159           castcls = db->getSchema()->getClass(modname);
02160           if (!castcls)
02161             return new oqmlStatus(this, "unknown class '%s'", modname);
02162         }
02163       else
02164         {
02165           name = ((oqmlIdent *)qleft)->getName();
02166           castcls = 0;
02167         }
02168       
02169       if (!cls)
02170         return new oqmlStatus(this, "class is unknown");
02171 
02172       oqmlAtom *rcuratom;
02173       s = getAttr(db, ctx, cls, d->curatom, name, &attr, &rcuratom);
02174       if (s) return s;
02175       // added 28/12/00 because getAttrRealize changed
02176       if (!attr) {
02177         return new oqmlStatus(this, not_found_fmt, name, cls ? cls->getName() : "<unknown>");
02178       }
02179       // ...
02180 
02181       s = dctx->add(db, ctx, attr, 0, (char *)name, rcuratom, castcls, 0);
02182       if (s) return s;
02183     }
02184   else if (t == oqmlARRAY)
02185     {
02186       s = qleft->compile(db, ctx);
02187       if (s) return s;
02188     }
02189   else if (t != oqmlCALL) // added the 19/02/99
02190     return new oqmlStatus(this, "cannot use a path expression "
02191                           "on a unidentificable atom.");
02192   else if (t == oqmlCALL)
02193     {
02194       s = ((oqmlCall *)qleft)->preCompile(db, ctx);
02195       if (s) return s;
02196 
02197       oqmlMethodCall *xmth = new oqmlMethodCall(((oqmlCall *)qleft)->getName(),
02198                                                 ((oqmlCall *)qleft)->getList());
02199       if (locked)
02200         xmth->lock();
02201       s = dctx->add(db, ctx, 0, 0, 0, 0, 0, xmth);
02202       if (s) return s;
02203     }
02204 
02205   d = &dctx->desc[dctx->count-1];
02206   cls = d->cls;
02207   oqmlAtom *curatom = d->curatom;
02208 
02209   char *attrname;
02210   oqmlAtom *rcuratom;
02211   s = oqmlDot_left(db, ctx, cls, curatom, (Attribute **)&attr, &rcuratom,
02212                    &castcls, &attrname);
02213   if (s)
02214     return s;
02215   
02216   s = dctx->add(db, ctx, attr, 0, attrname, rcuratom, castcls, qlmth);
02217   
02218   if (s)
02219     return s;
02220 
02221   if (qlmth && !((oqmlMethodCall *)qlmth)->isCompiled())
02222     {
02223       oqmlDotContext *dctx = ctx->getDotContext();
02224       ctx->setDotContext(0);
02225       s = qlmth->compile(db, ctx);
02226       ctx->setDotContext(dctx);
02227       if (s)
02228         return s;
02229     }
02230 
02231   return oqmlSuccess;
02232 }
02233 
02234 oqmlStatus *
02235 oqml_use_index(Database *db, oqmlContext *ctx, oqmlNode *node,
02236                oqmlDotContext *dctx, oqmlAtomList **alist,
02237                oqmlBool &indexUsed)
02238 {
02239   if (db->getVersionNumber() < MULTIIDX_VERSION)
02240     {
02241       indexUsed = oqml_False;
02242       return oqmlSuccess;
02243     }
02244 
02245   indexUsed = oqml_True;
02246   
02247   oqmlDotDesc *d = 0;
02248   for (int i = 1; i < dctx->count; i++)
02249     {
02250       d = &dctx->desc[i];
02251       if ((i != dctx->count-1 && d->isref) ||
02252           (d->array && !d->array->wholeRange))
02253         {
02254           indexUsed = oqml_False;
02255           return oqmlSuccess;
02256         }
02257     }
02258 
02259   if (!d || !d->idx_cnt)
02260     {
02261       indexUsed = oqml_False;
02262       return oqmlSuccess;
02263     }
02264 
02265   if (d->attr->getClass()->asCollectionClass() &&
02266       ((d->attr->isIndirect() && d->is_coll) ||
02267        (!d->attr->isIndirect() && !d->is_coll)))
02268     {
02269       indexUsed = oqml_False;
02270       return oqmlSuccess;
02271     }
02272 
02273   return oqmlIndexIter(db, ctx, node, dctx, d, alist);
02274 }
02275 
02276 oqmlStatus *
02277 oqmlDot::eval_realize(Database *db, oqmlContext *ctx,
02278                       const Class *cls,
02279                       oqmlAtom *atom, oqmlAtom *value, oqmlAtomList **alist)
02280 {
02281   oqmlDotContext *dctx;
02282   oqmlStatus *s;
02283 
02284 #if DBG_LEVEL > 1
02285   printf("oqmlDot::eval_realize(cls = %s)\n", cls ? cls->getName() : "NOCLASS");
02286 #endif
02287          
02288   dctx = 0;
02289   s = construct(db, ctx, cls, (cls ? 0 : atom), &dctx);
02290 
02291   if (s)
02292     return s;
02293 
02294   s = check(db, dctx);
02295   if (s)
02296     return s;
02297 
02298   delete dot_ctx->tctx;
02299   dot_ctx->tctx = dctx;
02300 
02301 #if DBG_LEVEL > 1
02302   printf("oqmlDot::eval_realize SelectContext %d [%s] atom = '%s'\n",
02303          ctx->isSelectContext(), cls->getName(),
02304          atom ? atom->getString() : "");
02305 #endif
02306 
02307   if (atom)
02308     return dctx->eval(db, ctx, atom, value, alist);
02309 
02310   oqmlBool indexUsed;
02311 
02312   if ((s = oqml_use_index(db, ctx, this, dctx, alist, indexUsed)) || indexUsed)
02313     return s;
02314 
02315   // should use an ClassIterator
02316   Iterator q((Class *)cls, True);
02317   
02318   Status is;
02319   if ((is = q.getStatus()) == Success)
02320     {
02321       IteratorAtom qatom;
02322       Bool found;
02323       
02324       for (;;)
02325         {
02326           OQML_CHECK_INTR(); // must put 'q' for args to delete it
02327           is = q.scanNext(&found, &qatom);
02328           
02329           if (is)
02330             return new oqmlStatus(this, is);
02331           
02332           if (!found)
02333             break;
02334           
02335           s = dctx->eval(db, ctx,
02336                          oqmlAtom::make_atom(qatom, (Class *)cls),
02337                          value, alist);
02338           if (s) return s;
02339           OQML_CHECK_MAX_ATOMS(*alist, ctx, 0);
02340         }
02341     }
02342   else
02343     return new oqmlStatus(this, is);
02344 
02345   return oqmlSuccess;
02346 }
02347 
02348 oqmlStatus *oqmlDot::compile(Database *db, oqmlContext *ctx)
02349 {
02350   delete dot_ctx;
02351   // added the 28/05/01 because of a memory leak detected by purify!
02352   if (qlmth) qlmth->unlock();
02353 
02354   qlmth = 0;
02355   dot_ctx = 0;
02356   boolean_dot = False;
02357   boolean_node = False;
02358   constructed = oqml_False;
02359   populated = oqml_False;
02360 
02361   oqmlDotContext *dctx = ctx->getDotContext();
02362 
02363 #if DBG_LEVEL > 1
02364   printf("oqmlDot::compile this = %p %s SelectContext = %d, DotContext = %p\n",
02365          this, (const char *)toString(), ctx->isSelectContext(), dctx);
02366 #endif
02367   oqmlStatus *s;
02368   if (!dctx)
02369     s = compile_start(db, ctx);
02370   else
02371     s = compile_continue(db, ctx, dctx);
02372 
02373 #if DBG_LEVEL > 1
02374   printf("oqmlDot::compile %s dot_ctx %p count %d\n",
02375          (const char *)toString(), dot_ctx, (dot_ctx ? dot_ctx->count : 0));
02376 #endif
02377   
02378   return s;
02379 }
02380 
02381 oqmlStatus *
02382 oqmlDot::reinit(Database *db, oqmlContext *ctx, oqmlBool mustCompile)
02383 {
02384   delete dot_ctx;
02385 
02386 #if DBG_LEVEL > 1
02387   printf("oqmlDot::reinit <<%s>>\n", (const char *)toString());
02388 #endif
02389 
02390   // added the 28/05/01 because of a memory leak detected by purify!
02391   if (qlmth) qlmth->unlock();
02392   qlmth = 0;
02393   dot_ctx = 0;
02394   boolean_dot = False;
02395   boolean_node = False;
02396   constructed = oqml_False;
02397   populated = oqml_False;
02398   return (mustCompile ? compile(db, ctx) : oqmlSuccess);
02399 }
02400 
02401 oqmlStatus *
02402 oqmlDot::complete(Database *db, oqmlContext *ctx)
02403 {
02404 #if DBG_LEVEL > 1
02405   printf("oqmlDot::complete(this = %p, %s)\n", this,
02406          (const char *)toString());
02407 #endif
02408   if (dot_ctx)
02409     return oqmlSuccess;
02410 
02411 #if DBG_LEVEL > 1
02412   assert(boolean_node);
02413   assert(qleft->getType() == oqmlIDENT);
02414 #endif
02415   const char *name = ((oqmlIdent *)qleft)->getName();
02416   oqmlAtom *atom;
02417   oqmlAtomType at;
02418   oqmlStatus *s;
02419 
02420   if (!ctx->getSymbol(name, &at, &atom))
02421     return new oqmlStatus(this, oqml_uninit_fmt, name);
02422 
02423   if (!atom)
02424     return new oqmlStatus(this, "internal select error");
02425 
02426   if (at.type != oqmlATOM_SELECT)
02427     {
02428       dot_ctx = new oqmlDotContext(this, name);
02429       boolean_dot = True;
02430       boolean_node = False;
02431       return oqmlSuccess;
02432     }
02433 
02434   oqmlNode *node = atom->as_select()->node;
02435 #if DBG_LEVEL > 1
02436   printf("Symbol %s is still a selectContext!\n", name);
02437 #endif
02438 
02439   oqmlNode *node_ident;
02440   
02441   /*
02442   if (!node)
02443     node_ident = 0;
02444     else */ if (node && node->getType() == oqmlIDENT)
02445     node_ident = node;
02446   else if ((ctx->isOrContext() || ctx->isAndContext()) &&
02447            atom->as_select()->node_orig->getType() == oqmlIDENT)
02448     node_ident = atom->as_select()->node_orig;
02449   else
02450     node_ident = 0;
02451 
02452   if (node_ident)
02453     {
02454       const Class *cls =
02455         db->getSchema()->getClass(((oqmlIdent *)node_ident)->getName());
02456       
02457       if (!cls)
02458         return new oqmlStatus(this, "unknown class '%s'",
02459                               ((oqmlIdent *)node_ident)->getName());
02460       
02461       s = construct(db, ctx, cls, 0, &dot_ctx);
02462       if (s) return s;
02463       return check(db, dot_ctx);
02464     }
02465 
02466   if (atom->as_select()->list)
02467     {
02468 #if DBG_LEVEL > 1
02469       printf("oqmlDot::complete() WARNING there is a list in atom select\n");
02470 #endif
02471       dot_ctx = new oqmlDotContext(this, node);
02472       return oqmlSuccess;
02473     }
02474 
02475   dot_ctx = new oqmlDotContext(this, node);
02476   return oqmlSuccess;
02477 }
02478 
02479 oqmlStatus *oqmlDot::eval(Database *db, oqmlContext *ctx,
02480                           oqmlAtomList **alist, oqmlComp *comp,
02481                           oqmlAtom *atom)
02482 {
02483   oqmlStatus *s;
02484 
02485 #if DBG_LEVEL > 1
02486   printf("oqmlDot::eval SelectContext = <<%s>>:\n", (const char *)toString());
02487 #endif
02488 
02489   s = complete(db, ctx);
02490   if (s) return s;
02491 
02492 #if DBG_LEVEL > 1
02493   printf("\tcomp %p\n\tdot_ctx->oqml %p\n\tdot_ctx->varname %p\n\t[%s]\n\ttctx %p\n",
02494          comp, dot_ctx->oqml, dot_ctx->varname, dot_ctx->oqml ?
02495          (const char *)dot_ctx->oqml->toString() : "",
02496          dot_ctx->tctx);
02497 #endif
02498 
02499   if (comp)
02500     return comp->makeIterator(db, dot_ctx, atom);
02501 
02502   if (dot_ctx->oqml || dot_ctx->varname)
02503     {
02504       s = eval_perform(db, ctx, 0, alist);
02505       if (s) return s;
02506 
02507       if (*alist && (*alist)->cnt > 1)
02508         *alist = new oqmlAtomList(new oqmlAtom_list(*alist));
02509 
02510       return oqmlSuccess;
02511     }
02512 
02513   s = eval_perform(db, ctx, 0, alist);
02514   if (s) return s;
02515 
02516   if (*alist && (*alist)->cnt > 1)
02517     *alist = new oqmlAtomList(new oqmlAtom_list(*alist));
02518 
02519   return oqmlSuccess;
02520 }
02521 
02522 oqmlStatus *oqmlDot::set(Database *db, oqmlContext *ctx, oqmlAtom *value,
02523                          oqmlAtomList **alist)
02524 {
02525   return eval_perform(db, ctx, value, alist);
02526 }
02527 
02528 oqmlArray *oqmlDot::make_right_array()
02529 {
02530   if (qright->getType() == oqmlARRAY)
02531     return (oqmlArray *)qright;
02532 
02533   if (qright->getType() == oqmlIDENT)
02534     {
02535       oqmlArray *array = new oqmlArray(qright);
02536       qright = array;
02537       return array;
02538     }
02539 
02540   if (qright->asDot())
02541     return qright->asDot()->make_right_array();
02542 
02543   return 0;
02544 }
02545 
02546 oqmlDot *oqmlDot::make_right_dot(const char *ident, oqmlBool _isArrow)
02547 {
02548   if (qright->getType() != oqmlDOT)
02549     {
02550       qright = new oqmlDot(qright, new oqmlIdent(ident), _isArrow);
02551       return this;
02552     }
02553 
02554   qright = qright->asDot()->make_right_dot(ident, _isArrow);
02555   return this;
02556 }
02557 
02558 oqmlDot *oqmlDot::make_right_call(oqml_List *list)
02559 {
02560   if (qright->getType() != oqmlDOT)
02561     {
02562       qright = new oqmlCall(qright, list);
02563       return this;
02564     }
02565 
02566   qright = qright->asDot()->make_right_call(list);
02567   return this;
02568 }
02569 
02570 oqmlAtomList *
02571 make_atom_coll_1(oqmlAtom_coll *a, oqmlAtomList *rlist)
02572 {
02573   if (!a)
02574     return rlist;
02575 
02576   if (a->as_list())
02577     return new oqmlAtomList(new oqmlAtom_list(rlist));
02578   if (a->as_bag())
02579     return new oqmlAtomList(new oqmlAtom_bag(rlist));
02580   if (a->as_set())
02581     return new oqmlAtomList(new oqmlAtom_set(rlist));
02582   if (a->as_array())
02583     return new oqmlAtomList(new oqmlAtom_array(rlist));
02584 
02585   return 0;
02586 }
02587 
02588 oqmlAtom *
02589 make_atom_coll_2(oqmlAtom_coll *a, oqmlAtomList *rlist)
02590 {
02591   if (a->as_list())
02592     return new oqmlAtom_list(rlist);
02593 
02594   if (a->as_bag())
02595     return new oqmlAtom_bag(rlist);
02596 
02597   if (a->as_set())
02598     return new oqmlAtom_set(rlist);
02599 
02600   if (a->as_array())
02601     return new oqmlAtom_array(rlist);
02602 
02603   return 0;
02604 }
02605 
02606 oqmlStatus *
02607 oqmlDot::eval_realize_list(Database *db, oqmlContext *ctx,
02608                            oqmlAtomList *list, oqmlAtom *value,
02609                            oqmlAtomList **alist, int level)
02610 {
02611   oqmlStatus *s;
02612   oqmlAtom *a = list->first;
02613 
02614   while (a)
02615     {
02616       oqmlAtom *next = a->next;
02617       if (a->as_coll())
02618         {
02619           if (!level)
02620             {
02621               s = eval_realize_list(db, ctx, a->as_coll()->list, value, alist,
02622                                     level+1);
02623               if (s) return s;
02624             }
02625           else
02626             {
02627               oqmlAtomList *rlist = new oqmlAtomList();
02628               s = eval_realize_list(db, ctx, OQML_ATOM_COLLVAL(a), value,
02629                                     &rlist, level+1);
02630               if (s) return s;
02631               (*alist)->append(make_atom_coll_2(a->as_coll(), rlist));
02632             }
02633         }
02634       else
02635         {
02636           Class *cls = a->type.cls;
02637           s = oqml_getclass(this, db, ctx, a, &cls);
02638           if (s) return s;
02639           
02640           s = eval_realize(db, ctx, cls, a, value, alist);
02641           if (s) return s;
02642         }
02643 
02644       a = next;
02645     }
02646 
02647   return oqmlSuccess;
02648 }
02649 
02650 oqmlStatus *oqmlDot::eval_perform(Database *db, oqmlContext *ctx,
02651                                   oqmlAtom *value, oqmlAtomList **xalist)
02652 {
02653   oqmlAtomList *rlist = 0;
02654   oqmlStatus *s;
02655 
02656 #if DBG_LEVEL > 1
02657   printf("oqmlDot::eval_perform -> %d\n", ctx->isSelectContext());
02658 #endif
02659   rlist = new oqmlAtomList();
02660 
02661   if (dot_ctx->varname)
02662     {
02663       const char *varname = dot_ctx->varname;
02664       
02665       oqmlAtomType at;
02666       oqmlAtom *a = 0;
02667       
02668       if (ctx->getSymbol(varname, &at, &a) && a) {
02669 #ifdef SYNC_GARB
02670         //delete dot_ctx->tlist;
02671 #endif
02672         dot_ctx->tlist = new oqmlAtomList(a->copy());
02673 
02674         Class *cls = at.cls;
02675 #if DBG_LEVEL > 1
02676         printf("oqmlDot::eval -> getSymbol(%s) -> %s [%s]\n",
02677                  varname, (a ? a->makeString(0) : "NullAtom"),
02678                cls ? cls->getName() : "noclass");
02679 #endif
02680         if (a->as_coll()) {
02681           s = eval_realize_list(db, ctx, OQML_ATOM_COLLVAL(a), value,
02682                                 &rlist, 0);
02683           if (s) return s;
02684 
02685           *xalist = make_atom_coll_1(a->as_coll(), rlist);
02686           return oqmlSuccess;
02687         }
02688 
02689         s = oqml_getclass(this, db, ctx, a, &cls, varname);
02690         if (s) return s;
02691           
02692         s = eval_realize(db, ctx, cls, a, value, &rlist);
02693         if (s) return s;
02694         
02695         *xalist = rlist;
02696         return oqmlSuccess;
02697       }
02698 
02699       return new oqmlStatus(this, oqml_uninit_fmt, varname);
02700     }
02701 
02702   if (dot_ctx->oqml)
02703     {
02704       oqmlAtomList *al;
02705 
02706       s = dot_ctx->oqml->compile(db, ctx);
02707       if (s) return s;
02708 
02709       s = dot_ctx->oqml->eval(db, ctx, &al);
02710       if (s) return s;
02711 
02712 #ifdef SYNC_GARB
02713       //delete dot_ctx->tlist;
02714 #endif
02715       dot_ctx->tlist = new oqmlAtomList(al);
02716 
02717       s = eval_realize_list(db, ctx, al, value, &rlist, 0);
02718       if (s) return s;
02719       *xalist = make_atom_coll_1(al->first ? al->first->as_coll() : 0, rlist);
02720       return oqmlSuccess;
02721     }
02722 
02723   s = eval_realize(db, ctx, dot_ctx->desc[0].cls, 0, value, &rlist);
02724   if (s) return s;
02725   *xalist = new oqmlAtomList(new oqmlAtom_bag(rlist));
02726   return oqmlSuccess;
02727 }
02728 
02729 static void
02730 oqml_append_realize(oqmlContext *ctx, oqmlAtom_select *atom_select,
02731                     oqmlAtomList *list)
02732 {
02733   oqmlAtomList *alist = atom_select->list;
02734 #if 0
02735   if (!alist) {
02736     oqmlDot::makeSet(ctx, atom_select,  list);
02737     return;
02738   }
02739 #else
02740   if (!alist)
02741     alist = atom_select->list = new oqmlAtomList();
02742 #endif
02743 
02744   oqmlAtom *a = (list ? list->first : 0);
02745 
02746   if (a && a->as_coll())
02747     a = a->as_coll()->list->first;
02748 
02749   while (a)
02750     {
02751       oqmlAtom *next = a->next;
02752       if (alist->first && alist->first->as_coll())
02753         alist->first->as_coll()->list->append(a);
02754       else
02755         alist->append(a);
02756 
02757       atom_select->appendCP(ctx);
02758       a = next;
02759     }
02760 }
02761 
02762 #define NEW_POPULATE_POLICY
02763 
02764 void
02765 oqmlDot::makeUnion(oqmlContext *ctx, oqmlAtom_select *atom_select, oqmlAtomList *list)
02766 {
02767 #if DBG_LEVEL > 1
02768   printf("oqmlDot::makeUnion symbol set to %s (should append ?) a->list=%p, "
02769          "list=%p\n", atom_select->getString(), atom_select->list, list);
02770 #endif
02771 
02772   oqml_append_realize(ctx, atom_select, list);
02773 }
02774 
02775 void
02776 oqmlDot::makeIntersect(oqmlContext *ctx, oqmlAtom_select *atom_select,
02777                        oqmlAtomList *list)
02778 {
02779 #if DBG_LEVEL > 1
02780   printf("oqmlDot::makeIntersect(%p, %d) ", list,
02781          //(list->first ? list->first->getString() : ""));
02782          (list->first ? list->cnt : 0));
02783 #endif
02784   if (!list->first || !atom_select->as_select()->list ||
02785       !OQML_IS_COLL(list->first))
02786     {
02787       atom_select->list = new oqmlAtomList();
02788       atom_select->setCP(ctx);
02789       return;
02790     }
02791 
02792   oqmlAtomList *rlist = new oqmlAtomList();
02793   oqmlAtomList *nlist =  atom_select->as_select()->list;
02794 
02795   oqmlAtom *a = ((oqmlAtom_coll *)list->first)->list->first;
02796   while (a) 
02797     {
02798       assert(OQML_IS_OID(a));
02799       oqmlBool found = oqml_False;
02800       oqmlAtom *next = a->next;
02801       Oid oid = OQML_ATOM_OIDVAL(a);
02802       oqmlAtom *na = nlist->first;
02803       while (na)
02804         {
02805           assert(OQML_IS_OID(na));
02806           if (oid == OQML_ATOM_OIDVAL(na))
02807             {
02808               found = oqml_True;
02809               break;
02810             }
02811           na = na->next;
02812         }
02813       
02814       if (found) {
02815         rlist->append(a);
02816         atom_select->appendCP(ctx);
02817       }
02818       a = next;
02819     }
02820   
02821   atom_select->list = rlist;
02822 }
02823 
02824 void
02825 oqmlDot::makeSet(oqmlContext *ctx, oqmlAtom_select *atom_select, oqmlAtomList *list)
02826 {
02827   if (list->first && OQML_IS_COLL(list->first))
02828     atom_select->list = OQML_ATOM_COLLVAL(list->first);
02829   else
02830     atom_select->list = list;
02831 
02832   atom_select->setCP(ctx);
02833 }                   
02834 
02835 oqmlStatus *
02836 oqmlDot::populate(Database *db, oqmlContext *ctx, oqmlAtomList *list,
02837                   oqmlBool _makeUnion)
02838 {
02839   assert(qleft->getType() == oqmlIDENT);
02840 
02841   const char *name = ((oqmlIdent *)qleft)->getName();
02842 
02843 #if DBG_LEVEL > 1
02844   printf("\noqmlDot::populate dot=%p symbol '%s' "
02845          "<<%s>> -> list_cnt=%d (%s) populated=%d, "
02846          "boolean_node=%d, and_ctx=%d, or_ctx=%d, makeunion=%d\n",
02847          this, name, (const char *)toString(),
02848          (list && list->first && OQML_IS_COLL(list->first) ?
02849           OQML_ATOM_COLLVAL(list->first)->cnt : 0),
02850          (list ? (const char *)list->getString() : ""),
02851          populated,
02852          boolean_node, ctx->isAndContext(), ctx->isOrContext(),
02853          _makeUnion);
02854 #endif
02855   
02856   if (!list || !boolean_node || (populated && !_makeUnion))
02857     return oqmlSuccess;
02858 
02859   oqmlAtom *atom = 0;
02860   ctx->getSymbol(name, 0, &atom);
02861 
02862   assert(atom && atom->as_select());
02863 
02864   oqmlAtom_select *atom_select = atom->as_select();
02865 
02866   if (ctx->isOrContext() || _makeUnion)
02867     makeUnion(ctx, atom_select, list);
02868   else if (ctx->isAndContext())
02869     makeIntersect(ctx, atom_select, list);
02870   else
02871     makeSet(ctx, atom_select, list);
02872 
02873   oqmlStatus *s = ctx->setSymbol(name, &atom_select->type,
02874                                  atom_select, oqml_False);
02875   if (s) return s;
02876 
02877   atom_select->as_select()->node = 0;
02878   populated = oqml_True;
02879   return oqmlSuccess;
02880 }
02881 
02882 void oqmlDot::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
02883 {
02884   *at = eval_type;
02885 }
02886 
02887 oqmlBool oqmlDot::isConstant() const
02888 {
02889   return OQMLBOOL(qleft->isConstant() && qright->isConstant());
02890 }
02891 
02892 void
02893 oqmlDot::setIndexHint(oqmlContext *ctx, oqmlBool indexed)
02894 {
02895   if (qleft->asDot())
02896     qleft->asDot()->setIndexHint(ctx, indexed);
02897 
02898   if (qleft->getType() == oqmlIDENT)
02899     {
02900       oqmlAtom *atom;
02901           
02902       if (ctx->getSymbol(((oqmlIdent *)qleft)->getName(), 0, &atom) &&
02903           atom && atom->as_select())
02904         atom->as_select()->indexed = indexed;
02905     }
02906 }
02907 
02908 oqmlBool
02909 oqmlDot::hasIdent(const char *_ident)
02910 {
02911   return OQMLBOOL(qleft->hasIdent(_ident) ||
02912                   (qlmth && qlmth->hasIdent(_ident)));
02913 }
02914 
02915 const char *
02916 oqmlDot::getLeftIdent() const
02917 {
02918   if (qleft->asDot())
02919     return qleft->asDot()->getLeftIdent();
02920   if (qleft->asIdent())
02921     return qleft->asIdent()->getName();
02922 
02923   return (const char *)0;
02924 }
02925 
02926 void
02927 oqmlDot::replaceLeftIdent(const char *ident, oqmlNode *node, oqmlBool &done)
02928 {
02929   /*
02930   printf("oqmlDot::replaceLeftIdent(%s, %s, %s, dot_context = %p)\n",
02931          ident, (const char *)toString(),
02932          (const char *)node->toString(),
02933          dot_ctx);
02934          */
02935   
02936   if (qleft->asDot())
02937     qleft->asDot()->replaceLeftIdent(ident, node, done);
02938   else if (qleft->asIdent())
02939     {
02940       if (!strcmp(qleft->asIdent()->getName(), ident))
02941         {
02942           requal_ident = strdup(ident);
02943           done = oqml_True;
02944 
02945           if (node->asDot())
02946             {
02947               oqmlNode *nqleft = node->asDot()->qleft;
02948               oqmlNode *nqright = new oqmlDot(node->asDot()->qright, qright, oqml_False);
02949               nqleft->back = qleft;
02950               nqright->back = qright;
02951               qleft = nqleft;
02952               qright = nqright;
02953 
02954               if (isLocked())
02955                 qright->lock();
02956             }
02957           else
02958             {
02959               node->back = qleft;
02960               qleft = node;
02961             }
02962 
02963           if (isLocked())
02964             qleft->lock();
02965         }
02966     }
02967   else
02968     assert(0);
02969 }
02970 
02971 oqmlStatus *
02972 oqmlDot::requalify_back(Database *db, oqmlContext *ctx)
02973 {
02974   oqmlStatus *s = requalify_node_back(db, ctx, qleft);
02975   if (s) return s;
02976   return requalify_node_back(db, ctx, qright);
02977 }
02978 
02979 void
02980 oqmlDot::lock()
02981 {
02982   oqmlNode::lock();
02983   qleft->lock();
02984   qright->lock();
02985   if (qlmth) qlmth->lock();
02986 }
02987 
02988 void
02989 oqmlDot::unlock()
02990 {
02991   oqmlNode::unlock();
02992   qleft->unlock();
02993   qright->unlock();
02994   if (qlmth) qlmth->unlock();
02995 }
02996 
02997 std::string
02998 oqmlDot::toString(void) const
02999 {
03000   return qleft->toString() + (isArrow ? "->" : ".") + qright->toString()
03001     + oqml_isstat();
03002 }
03003 }

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