oqlcoll.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 <math.h>
00029 #include <assert.h>
00030 
00031 #include "oql_p.h"
00032 #define OQML_NEW_COLL
00033 
00034 namespace eyedb {
00035 
00036   //
00037   // TODO:
00038   // - remplacer les appels aux methodes ::usage par un status adequat.
00039   // - les functions xx_perform doivent avoir oqmlNode * en premier argument.
00040   //
00041 
00042   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00043   //
00044   // private utility methods
00045   //
00046   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00047 
00048   static oqmlStatus *
00049   append_perform(oqmlNode *node, Collection *coll, const Oid *oid,
00050                  Data data, int size, oqmlAtom *a,
00051                  oqmlAtomList *atom_coll, oqmlAtomList *alist);
00052 
00053   static oqmlStatus *
00054   oqml_check_coll_type(Collection *coll, oqmlATOMTYPE &t)
00055   {
00056     Bool isref;
00057     eyedblib::int16 dim;
00058     if (!coll->asCollection() || !coll->getClass()->asCollectionClass())
00059       return new oqmlStatus("object '%s' is not a collection",
00060                             coll->getOid().toString());
00061 
00062     const Class *coll_class =
00063       coll->getClass()->asCollectionClass()->getCollClass(&isref, &dim);
00064     const char *name = coll_class->getName();
00065   
00066     if (isref)
00067       t = oqmlATOM_OID;
00068     else if (dim > 1) {
00069       if (!strcmp(name, char_class_name))
00070         t = oqmlATOM_STRING;
00071       else {
00072         return new oqmlStatus("OQL cannot deal with collection of "
00073                               "non basic types");
00074       }
00075     }
00076     else if (!strcmp(name, int32_class_name) ||
00077              !strcmp(name, int16_class_name) ||
00078              !strcmp(name, int64_class_name))
00079       t = oqmlATOM_INT;
00080     else if (!strcmp(name, "char"))
00081       t = oqmlATOM_CHAR;
00082     else if (!strcmp(name, "float"))
00083       t = oqmlATOM_DOUBLE;
00084     else {
00085       t = oqmlATOM_OBJ;
00086     }
00087 
00088     return oqmlSuccess;
00089   }
00090       
00091   static oqmlStatus *
00092   oqml_coll_eval(oqmlNode *node, Database *db, oqmlContext *ctx,
00093                  oqmlAtom *a, oqmlAtomList *rlist, const Class *&cls,
00094                  Bool indexed = False)
00095   {
00096     oqmlStatus *s;
00097 
00098     if (!a)
00099       return oqmlStatus::expected(node, "oid or object", "nil");
00100 
00101     if (!OQML_IS_OBJECT(a))
00102       return oqmlStatus::expected(node, "oid or object", a->type.getString());
00103 
00104     Object *o;
00105     s = oqmlObjectManager::getObject(node, db, a, o, oqml_False);
00106     if (s) return s;
00107     if (!o) {
00108       return new oqmlStatus(node, "invalid null object");
00109     }
00110 
00111     cls = o->getClass();
00112     if (!cls->asCollectionClass()) {
00113       oqmlObjectManager::releaseObject(o);
00114       return oqmlStatus::expected(node, "collection", o->getClass()->getName());
00115     }
00116 
00117     oqmlATOMTYPE t;
00118 
00119     s = oqml_check_coll_type((Collection *)o, t);
00120 
00121     if (s) {
00122       oqmlObjectManager::releaseObject(o);
00123       return s;
00124     }
00125   
00126     // 13/09/05
00127 #if 1
00128     OQML_CHECK_INTR();
00129 #if 1
00130     Bool is_indexed = (indexed && o->asCollArray() && !ctx->isWhereContext()) ? True : False;
00131     CollectionIterator iter(o->asCollection(), is_indexed);
00132 
00133     Value v;
00134     int idx;
00135     for (int n = 0; iter.next(v); n++) {
00136       if (is_indexed && !(n & 1)) {
00137         idx = v.i;
00138         continue;
00139       }
00140 
00141       oqmlAtom *x;
00142       Value::Type type = v.getType();
00143       if (type == Value::tOid)
00144         x = new oqmlAtom_oid(*v.oid, (Class *)cls);
00145       else if (type == Value::tObject) {
00146         v.o->trace();
00147         x = oqmlObjectManager::registerObject(v.o->clone());
00148       }
00149       else if (type == Value::tString)
00150         x = new oqmlAtom_string(v.str);
00151       else if (type == Value::tInt)
00152         x = new oqmlAtom_int(v.i);
00153       else if (type == Value::tLong)
00154         x = new oqmlAtom_int(v.l);
00155       else if (type == Value::tChar)
00156         x = new oqmlAtom_char(v.c);
00157       else if (type == Value::tDouble)
00158         x = new oqmlAtom_double(v.d);
00159       else {
00160         oqmlObjectManager::releaseObject(o);
00161         return new oqmlStatus(node, "unsupported value type %s\n",
00162                               v.getStringType());
00163       }
00164 
00165       if (is_indexed)
00166         rlist->append(oqml_make_struct_array(db, ctx, idx, x));
00167       else
00168         rlist->append(x);
00169     }
00170 
00171 #else
00172     ValueArray val_arr;
00173     Status status = o->asCollection()->getElements(val_arr);
00174     if (status) {
00175       oqmlObjectManager::releaseObject(o);
00176       return new oqmlStatus(node, status);
00177     }
00178     OQML_CHECK_INTR();
00179     int count = val_arr.getCount();
00180     for (int n = 0; n < count; n++) {
00181       Value &v = val_arr[n];
00182       Value::Type type = v.getType();
00183       if (type == Value::tOid)
00184         rlist->append(new oqmlAtom_oid(*v.oid, (Class *)cls));
00185       else if (type == Value::tObject)
00186         rlist->append(oqmlObjectManager::registerObject(v.o));
00187       else if (type == Value::tString)
00188         rlist->append(new oqmlAtom_string(v.str));
00189       else if (type == Value::tInt)
00190         rlist->append(new oqmlAtom_int(v.i));
00191       else if (type == Value::tLong)
00192         rlist->append(new oqmlAtom_int(v.l));
00193       else if (type == Value::tChar)
00194         rlist->append(new oqmlAtom_char(v.c));
00195       else if (type == Value::tDouble)
00196         rlist->append(new oqmlAtom_double(v.d));
00197       else {
00198         oqmlObjectManager::releaseObject(o);
00199         return new oqmlStatus(node, "unsupported value type %s\n",
00200                               v.getStringType());
00201       }
00202     }
00203 #endif
00204 
00205     oqmlObjectManager::releaseObject(o);
00206     return oqmlSuccess;
00207 #else
00208     Iterator *q = new Iterator(o->asCollection(),
00209                                (indexed && o->asCollArray() && !ctx->isWhereContext()) ? True : False);
00210   
00211     if (q->getStatus()) {
00212       Status s = q->getStatus();
00213       delete q;
00214       return new oqmlStatus(node, s);
00215     }
00216 
00217     s = oqml_scan(ctx, q,       ((CollectionClass *)
00218                                  (o->getClass()))->getCollClass(), rlist, t);
00219 
00220     oqmlObjectManager::releaseObject(o);
00221     return s;
00222 #endif
00223   }
00224 
00225   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00226   //
00227   // oqmlCollection methods
00228   //
00229   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00230 
00231   oqmlCollection::oqmlCollection(oqmlNode *_location, oqml_CollSpec *_coll_spec,
00232                                  oqmlNode * _ql) : oqmlNode(oqmlCOLLECTION)
00233   {
00234     location = _location;
00235     coll_spec = _coll_spec;
00236     ql = _ql;
00237 
00238     if (!location)
00239       eval_type.type = oqmlATOM_OBJ;
00240     else
00241       eval_type.type = oqmlATOM_OID;
00242   }
00243 
00244   oqmlCollection::~oqmlCollection()
00245   {
00246     delete coll_spec;
00247   }
00248 
00249   oqmlStatus *oqmlCollection::compile(Database *db, oqmlContext *ctx)
00250   {
00251     Bool modify = False;
00252     const char *which = coll_spec->coll_type;
00253 
00254     if (!strcmp(which, "set"))
00255       what = collset;
00256     else if (!strcmp(which, "array"))
00257       what = collarray;
00258     else if (!strcmp(which, "bag"))
00259       what = collbag;
00260     else if (!strcmp(which, "list"))
00261       return new oqmlStatus(this, "list collection type '%s' is not yet "
00262                             "implemented");
00263     else
00264       return new oqmlStatus(this, "invalid collection type '%s'", which);
00265 
00266     const char *type_spec = coll_spec->type_spec;
00267     char *ident = coll_spec->ident;
00268 
00269     Bool isref = coll_spec->isref;
00270 
00271     Schema *m = db->getSchema();
00272 
00273     if (type_spec) {
00274       if (!strcmp(type_spec, "int"))
00275         cls = m->Int32_Class;
00276       else
00277         cls = m->getClass(type_spec);
00278 
00279       if (!cls)
00280         return new oqmlStatus(this, "unknown class '%s'",
00281                               type_spec);
00282     }
00283   
00284     if (coll_spec->coll_spec) {
00285       oqml_CollSpec *cs = coll_spec->coll_spec;
00286       oqml_CollSpec *coll_spec_arr[64];
00287       int coll_spec_cnt = 0;
00288 
00289       while (cs) {
00290         coll_spec_arr[coll_spec_cnt++] = cs;
00291         cs = cs->coll_spec;
00292       }
00293 
00294       char coll_typname[256];
00295       strcpy(coll_typname, coll_spec_arr[coll_spec_cnt-1]->type_spec);
00296 
00297       Class *mcoll = NULL;
00298 
00299       for (int i = coll_spec_cnt-1; i >= 0; i--) {
00300         cs = coll_spec_arr[i];
00301         cls = m->getClass(coll_typname);
00302 
00303         if (!cls)
00304           return new oqmlStatus(this, "unknown class '%s'",
00305                                 type_spec);
00306 
00307         if (!strcmp(cs->coll_type, "set"))
00308           mcoll = new CollSetClass(cls, (Bool)cs->isref);
00309         else if (!strcmp(cs->coll_type, "bag"))
00310           mcoll = new CollBagClass(cls, (Bool)cs->isref);
00311         else if (!strcmp(cs->coll_type, "array"))
00312           mcoll = new CollArrayClass(cls, (Bool)cs->isref);
00313         else if (!strcmp(cs->coll_type, "list"))
00314           mcoll = new CollListClass(cls, (Bool)cs->isref);
00315         else
00316           return new oqmlStatus(this, "invalid collection type '%s'",
00317                                 cs->coll_type);
00318 
00319         strcpy(coll_typname, mcoll->getName());
00320 
00321         if (!m->getClass(mcoll->getName())) {
00322           m->addClass(mcoll);
00323           modify = True;
00324         }
00325       }
00326 
00327       cls = mcoll;
00328     }
00329 
00330     atref.cls = 0;
00331     atref.comp = oqml_False;
00332 
00333     if (isref) {
00334       atref.type = oqmlATOM_OID;
00335       atref.cls = cls;
00336     }
00337     else if (cls->asInt16Class() || cls->asInt32Class() ||
00338              cls->asInt64Class() || cls->asEnumClass())
00339       atref.type = oqmlATOM_INT;
00340     else if (!strcmp(cls->getName(), m->Char_Class->getName())||
00341              !strcmp(cls->getName(), m->Byte_Class->getName()))
00342       atref.type = oqmlATOM_CHAR;
00343     else if (!strcmp(cls->getName(), m->Float_Class->getName()))
00344       atref.type = oqmlATOM_DOUBLE;
00345     else if (!strcmp(cls->getName(), m->OidP_Class->getName()))
00346       atref.type = oqmlATOM_OID;
00347     else {
00348       atref.type = oqmlATOM_OBJ;
00349       atref.cls = cls;
00350     }
00351     /*
00352       return new oqmlStatus(this, "collection type '%s' is neither a reference nor a basic type", type_spec);
00353     */
00354 
00355     oqmlStatus *s = oqml_get_location(db, ctx, location);
00356     if (s) return s;
00357     newdb = db;
00358 
00359     return ql ? ql->compile(db, ctx) : oqmlSuccess;
00360   }
00361 
00362   oqmlStatus *oqmlCollection::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00363   {
00364     oqmlStatus *s;
00365     Collection *coll = 0;
00366 
00367     db = newdb;
00368 
00369     char *ident = coll_spec->ident;
00370     Bool isref = coll_spec->isref;
00371 
00372     IndexImpl *idximpl = 0;
00373     if (coll_spec->impl_hints) {
00374       Status status = IndexImpl::make(db, coll_spec->ishash ?
00375                                       IndexImpl::Hash :
00376                                       IndexImpl::BTree,
00377                                       coll_spec->impl_hints, idximpl);
00378       if (status) return new oqmlStatus(this, status);
00379     }
00380 
00381     if (what == collset)
00382       coll = new CollSet(ident, cls, isref, idximpl);
00383     else if (what == collbag)
00384       coll = new CollBag(ident, cls, isref, idximpl);
00385     else if (what == collarray)
00386       coll = new CollArray(ident, cls, isref, idximpl);
00387     /*
00388       else if (what == colllist)
00389       coll = new CollList(ident, cls, isref, idximpl);
00390     */
00391 
00392     if (!coll)
00393       return new oqmlStatus(this, "internal error in collection create");
00394 
00395     Status status = coll->setDatabase(db);
00396     if (status) {
00397       coll->release();
00398       return new oqmlStatus(this, status);
00399     }
00400 
00401     if (!ql) {
00402       if (!location) {
00403         *alist = new oqmlAtomList(oqmlObjectManager::registerObject(coll));
00404         return oqmlSuccess;
00405       }
00406 
00407       Status is = coll->realize();
00408 
00409       if (is) {
00410         coll->release();
00411         return new oqmlStatus(this, is);
00412       }
00413       
00414       *alist = new oqmlAtomList(new oqmlAtom_oid(coll->getOid()));
00415 
00416       coll->release();
00417       return oqmlSuccess;
00418     }
00419 
00420     Status is;
00421     int ii = 0;
00422 
00423     oqmlAtomList *al;
00424     s = ql->eval(db, ctx, &al);
00425     if (s) return s;
00426 
00427     if (!al->cnt)
00428       return oqmlStatus::expected(this, "atom list", "nil");
00429 
00430     oqmlAtom *a = al->first;
00431 
00432     if (OQML_IS_COLL(a))
00433       a = OQML_ATOM_COLLVAL(a)->first;
00434     /*
00435       return oqmlStatus::expected(this, "collection literal",
00436       a->type.getString());
00437     */
00438 
00439     while (a) {
00440       oqmlAtom *next = a->next;
00441 
00442       if (!atref.cmp(a->type)) {
00443         coll->release();
00444         return oqmlStatus::expected(this, &atref, &a->type);
00445       }
00446       
00447       if (isref) {
00448         if (what == collarray)
00449           is = coll->asCollArray()->insertAt(ii, ((oqmlAtom_oid *)a)->oid);
00450         else
00451           is = coll->insert(((oqmlAtom_oid *)a)->oid);
00452       }
00453       else if (a->type.type == oqmlATOM_OBJ) {
00454         OQL_CHECK_OBJ(a);
00455         if (what == collarray)
00456           is = coll->asCollArray()->insertAt(ii, OQML_ATOM_OBJVAL(a));
00457         else
00458           is = coll->insert(OQML_ATOM_OBJVAL(a));
00459       }
00460       else {
00461           Data val;
00462           unsigned char buff[16];
00463           Size size;
00464           int len;
00465               
00466           size = sizeof(buff);
00467           if (a->getData(buff, &val, size, len, cls)) {
00468             Data data = (val ? val : buff);
00469             if (what == collarray)
00470               is = coll->asCollArray()->insertAt_p(ii, data, size);
00471             else
00472               is = coll->insert_p(data, False, size);
00473           }
00474           else
00475             is = Success;
00476         }
00477           
00478       if (is) {
00479         coll->release();
00480         return new oqmlStatus(this, is);
00481       }
00482       a = next;
00483       ii++;
00484     }
00485 
00486     if (!location) {
00487       *alist = new oqmlAtomList(oqmlObjectManager::registerObject(coll));
00488       return oqmlSuccess;
00489     }
00490 
00491     is = coll->realize();
00492 
00493     if (is) {
00494       coll->release();
00495       return new oqmlStatus(this, is);
00496     }
00497 
00498     *alist = new oqmlAtomList(new oqmlAtom_oid(coll->getOid()));
00499 
00500     coll->release();
00501 
00502     return oqmlSuccess;
00503   }
00504 
00505   void oqmlCollection::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00506   {
00507     *at = eval_type;
00508   }
00509 
00510   oqmlBool oqmlCollection::isConstant() const
00511   {
00512     return oqml_False;
00513   }
00514 
00515   void
00516   oqmlCollection::lock()
00517   {
00518     oqmlNode::lock();
00519     if (ql) ql->lock();
00520     if (location) location->lock();
00521   }
00522 
00523   void
00524   oqmlCollection::unlock()
00525   {
00526     oqmlNode::unlock();
00527     if (ql) ql->unlock();
00528     if (location) location->unlock();
00529   }
00530 
00531   std::string
00532   oqmlCollection::toString(void) const
00533   {
00534     if (is_statement)
00535       return std::string("new ") + coll_spec->toString() + "(" +
00536         (ql ? ql->toString() : std::string("")) + "); ";
00537 
00538     return std::string("(new ") + coll_spec->toString() + "(" +
00539       (ql ? ql->toString() : std::string("")) + "))";
00540   }
00541 
00542   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00543   //
00544   // oqmlContents methods
00545   //
00546   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00547 
00548   oqmlContents::oqmlContents(oqmlNode * _ql) : oqmlNode(oqmlCONTENTS)
00549   {
00550     ql = _ql;
00551   }
00552 
00553   oqmlContents::~oqmlContents()
00554   {
00555   }
00556 
00557   oqmlStatus *oqmlContents::compile(Database *db, oqmlContext *ctx)
00558   {
00559     oqmlStatus *s;
00560     s = ql->compile(db, ctx);
00561 
00562     if (s)
00563       return s;
00564 
00565     return oqmlSuccess;
00566   }
00567 
00568   oqmlAtom *
00569   oqml_make_struct_array(Database *db, oqmlContext *ctx, int idx, oqmlAtom *x)
00570   {
00571     if (ctx->isWhereContext())
00572       return x;
00573     oqml_StructAttr *attrs = new oqml_StructAttr[2];
00574     attrs[0].set("index", new oqmlAtom_int(idx));
00575     attrs[1].set("value", x);
00576     return new oqmlAtom_struct(attrs, 2);
00577   }
00578 
00579   static oqmlAtom *
00580   make_array_set(Database *db, oqmlContext *ctx, oqmlAtomList *list)
00581   {
00582     if (ctx->isWhereContext())
00583       return new oqmlAtom_set(list);
00584 
00585     oqmlAtomList *rlist = new oqmlAtomList();
00586     oqmlAtom *x = list->first;
00587 
00588     int idx;
00589     for (int n = 0; x; n++)
00590       {
00591         oqmlAtom *next = x->next;
00592         if (!(n & 1))
00593           idx = OQML_ATOM_INTVAL(x);
00594         else
00595           rlist->append(oqml_make_struct_array(db, ctx, idx, x));
00596 
00597         x = next;
00598       }
00599 
00600     return new oqmlAtom_set(rlist);
00601   }
00602 
00603   oqmlStatus *oqmlContents::eval(Database *db, oqmlContext *ctx,
00604                                  oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00605   {
00606     oqmlStatus *s;
00607     oqmlAtomList *al;
00608 
00609     s = ql->eval(db, ctx, &al);
00610 
00611     if (s) return s;
00612 
00613     oqmlAtomList *rlist = new oqmlAtomList();
00614 
00615     if (!al->first)
00616       {
00617         *alist = new oqmlAtomList();
00618         return oqmlSuccess;
00619       }
00620 
00621     const Class *cls;
00622     s = oqml_coll_eval(this, db, ctx, al->first, rlist, cls, True);
00623 
00624     if (s) return s;
00625 
00626     if (cls->asCollSetClass())
00627       *alist = new oqmlAtomList(new oqmlAtom_set(rlist, oqml_False)); // added
00628     // oqml_False the 16/02/01 => optimisation!
00629     else if (cls->asCollArrayClass())
00630       //*alist = new oqmlAtomList(make_array_set(db, ctx, rlist));
00631       *alist = new oqmlAtomList(new oqmlAtom_set(rlist));
00632     else if (cls->asCollBagClass())
00633       *alist = new oqmlAtomList(new oqmlAtom_bag(rlist));
00634     else if (cls->asCollListClass())
00635       *alist = new oqmlAtomList(new oqmlAtom_list(rlist));
00636     else
00637       *alist = new oqmlAtomList(new oqmlAtom_list(rlist));
00638     return oqmlSuccess;
00639   }
00640 
00641   void oqmlContents::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00642   {
00643     *at = eval_type;
00644   }
00645 
00646   oqmlBool oqmlContents::isConstant() const
00647   {
00648     return OQMLBOOL(ql->isConstant());
00649   }
00650 
00651   std::string
00652   oqmlContents::toString(void) const
00653   {
00654     if (is_statement)
00655       return std::string("contents ") + ql->toString() + "; ";
00656     return std::string("(contents ") + ql->toString() + ")";
00657   }
00658 
00659   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00660   //
00661   // oqmlIn methods
00662   //
00663   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00664 
00665   oqmlIn::oqmlIn(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlIN)
00666   {
00667     qleft = _qleft;
00668     qright = _qright;
00669     eval_type.type = oqmlATOM_BOOL;
00670     evalDone = oqml_False;
00671   }
00672 
00673   oqmlIn::~oqmlIn()
00674   {
00675   }
00676 
00677   oqmlStatus *oqmlIn::compile(Database *db, oqmlContext *ctx)
00678   {
00679     evalDone = oqml_False;
00680     oqmlStatus *s;
00681     s = qleft->compile(db, ctx);
00682 
00683     if (s) return s;
00684 
00685     return qright->compile(db, ctx);
00686   }
00687 
00688   static oqmlStatus *
00689   check_coll(oqmlNode *node, Database *db, oqmlAtom *aleft,
00690              Collection *&coll, oqmlATOMTYPE &t)
00691   {
00692     if (!OQML_IS_OBJECT(aleft))
00693       return oqmlStatus::expected(node, "oid or object", aleft->type.getString());
00694   
00695     oqmlStatus *s;
00696     s = oqmlObjectManager::getObject(node, db, aleft, (Object *&)coll,
00697                                      oqml_False);
00698 
00699     if (s) return s;
00700 
00701     if (!coll->getClass()->asCollectionClass())
00702       {
00703         oqmlObjectManager::releaseObject(coll);
00704         return oqmlStatus::expected(node, "collection", coll->getClass()->getName());
00705       }
00706       
00707     s = oqml_check_coll_type(coll, t);
00708   
00709     if (s)
00710       {
00711         oqmlObjectManager::releaseObject(coll);
00712         return s;
00713       }
00714 
00715     return oqmlSuccess;
00716   }
00717 
00718   static oqmlStatus *
00719   coll_perform(oqmlNode *node, Database *db, oqmlContext *ctx,
00720                oqmlAtomList **alist,
00721                oqmlNode *qleft, oqmlNode *qright,
00722                oqmlStatus *(*perform)(oqmlNode *,Collection *, const Oid *,
00723                                       Data, int, oqmlAtom *,
00724                                       oqmlAtomList *, oqmlAtomList *),
00725                oqmlBool write)
00726   {
00727     oqmlStatus *s;
00728     oqmlAtomList *al_left, *al_right;
00729 
00730     *alist = new oqmlAtomList();
00731 
00732     s = qleft->eval(db, ctx, &al_left);
00733     if (s) return s;
00734 
00735     oqmlAtom *aleft = al_left->first;
00736     if (!aleft)
00737       return new oqmlStatus(node, "invalid nil atom: %s",
00738                             qleft->toString().c_str());
00739 
00740     if (qright) {
00741       s = qright->eval(db, ctx, &al_right);
00742       if (s) return s;
00743     }
00744 
00745 #if 0
00746     if (perform == append_perform) {
00747       printf("aleft %p aright %p\n", al_left, al_right);
00748       printf("aleft first %p aright %p\n", al_left->first, al_right->first);
00749       printf("copying %p %d\n", al_right->first, aleft->as_coll());
00750       al_right = al_right->copy();
00751       printf("after copying %p\n", al_right->first);
00752       /*
00753       if (aleft->as_coll()) {
00754         aleft->as_coll()->list->append(al_right, oqml_False);
00755         return oqmlSuccess;
00756       }
00757       */
00758     }
00759 #endif
00760 
00761     oqmlAtom *aright = (qright ? al_right->first : 0);
00762 
00763     if (aleft->as_coll())
00764       return (*perform)(node, 0, 0, 0, 0, aright, aleft->as_coll()->list, *alist);
00765 
00766     Collection *coll = 0;
00767     oqmlATOMTYPE t;
00768 
00769     s = check_coll(node, db, aleft, coll, t);
00770     if (s) return s;
00771 
00772     if (!qright)
00773       {
00774         s = (*perform)(node, coll, 0, 0, 0, 0, 0, *alist);
00775         if (s)
00776           {
00777             oqmlObjectManager::releaseObject(coll);
00778             return s;
00779           }
00780 
00781         return oqmlSuccess;
00782       }
00783 
00784     if (aright->type.type != t &&
00785         !(aright->as_null() && t == oqmlATOM_OID))
00786       {
00787         oqmlObjectManager::releaseObject(coll);
00788         return oqmlStatus::expected(node, "oid", 
00789                                     aright->type.getString());
00790       }
00791   
00792     Status status = Success;
00793 
00794     if (t == oqmlATOM_OID)
00795       {
00796         Oid oid;
00797         if (!aright->as_null())
00798           oid = OQML_ATOM_OIDVAL(aright);
00799       
00800         s = (*perform)(node, coll, &oid, 0, 0,
00801                        aright, 0, *alist);
00802         if (s)
00803           {
00804             oqmlObjectManager::releaseObject(coll);
00805             return s;
00806           }
00807 
00808         if (write)
00809           status = coll->realize();
00810 
00811         oqmlObjectManager::releaseObject(coll);
00812 
00813         if (status)
00814           return new oqmlStatus(node, status);
00815 
00816         return oqmlSuccess;
00817       }
00818 
00819     Data val;
00820     unsigned char buff[16];
00821     Size size;
00822     int len;
00823   
00824     size = sizeof(buff);
00825     oqmlAtomType *at = &aleft->type;
00826     if (aright->getData(buff, &val, size, len, at->cls))
00827       {
00828         s = (*perform)(node, coll, 0, (val ? val : buff), size,
00829                        aright, 0, *alist);
00830       
00831         if (s)
00832           {
00833             oqmlObjectManager::releaseObject(coll);
00834             return s;
00835           }
00836       }
00837   
00838     if (write)
00839       status = coll->realize();
00840 
00841     oqmlObjectManager::releaseObject(coll);
00842 
00843     if (status)
00844       return new oqmlStatus(node, status);
00845 
00846     return oqmlSuccess;
00847   }
00848 
00849   static oqmlStatus *
00850   in_perform(oqmlNode *node, Collection *coll, const Oid *oid,
00851              Data data, int size,
00852              oqmlAtom *atom, oqmlAtomList *atom_coll, oqmlAtomList *alist)
00853   {
00854     Status status;
00855 
00856     if (coll)
00857       {
00858         Bool is;
00859 
00860         if (oid)
00861           status = coll->isIn(*oid, is);
00862         else
00863           status = coll->isIn_p(data, is);
00864       
00865         if (status)
00866           return new oqmlStatus(node, status);
00867 
00868         alist->append(new oqmlAtom_bool(OQMLBOOL(is)));
00869         return oqmlSuccess;
00870       }
00871 
00872     alist->append(new oqmlAtom_bool(atom_coll->isIn(atom)));
00873     return oqmlSuccess;
00874   }
00875 
00876   oqmlStatus *oqmlIn::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00877   {
00878     if (evalDone)
00879       {
00880         *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
00881         return oqmlSuccess;
00882       }
00883 
00884     return coll_perform(this, db, ctx, alist, qright, qleft, in_perform, oqml_False);
00885   }
00886 
00887   void oqmlIn::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00888   {
00889     *at = eval_type;
00890   }
00891 
00892   oqmlBool oqmlIn::isConstant() const
00893   {
00894     return oqml_False;
00895   }
00896 
00897   oqmlBool
00898   oqmlIn::hasDotIdent(const char *_ident)
00899   {
00900     if (qleft->asDot())
00901       return qleft->hasIdent(_ident);
00902     return oqml_False;
00903   }
00904 
00905   static oqmlNode *
00906   get_invalid_node()
00907   {
00908     return (new oqmlAtom_oid("0:0:1:oid"))->toNode();
00909   }
00910 
00911   oqmlStatus *
00912   oqmlIn::preEvalSelect(Database *db, oqmlContext *ctx,
00913                         const char *ident, oqmlBool &done,
00914                         unsigned int &cnt, oqmlBool firstPass)
00915   {
00916     done = oqml_False;
00917     cnt = 0;
00918 
00919     if (!hasDotIdent(ident))
00920       return oqmlSuccess;
00921 
00922     oqmlAtomList *alist;
00923     oqmlStatus *s = qright->eval(db, ctx, &alist);
00924     if (s) return s;
00925       
00926     oqmlAtomList *list;
00927 
00928     if (!alist->cnt)
00929       list = 0;
00930     else if (alist->first->as_coll())
00931       list = alist->first->as_coll()->list;
00932     else
00933       list = alist;
00934 
00935     if (!list || list->cnt <= 1)
00936       {
00937         oqmlNode *node = new oqmlEqual
00938           (qleft, (list && list->first ? list->first->toNode() :
00939                    get_invalid_node()));
00940         s = node->compile(db, ctx);
00941         if (s) return s;
00942         s = node->eval(db, ctx, &alist);
00943         if (!s)
00944           {
00945             done = oqml_True;
00946             evalDone = oqml_True;
00947           }
00948         return s;
00949       }
00950 
00951     oqmlAtom *x = list->first;
00952     if (x)
00953       {
00954         oqmlNode *nodeOr = new oqmlEqual(qleft, x->toNode());
00955 
00956         x = x->next;
00957         while (x)
00958           {
00959             nodeOr = new oqmlLOr
00960               (nodeOr, new oqmlEqual(qleft, x->toNode()), oqml_False);
00961             x = x->next;
00962           }
00963 
00964         s = nodeOr->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00965       }
00966 
00967     if (!s)
00968       evalDone = oqml_True;
00969     return s;
00970   }
00971 
00972   std::string
00973   oqmlIn::toString(void) const
00974   {
00975     if (is_statement)
00976       return std::string("") + qleft->toString() + " in " +
00977         qright->toString() + "; ";
00978     return std::string("(") + qleft->toString() + " in " +
00979       qright->toString() + ")";
00980   }
00981 
00982   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00983   //
00984   // oqmlAddTo methods
00985   //
00986   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00987 
00988   oqmlAddTo::oqmlAddTo(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlADDTO)
00989   {
00990     qleft = _qleft;
00991     qright = _qright;
00992   }
00993 
00994   oqmlAddTo::~oqmlAddTo()
00995   {
00996   }
00997 
00998   oqmlStatus *oqmlAddTo::compile(Database *db, oqmlContext *ctx)
00999   {
01000     oqmlStatus *s;
01001     s = qleft->compile(db, ctx);
01002 
01003     if (s)
01004       return s;
01005 
01006     s = qright->compile(db, ctx);
01007 
01008     if (s)
01009       return s;
01010 
01011     return oqmlSuccess;
01012   }
01013 
01014   static oqmlStatus *
01015   insert_perform(oqmlNode *node, Collection *coll, const Oid *oid,
01016                  Data data, int size, oqmlAtom *a, oqmlAtomList *atom_coll,
01017                  oqmlAtomList *alist)
01018   {
01019     if (coll)
01020       {
01021         Status status;
01022         if (oid)
01023           status = coll->insert(*oid);
01024         else
01025           status = coll->insert_p(data, False, size);
01026       
01027         if (status)
01028           return new oqmlStatus(node, status);
01029       
01030         alist->append(a->copy());
01031         return oqmlSuccess;
01032       }
01033 
01034     oqmlAtom *x = a->copy();
01035     atom_coll->append(x);
01036     alist->append(x);
01037     return oqmlSuccess;
01038   }
01039 
01040   oqmlStatus *oqmlAddTo::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01041   {
01042     return coll_perform(this, db, ctx, alist, qright, qleft, insert_perform, oqml_True);
01043   }
01044 
01045   void oqmlAddTo::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01046   {
01047     *at = eval_type;
01048   }
01049 
01050   oqmlBool oqmlAddTo::isConstant() const
01051   {
01052     return oqml_False;
01053   }
01054 
01055   std::string
01056   oqmlAddTo::toString(void) const
01057   {
01058     if (is_statement)
01059       return std::string("add ") + qleft->toString() + " to " +
01060         qright->toString() + "; ";
01061     return std::string("(add ") + qleft->toString() + " to " +
01062       qright->toString() + ")";
01063   }
01064 
01065   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01066   //
01067   // oqmlSuppressFrom methods
01068   //
01069   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01070 
01071   oqmlSuppressFrom::oqmlSuppressFrom(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlSUPPRESSFROM)
01072   {
01073     qleft = _qleft;
01074     qright = _qright;
01075   }
01076 
01077   oqmlSuppressFrom::~oqmlSuppressFrom()
01078   {
01079   }
01080 
01081   oqmlStatus *oqmlSuppressFrom::compile(Database *db, oqmlContext *ctx)
01082   {
01083     oqmlStatus *s;
01084     s = qleft->compile(db, ctx);
01085 
01086     if (s)
01087       return s;
01088 
01089     s = qright->compile(db, ctx);
01090 
01091     if (s)
01092       return s;
01093 
01094     return oqmlSuccess;
01095   }
01096 
01097   static oqmlStatus *
01098   suppress_perform(oqmlNode *node, Collection *coll, const Oid *oid,
01099                    Data data, int size, oqmlAtom *a,
01100                    oqmlAtomList *atom_coll, oqmlAtomList *alist)
01101   {
01102     if (coll)
01103       {
01104         Status status;
01105         if (oid)
01106           status = coll->suppress(*oid);
01107         else
01108           status = coll->suppress_p(data);
01109       
01110         if (status)
01111           return new oqmlStatus(node, status);
01112       
01113         alist->append(a->copy());
01114         return oqmlSuccess;
01115       }
01116 
01117     oqmlStatus *s = atom_coll->suppress(a);
01118     if (s) return s;
01119     alist->append(a->copy());
01120     return oqmlSuccess;
01121   }
01122 
01123   oqmlStatus *oqmlSuppressFrom::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01124   {
01125     return coll_perform(this, db, ctx, alist, qright, qleft, suppress_perform, oqml_True);
01126   }
01127 
01128   void oqmlSuppressFrom::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01129   {
01130     *at = eval_type;
01131   }
01132 
01133   oqmlBool oqmlSuppressFrom::isConstant() const
01134   {
01135     return oqml_False;
01136   }
01137 
01138   std::string
01139   oqmlSuppressFrom::toString(void) const
01140   {
01141     if (is_statement)
01142       return std::string("suppress ") + qleft->toString() + " from " +
01143         qright->toString() + "; ";
01144     return std::string("(suppress ") + qleft->toString() + " from " +
01145       qright->toString() + ")";
01146   }
01147 
01148   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01149   //
01150   // oqmlAppend methods
01151   //
01152   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01153 
01154   oqmlAppend::oqmlAppend(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlAPPEND)
01155   {
01156     qleft = _qleft;
01157     qright = _qright;
01158   }
01159 
01160   oqmlAppend::~oqmlAppend()
01161   {
01162   }
01163 
01164   oqmlStatus *oqmlAppend::compile(Database *db, oqmlContext *ctx)
01165   {
01166     oqmlStatus *s;
01167     s = qleft->compile(db, ctx);
01168 
01169     if (s)
01170       return s;
01171 
01172     s = qright->compile(db, ctx);
01173 
01174     if (s)
01175       return s;
01176 
01177     return oqmlSuccess;
01178   }
01179 
01180   static oqmlStatus *
01181   append_perform(oqmlNode *node, Collection *coll, const Oid *oid,
01182                  Data data, int size, oqmlAtom *a,
01183                  oqmlAtomList *atom_coll, oqmlAtomList *alist)
01184   {
01185     if (coll) {
01186       if (!coll->asCollArray())
01187         return new oqmlStatus(node, "cannot append to a non-array collection");
01188       Status status;
01189       if (oid)
01190         status = coll->asCollArray()->append(*oid);
01191       else
01192         status = coll->asCollArray()->append_p(data, False, size);
01193       
01194       if (status)
01195         return new oqmlStatus(node, status);
01196       return oqmlSuccess;
01197     }
01198 
01199     oqmlAtom *x = a->copy();
01200     if (atom_coll->append(x, true, x->as_coll() ? true : false))
01201       return new oqmlStatus(node, "collection cycle detected");
01202 
01203     alist->append(x);
01204     return oqmlSuccess;
01205   }
01206 
01207   oqmlStatus *oqmlAppend::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01208   {
01209     return coll_perform(this, db, ctx, alist, qright, qleft, append_perform, oqml_True);
01210   }
01211 
01212   void oqmlAppend::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01213   {
01214     *at = eval_type;
01215   }
01216 
01217   oqmlBool oqmlAppend::isConstant() const
01218   {
01219     return oqml_False;
01220   }
01221 
01222   std::string
01223   oqmlAppend::toString(void) const
01224   {
01225     if (is_statement)
01226       return std::string("append ") + qleft->toString() + " to " +
01227         qright->toString() + "; ";
01228     return std::string("(append ") + qleft->toString() + " to " +
01229       qright->toString() + ")";
01230   }
01231 
01232   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01233   //
01234   // oqmlEmpty methods
01235   //
01236   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01237 
01238   oqmlEmpty::oqmlEmpty(oqmlNode * _ql) : oqmlNode(oqmlEMPTY)
01239   {
01240     ql = _ql;
01241   }
01242 
01243   oqmlEmpty::~oqmlEmpty()
01244   {
01245   }
01246 
01247   oqmlStatus *oqmlEmpty::compile(Database *db, oqmlContext *ctx)
01248   {
01249     oqmlStatus *s;
01250     s = ql->compile(db, ctx);
01251 
01252     if (s)
01253       return s;
01254 
01255     return oqmlSuccess;
01256   }
01257 
01258   static oqmlStatus *
01259   empty_perform(oqmlNode *node, Collection *coll, const Oid *,
01260                 Data, int, oqmlAtom *, oqmlAtomList *atom_coll,
01261                 oqmlAtomList *alist)
01262   {
01263     if (coll)
01264       {
01265         Status status;
01266         status = coll->empty();
01267       
01268         if (status)
01269           return new oqmlStatus(node, status);
01270         return oqmlSuccess;
01271       }
01272 
01273     atom_coll->empty();
01274     return oqmlSuccess;
01275   }
01276 
01277   oqmlStatus *oqmlEmpty::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01278   {
01279     return coll_perform(this, db, ctx, alist, ql, 0, empty_perform, oqml_True);
01280   }
01281 
01282   void oqmlEmpty::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01283   {
01284     *at = eval_type;
01285   }
01286 
01287   oqmlBool oqmlEmpty::isConstant() const
01288   {
01289     return oqml_False;
01290   }
01291 
01292   std::string
01293   oqmlEmpty::toString(void) const
01294   {
01295     if (is_statement)
01296       return std::string("empty ") + ql->toString() + "; ";
01297     return std::string("(empty ") + ql->toString() + ")";
01298   }
01299 
01300   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01301   //
01302   // oqmlSetInAt methods
01303   //
01304   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01305 
01306   oqmlSetInAt::oqmlSetInAt(oqmlNode * _qleft, oqmlNode *_qright, oqmlNode *_ql3) : oqmlNode(oqmlSETINAT)
01307   {
01308     qleft = _qleft;
01309     qright = _qright;
01310     ql3 = _ql3;
01311   }
01312 
01313   oqmlSetInAt::~oqmlSetInAt()
01314   {
01315   }
01316 
01317   oqmlStatus *oqmlSetInAt::compile(Database *db, oqmlContext *ctx)
01318   {
01319     oqmlStatus *s;
01320 
01321     s = qleft->compile(db, ctx);
01322 
01323     if (s)
01324       return s;
01325 
01326     s = qright->compile(db, ctx);
01327 
01328     if (s)
01329       return s;
01330 
01331     s = ql3->compile(db, ctx);
01332 
01333     if (s)
01334       return s;
01335 
01336     return oqmlSuccess;
01337   }
01338 
01339   oqmlStatus *oqmlSetInAt::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01340   {
01341     oqmlAtomList *al_left, *al_right, *al3;
01342     oqmlStatus *s;
01343 
01344     *alist = new oqmlAtomList();
01345 
01346     s = qleft->eval(db, ctx, &al_left);
01347 
01348     if (s)
01349       return s;
01350 
01351     s = qright->eval(db, ctx, &al_right);
01352 
01353     if (s)
01354       return s;
01355 
01356     s = ql3->eval(db, ctx, &al3);
01357 
01358     if (s)
01359       return s;
01360 
01361     oqmlAtom *array = al3->first;
01362 
01363     while (array)
01364       {
01365         Status is;
01366         if (!OQML_IS_OBJECT(array))
01367           return oqmlStatus::expected(this, "oid or object",
01368                                       array->type.getString());
01369 
01370         Object *o;
01371         s = oqmlObjectManager::getObject(this, db, array, o, oqml_False);
01372         if (s) return s;
01373         if (!o->getClass()->asCollArrayClass())
01374           {
01375             oqmlObjectManager::releaseObject(o);
01376             return oqmlStatus::expected(this, "array",
01377                                         o->getClass()->getName());
01378           }
01379 
01380         CollArray *arr = (CollArray *)o;
01381         oqmlAtom *aind = al_left->first;
01382 
01383         oqmlATOMTYPE t;
01384         oqml_check_coll_type(arr, t);
01385       
01386         while(aind)
01387           {
01388             oqmlAtom *nextaind = aind->next;
01389             if (aind->type.type != oqmlATOM_INT)
01390               return oqmlStatus::expected(this, "integer",
01391                                           aind->type.getString());
01392 
01393             oqmlAtom *e = al_right->first;
01394             while (e)
01395               {
01396                 oqmlAtom *nexte = e->next;
01397                 if (t == oqmlATOM_OID)
01398                   {
01399                     if (e->type.type != oqmlATOM_OID)
01400                       return oqmlStatus::expected(this, "oid",
01401                                                   e->type.getString());
01402 
01403                     is = arr->insertAt(((oqmlAtom_int *)aind)->i, ((oqmlAtom_oid *)e)->oid);
01404                     if (is)
01405                       return new oqmlStatus(this, is);
01406                   }
01407                 else
01408                   {
01409                     Data val = 0;
01410                     unsigned char buff[16];
01411                     Size size;
01412                     int len;
01413                   
01414                     size = sizeof(buff);
01415                     if (e->getData(buff, &val, size, len))
01416                       {
01417                         is = arr->insertAt_p(((oqmlAtom_int *)aind)->i, (val ? val : buff));
01418                         if (is)
01419                           return new oqmlStatus(this, is);
01420                       }
01421                   }
01422 
01423                 (*alist)->append(e->copy());
01424                 e = nexte;
01425               }
01426             aind = nextaind;
01427           }
01428 
01429         is = arr->realize();
01430         if (is)
01431           return new oqmlStatus(this, is);
01432 
01433         oqmlObjectManager::releaseObject(o);
01434         array = array->next;
01435       }
01436 
01437     return oqmlSuccess;
01438   }
01439 
01440   void oqmlSetInAt::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01441   {
01442     *at = eval_type;
01443   }
01444 
01445   oqmlBool oqmlSetInAt::isConstant() const
01446   {
01447     return oqml_False;
01448   }
01449 
01450   std::string
01451   oqmlSetInAt::toString(void) const
01452   {
01453     if (is_statement)
01454       return std::string("set ") + qleft->toString() + " in " +
01455         ql3->toString() + " at " + qright->toString() + "; ";
01456     return std::string("(set ") + qleft->toString() + " in " +
01457       ql3->toString() + " at " + qright->toString() + ")";
01458   }
01459 
01460   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01461   //
01462   // oqmlUnsetInAt methods
01463   //
01464   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01465 
01466   oqmlUnsetInAt::oqmlUnsetInAt(oqmlNode * _qleft, oqmlNode *_qright) : oqmlNode(oqmlUNSETINAT)
01467   {
01468     qleft = _qleft;
01469     qright = _qright;
01470   }
01471 
01472   oqmlUnsetInAt::~oqmlUnsetInAt()
01473   {
01474   }
01475 
01476   oqmlStatus *oqmlUnsetInAt::compile(Database *db, oqmlContext *ctx)
01477   {
01478     oqmlStatus *s;
01479 
01480     s = qleft->compile(db, ctx);
01481 
01482     if (s)
01483       return s;
01484 
01485     s = qright->compile(db, ctx);
01486 
01487     if (s) return s;
01488 
01489     return oqmlSuccess;
01490   }
01491 
01492   oqmlStatus *oqmlUnsetInAt::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01493   {
01494     oqmlAtomList *al_left, *al_right;
01495     oqmlStatus *s;
01496 
01497     *alist = new oqmlAtomList();
01498 
01499     s = qleft->eval(db, ctx, &al_left);
01500 
01501     if (s) return s;
01502 
01503     s = qright->eval(db, ctx, &al_right);
01504 
01505     if (s) return s;
01506 
01507     oqmlAtom *array = al_right->first;
01508 
01509     while (array)
01510       {
01511         Status is;
01512         if (!OQML_IS_OBJECT(array))
01513           return oqmlStatus::expected(this, "oid or object",
01514                                       array->type.getString());
01515 
01516         Object *o;
01517         s = oqmlObjectManager::getObject(this, db, array, o, oqml_False);
01518         if (s) return s;
01519         if (!o->getClass()->asCollArrayClass())
01520           {
01521             oqmlObjectManager::releaseObject(o);
01522             return oqmlStatus::expected(this, "array",
01523                                         o->getClass()->getName());
01524           }
01525 
01526         CollArray *arr = (CollArray *)o;
01527         oqmlAtom *aind = al_left->first;
01528 
01529         while(aind)
01530           {
01531             if (aind->type.type != oqmlATOM_INT)
01532               return oqmlStatus::expected(this, "integer",
01533                                           aind->type.getString());
01534 
01535             is = arr->suppressAt(((oqmlAtom_int *)aind)->i);
01536             if (is)
01537               return new oqmlStatus(this, is);
01538 
01539             aind = aind->next;
01540           }
01541 
01542         is = arr->realize();
01543         if (is)
01544           return new oqmlStatus(this, is);
01545 
01546         oqmlObjectManager::releaseObject(o);
01547         array = array->next;
01548       }
01549 
01550     return oqmlSuccess;
01551   }
01552 
01553   void oqmlUnsetInAt::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01554   {
01555     *at = eval_type;
01556   }
01557 
01558   oqmlBool oqmlUnsetInAt::isConstant() const
01559   {
01560     return oqml_False;
01561   }
01562 
01563   std::string
01564   oqmlUnsetInAt::toString(void) const
01565   {
01566     if (is_statement)
01567       return std::string("unset in ") + qright->toString() + " at " +
01568         qleft->toString() + "; ";
01569 
01570     return std::string("(unset in ") + qleft->toString() + " at " +
01571       qleft->toString() + ")";
01572   }
01573 
01574   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01575   //
01576   // oqmlElement methods
01577   //
01578   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01579 
01580   oqmlElement::oqmlElement(oqmlNode * _ql) : oqmlNode(oqmlELEMENT)
01581   {
01582     ql = _ql;
01583   }
01584 
01585   oqmlElement::~oqmlElement()
01586   {
01587   }
01588 
01589   oqmlStatus *oqmlElement::compile(Database *db, oqmlContext *ctx)
01590   {
01591     return ql->compile(db, ctx);
01592   }
01593 
01594   oqmlStatus *oqmlElement::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01595   {
01596     oqmlAtomList *al;
01597     oqmlStatus *s;
01598 
01599     s = ql->eval(db, ctx, &al);
01600 
01601     if (s) return s;
01602 
01603     if (!al->cnt || !OQML_IS_COLL(al->first))
01604       return oqmlStatus::expected(this, "collection",
01605                                   (al->first ? al->first->type.getString() :
01606                                    "nil"));
01607 
01608     int cnt = OQML_ATOM_COLLVAL(al->first)->cnt;
01609     if (cnt != 1)
01610       return new oqmlStatus(this, "expected collection with one and "
01611                             "only one element, got %d element%s",
01612                             cnt, cnt != 1 ? "s" : "");
01613 
01614     *alist = new oqmlAtomList(OQML_ATOM_COLLVAL(al->first)->first);
01615     return oqmlSuccess;
01616   }
01617 
01618   void oqmlElement::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01619   {
01620     *at = eval_type;
01621   }
01622 
01623   oqmlBool oqmlElement::isConstant() const
01624   {
01625     return oqml_False;
01626   }
01627 
01628   std::string
01629   oqmlElement::toString(void) const
01630   {
01631     if (is_statement)
01632       return std::string("element ") + ql->toString() + "; ";
01633     return std::string("(element ") + ql->toString() + ")";
01634   }
01635 
01636   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01637   //
01638   // oqmlElementAt methods
01639   //
01640   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01641 
01642   oqmlElementAt::oqmlElementAt(oqmlNode * _qleft, oqmlNode *_qright) : oqmlNode(oqmlELEMENTAT)
01643   {
01644     qleft = _qleft;
01645     qright = _qright;
01646   }
01647 
01648   oqmlElementAt::~oqmlElementAt()
01649   {
01650   }
01651 
01652   oqmlStatus *oqmlElementAt::compile(Database *db, oqmlContext *ctx)
01653   {
01654     oqmlStatus *s;
01655 
01656     s = qleft->compile(db, ctx);
01657 
01658     if (s)
01659       return s;
01660 
01661     s = qright->compile(db, ctx);
01662 
01663     if (s)
01664       return s;
01665 
01666     return oqmlSuccess;
01667   }
01668 
01669   oqmlStatus *oqmlElementAt::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01670   {
01671     oqmlAtomList *al_left, *al_right;
01672     oqmlStatus *s;
01673 
01674     *alist = new oqmlAtomList();
01675 
01676     s = qleft->eval(db, ctx, &al_left);
01677 
01678     if (s)
01679       return s;
01680 
01681     s = qright->eval(db, ctx, &al_right);
01682 
01683     if (s)
01684       return s;
01685 
01686     oqmlAtom *array = al_right->first;
01687 
01688     while (array)
01689       {
01690         Status is;
01691         if (!OQML_IS_OBJECT(array))
01692           return oqmlStatus::expected(this, "oid or object",
01693                                       array->type.getString());
01694 
01695         Object *o;
01696         s = oqmlObjectManager::getObject(this, db, array, o, oqml_False);
01697         if (s) return s;
01698         if (!o->getClass()->asCollArrayClass())
01699           {
01700             oqmlObjectManager::releaseObject(o);
01701             return oqmlStatus::expected(this, "array",
01702                                         o->getClass()->getName());
01703           }
01704 
01705         CollArray *arr = (CollArray *)o;
01706         oqmlAtom *aind = al_left->first;
01707 
01708         oqmlATOMTYPE t;
01709         oqml_check_coll_type(arr, t);
01710       
01711         while(aind)
01712           {
01713             oqmlAtom *next = aind->next;
01714             if (aind->type.type != oqmlATOM_INT)
01715               return oqmlStatus::expected(this, "integer",
01716                                           aind->type.getString());
01717 
01718             if (t == oqmlATOM_OID)
01719               {
01720                 Oid xoid;
01721                 is = arr->retrieveAt(((oqmlAtom_int *)aind)->i, xoid);
01722                 if (is)
01723                   return new oqmlStatus(this, is);
01724                 (*alist)->append(new oqmlAtom_oid(xoid));
01725               }
01726             else
01727               {
01728                 unsigned char buff[256];
01729                 is = arr->retrieveAt_p(((oqmlAtom_int *)aind)->i, buff);
01730                 if (is)
01731                   return new oqmlStatus(this, is);
01732                 switch(t)
01733                   {
01734                   case oqmlATOM_INT:
01735                     {
01736                       int i;
01737                       memcpy(&i, buff, sizeof(int));
01738                       (*alist)->append(new oqmlAtom_int(i));
01739                       break;
01740                     }
01741                   case oqmlATOM_DOUBLE:
01742                     {
01743                       double d;
01744                       memcpy(&d, buff, sizeof(double));
01745                       (*alist)->append(new oqmlAtom_double(d));
01746                       break;
01747                     }
01748                   case oqmlATOM_STRING:
01749                     {
01750                       (*alist)->append(new oqmlAtom_string((char *)buff));
01751                       break;
01752                     }
01753 
01754                   default:
01755                     return new oqmlStatus(this, "type #%d not supported", t);
01756                   }
01757               }
01758 
01759             aind = next;
01760           }
01761 
01762         oqmlObjectManager::releaseObject(o);
01763         array = array->next;
01764       }
01765 
01766     return oqmlSuccess;
01767   }
01768 
01769   void oqmlElementAt::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01770   {
01771     *at = eval_type;
01772   }
01773 
01774   oqmlBool oqmlElementAt::isConstant() const
01775   {
01776     return oqml_False;
01777   }
01778 
01779   std::string
01780   oqmlElementAt::toString(void) const
01781   {
01782     if (is_statement)
01783       return std::string("element at ") + qleft->toString() + " in " +
01784         qright->toString() + "; ";
01785     return std::string("(element at ") + qleft->toString() + " in " +
01786       qright->toString() + ")";
01787   }
01788 
01789   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01790   //
01791   // oqml_Interval methods
01792   //
01793   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01794 
01795   oqml_Interval::oqml_Interval(oqmlNode *_from, oqmlNode *_to) :
01796     from(_from), to(_to)
01797   {
01798     from_base = 0;
01799     to_base = 0;
01800   }
01801 
01802   oqmlStatus *
01803   oqml_Interval::compile(Database *db, oqmlContext *ctx)
01804   {
01805     oqmlStatus *s;
01806 
01807     if (from)
01808       {
01809         s = from->compile(db, ctx);
01810         if (s) return s;
01811       }
01812 
01813     if (to)
01814       return to->compile(db, ctx);
01815 
01816     return oqmlSuccess;
01817   }
01818 
01819   oqmlStatus *
01820   oqml_Interval::evalNode(Database *db, oqmlContext *ctx,
01821                           oqmlNode *node, unsigned int &base)
01822   {
01823     oqmlStatus *s;
01824     if (!node)
01825       {
01826         base = oqml_INFINITE;
01827         return oqmlSuccess;
01828       }
01829 
01830     oqmlAtomList *al;
01831     s = node->eval(db, ctx, &al);
01832     if (s) return s;
01833 
01834     if (!al->first)
01835       return new oqmlStatus("interval %s: integer expected, got nil",
01836                             toString().c_str());
01837 
01838     if (!OQML_IS_INT(al->first))
01839       return new oqmlStatus("interval %s: integer expected, got %s",
01840                             toString().c_str(),
01841                             al->first->type.getString());
01842 
01843     base = OQML_ATOM_INTVAL(al->first);
01844     return oqmlSuccess;
01845   }
01846 
01847   oqmlBool
01848   oqml_Interval::isAll() const
01849   {
01850     return OQMLBOOL(from_base == oqml_INFINITE && to_base == oqml_INFINITE);
01851   }
01852 
01853   oqml_Interval::Status
01854   oqml_Interval::isIn(unsigned int count, unsigned int max) const
01855   {
01856     if (max == oqml_INFINITE)
01857       {
01858         if (count >= from_base && count <= to_base)
01859           return Success;
01860 
01861         return Error;
01862       }
01863 
01864     if (count > to_base)
01865       return Error;
01866 
01867     if (count >= from_base && max <= to_base)
01868       return Success;
01869 
01870     return Continue;
01871   }
01872 
01873   oqmlStatus *
01874   oqml_Interval::evalNodes(Database *db, oqmlContext *ctx)
01875   {
01876     oqmlStatus *s;
01877 
01878     s = evalNode(db, ctx, from, from_base);
01879     if (s) return s;
01880 
01881     return evalNode(db, ctx, to, to_base);
01882   }
01883 
01884   std::string
01885   oqml_Interval::toString() const
01886   {
01887     if (!from && !to) return "all";
01888 
01889     std::string s = "<";
01890 
01891     if (from) s += from->toString();
01892     else      s += "$";
01893 
01894     if (to != from)
01895       {
01896         s += ":";
01897         if (to) s += to->toString();
01898         else    s += "$";
01899       }
01900 
01901     return s + ">";
01902   }
01903 
01904   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01905   //
01906   // oqmlFor methods
01907   //
01908   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01909 
01910   oqmlFor::oqmlFor(oqml_Interval *_interval, const char *_ident,
01911                    oqmlNode * _qcoll, oqmlNode * _qpred,
01912                    oqmlBool _exists) : oqmlNode(_exists ? oqmlEXISTS : oqmlFOR)
01913   {
01914     interval = _interval;
01915     qcoll = _qcoll;
01916     qpred = _qpred;
01917     ident = strdup(_ident);
01918     exists = _exists;
01919     eval_type.type = oqmlATOM_BOOL;
01920   }
01921 
01922   oqmlFor::~oqmlFor()
01923   {
01924     free(ident);
01925   }
01926 
01927   oqmlStatus *oqmlFor::compile(Database *db, oqmlContext *ctx)
01928   {
01929     oqmlStatus *s;
01930 
01931     s = interval->compile(db, ctx);
01932     if (s) return s;
01933 
01934     s = qcoll->compile(db, ctx);
01935     if (s) return s;
01936 
01937     oqmlAtomType nodeType;
01938     ctx->pushSymbol(ident, &nodeType, 0, oqml_False);
01939     s = qpred->compile(db, ctx);
01940     ctx->popSymbol(ident, oqml_False);
01941 
01942     if (s) return s;
01943 
01944     return oqmlSuccess;
01945   }
01946 
01947   oqmlStatus *oqmlFor::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01948   {
01949     oqmlStatus *s;
01950 
01951     s = interval->evalNodes(db, ctx);
01952     if (s) return s;
01953 
01954     oqmlAtomList *al;
01955     s = qcoll->eval(db, ctx, &al);
01956     if (s) return s;
01957 
01958     oqmlAtomList *rlist = new oqmlAtomList();
01959     const Class *cls;
01960     s = oqml_coll_eval(this, db, ctx, al->first, rlist, cls);
01961     if (s) return s;
01962 
01963     oqmlBool isAll = interval->isAll();
01964 
01965     unsigned int count = 0;
01966     unsigned int max = rlist->cnt;
01967     oqmlAtom *a = rlist->first;
01968     while(a)
01969       {
01970         oqmlAtomList *predList;
01971         oqmlAtom *next = a->next;
01972 
01973         ctx->pushSymbol(ident, &a->type, a, oqml_False);
01974         s = qpred->eval(db, ctx, &predList);
01975         ctx->popSymbol(ident, oqml_False);
01976         if (s) return s;
01977 
01978         if (!predList->first)
01979           return new oqmlStatus(this,
01980                                 "condition: boolean expected, got nil");
01981 
01982         if (!OQML_IS_BOOL(predList->first))
01983           return new oqmlStatus(this,
01984                                 "condition: boolean expected, got %s",
01985                                 predList->first->type.getString());
01986 
01987         if (OQML_ATOM_BOOLVAL(predList->first))
01988           {
01989             oqml_Interval::Status is = interval->isIn(++count, max);
01990             if (is == oqml_Interval::Error)
01991               {
01992                 *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_False));
01993                 return oqmlSuccess;
01994               }
01995 
01996             if (is == oqml_Interval::Success)
01997               {
01998                 *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
01999                 return oqmlSuccess;
02000               }
02001           }
02002         else if (isAll)
02003           {
02004             *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_False));
02005             return oqmlSuccess;
02006           }
02007 
02008         a = next;
02009       }
02010 
02011     if (isAll && count == max)
02012       {
02013         *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
02014         return oqmlSuccess;
02015       }
02016 
02017     oqml_Interval::Status is = interval->isIn(count, oqml_INFINITE);
02018 
02019     if (is == oqml_Interval::Success)
02020       *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
02021     else
02022       *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_False));
02023 
02024     return oqmlSuccess;
02025   }
02026 
02027   void oqmlFor::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
02028   {
02029     *at = eval_type;
02030   }
02031 
02032   oqmlBool oqmlFor::isConstant() const
02033   {
02034     return oqml_False;
02035   }
02036 
02037   void
02038   oqmlFor::lock()
02039   {
02040     oqmlNode::lock();
02041     interval->lock();
02042     qcoll->lock();
02043     qpred->lock();
02044   }
02045 
02046   void
02047   oqmlFor::unlock()
02048   {
02049     oqmlNode::unlock();
02050     interval->unlock();
02051     qcoll->unlock();
02052     qpred->unlock();
02053   }
02054 
02055   std::string
02056   oqmlFor::toString(void) const
02057   {
02058     if (exists)
02059       {
02060         if (is_statement)
02061           return std::string("exists ") + ident + " in " +
02062             qcoll->toString() + ": " + qpred->toString() + "; ";
02063         return std::string("(exists ") + ident + " in " +
02064           qcoll->toString() + ": " + qpred->toString() + ")";
02065       }
02066 
02067     if (is_statement)
02068       return std::string("for ") + interval->toString() + " " + ident + " in " +
02069         qcoll->toString() + ": " + qpred->toString() + "; ";
02070     return std::string("(for ") + interval->toString() + " " + ident + " in " +
02071       qcoll->toString() + ": " + qpred->toString() + ")";
02072   }
02073 
02074   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
02075   //
02076   // oqml_CollSpec methods
02077   //
02078   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
02079 
02080   oqml_CollSpec::oqml_CollSpec(const char *_coll_type, const char *_type_spec, oqmlBool _isref, const char *_ident, oqmlBool _ishash, const char *_impl_hints)
02081   {
02082     coll_type = strdup(_coll_type);
02083     type_spec = strdup(_type_spec);
02084     isref = (_isref ? True : False);
02085     ishash = (_ishash ? True : False);
02086     ident = strdup(_ident);
02087     impl_hints = _impl_hints ? strdup(_impl_hints) : 0;
02088     coll_spec = NULL;
02089   }
02090 
02091   oqml_CollSpec::oqml_CollSpec(const char *_coll_type, oqml_CollSpec *_coll_spec, oqmlBool _isref, const char *_ident, oqmlBool _ishash, const char *_impl_hints)
02092   {
02093     coll_type = strdup(_coll_type);
02094     isref = (_isref ? True : False);
02095     ishash = (_ishash ? True : False);
02096     ident = strdup(_ident);
02097     impl_hints = _impl_hints ? strdup(_impl_hints) : 0;
02098     type_spec = NULL;
02099     coll_spec = _coll_spec;
02100   }
02101 
02102   std::string
02103   oqml_CollSpec::toString(void) const
02104   {
02105     return std::string(coll_type) + "<" + (type_spec ? type_spec : "??") +
02106       (isref ? "*" : "") +
02107       (ident ? std::string(", \"") + ident + "\"" : std::string(", \"\"")) +
02108       (ishash ? ", hash" : ", btree") +
02109       (impl_hints ? std::string(", \"") + impl_hints + "\"":  std::string(", """)) +
02110       ">";
02111   }
02112 
02113   oqml_CollSpec::~oqml_CollSpec()
02114   {
02115     free(coll_type);
02116     free(type_spec);
02117     free(ident);
02118     free(impl_hints);
02119   }
02120 }

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