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