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