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
00030 #ifdef USE_LIBGEN
00031 zoulou !!!
00032 #include <libgen.h>
00033 #endif
00034
00035 #include <sys/types.h>
00036 #include <regex.h>
00037
00038 #include "oql_p.h"
00039 #include "Attribute_p.h"
00040
00041 namespace eyedb {
00042
00043 #define AND(N) ((N) ? ", " : "")
00044
00045 #define ISNULL(K) (((K) == Attribute::idxNull) ? True : False)
00046 #define idxISNULL(ATOM) \
00047 ((ATOM)->type.type == oqmlATOM_NULL ? Attribute::idxNull : \
00048 Attribute::idxNotNull)
00049
00050 static char CI = 'I';
00051 static char CS = 'S';
00052
00053 static oqmlBool equal_oid(Data data, Bool isnull,
00054 const oqmlAtom *start, const oqmlAtom *, int, void *)
00055 {
00056 if (isnull)
00057 return oqml_False;
00058 Oid oid;
00059 memcpy(&oid, data, sizeof(Oid));
00060 return OQMLBOOL(oid.compare(((oqmlAtom_oid *)start)->oid));
00061 }
00062
00063 static int
00064 getThreadCount(oqmlContext *ctx)
00065 {
00066 oqmlAtom *thread_cnt_a;
00067
00068 if (ctx->getSymbol("oql$thread$count", 0, &thread_cnt_a)) {
00069 if (thread_cnt_a && OQML_IS_INT(thread_cnt_a))
00070 return OQML_ATOM_INTVAL(thread_cnt_a);
00071 }
00072
00073 return 0;
00074 }
00075
00076 static oqmlStatus *
00077 oqmlMakeIter(oqmlNode *node,
00078 Database *db, oqmlContext *ctx, oqmlDotContext *dctx, int n,
00079 oqmlAtomList *alist, oqmlAtom *start, oqmlAtom *end,
00080 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
00081 const oqmlAtom *, int, void *),
00082 int depth,
00083 int thread_cnt = 0,
00084 void *user_data = 0,
00085 eyedbsm::Boolean sexcl = eyedbsm::False, eyedbsm::Boolean eexcl = eyedbsm::False);
00086
00087 static inline oqmlBool
00088 oqmlCheckType(Database *db, Oid *cloid, const Class *cls)
00089 {
00090
00091 if (cls->getOid() == *cloid)
00092 return oqml_True;
00093
00094
00095
00096 Class *rcl;
00097
00098 rcl = db->getSchema()->getClass(*cloid);
00099 if (!rcl)
00100 return oqml_False;
00101
00102 Bool issuperclassof;
00103 return OQMLBOOL(((Class *)cls)->isSuperClassOf(rcl, &issuperclassof)
00104 == Success && issuperclassof);
00105 }
00106
00107 static const Class *
00108 oqmlIterGetClass(Database *db, oqmlDotContext *dctx, int n, int &pn,
00109 oqmlBool &mustCheck)
00110 {
00111 const Class *cls = NULL;
00112 oqmlDotDesc *d = &dctx->desc[n];
00113
00114 mustCheck = (db->getVersionNumber() >= MULTIIDX_VERSION) ? oqml_False :
00115 oqml_True;
00116
00117 pn = n;
00118 if (dctx->ident_mode)
00119 cls = d->cls;
00120 else
00121 {
00122
00123 d = &dctx->desc[pn];
00124 if (d->array && !d->array->wholeRange)
00125 mustCheck = oqml_True;
00126
00127
00128 for (; pn >= 1; pn--)
00129 {
00130 d = &dctx->desc[pn-1];
00131 if (d->array && !d->array->wholeRange)
00132 mustCheck = oqml_True;
00133
00134 if (d->isref)
00135 {
00136 cls = d->cls;
00137 break;
00138 }
00139 }
00140
00141 if (!cls)
00142 cls = dctx->desc[0].cls;
00143 }
00144
00145 if (!cls->getDatabase())
00146 cls = db->getSchema()->getClass(cls->getName());
00147
00148 return cls;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 static Status
00163 oqmlIterPrelim(oqmlNode *node, Database *db, oqmlContext *ctx, Object *o,
00164 oqmlDotDesc *d, Data* pdata, const Attribute *&xattr)
00165 {
00166 oqmlStatus *s;
00167 Status is;
00168
00169 if (d->attrname)
00170 {
00171 xattr = o->getClass()->getAttribute(d->attrname);
00172
00173
00174
00175
00176
00177
00178
00179 if (d->attr)
00180 return Success;
00181
00182 s = d->make(db, ctx, (oqmlDot *)node, xattr, d->array, d->attrname, 0);
00183 if (s) return Exception::make(IDB_OQL_ERROR, s->msg);
00184 if (!*pdata)
00185 *pdata = d->e_data;
00186
00187 return Success;
00188 }
00189
00190 assert(d->qlmth);
00191
00192 if (!((oqmlMethodCall *)d->qlmth)->isCompiled())
00193 {
00194 s = d->qlmth->compile(db, ctx);
00195 if (s) return Exception::make(IDB_OQL_ERROR, s->msg);
00196 }
00197
00198 xattr = 0;
00199 return Success;
00200 }
00201
00202 static Status
00203 oqmlIterGetValue(oqmlNode *node,
00204 Database *db, oqmlContext *ctx, Object *o,
00205 oqmlDotContext *dctx, int n, int pn, Data* pdata,
00206 Bool *isnull, int nb, int ind,
00207 const Attribute *xattr, Size &size);
00208
00209 static Status
00210 oqmlIterGetValueMiddle(oqmlNode *node,
00211 Database *db, oqmlContext *ctx, Object *o,
00212 oqmlDotContext *dctx, int n, int pn, Data* pdata,
00213 Bool *isnull, int nb, int ind, oqmlDotDesc *d,
00214 const Attribute *xattr, Size &size)
00215 {
00216 oqmlStatus *s;
00217 int s_ind, e_ind;
00218
00219 if (!d->icurs)
00220 {
00221 s = d->evalInd(node, db, ctx, s_ind, e_ind, oqml_True, oqml_False);
00222
00223 if (s)
00224 return Exception::make(s->msg);
00225
00226 if (s_ind != e_ind)
00227 d->icurs = new oqmlIterCursor(s_ind, e_ind);
00228 }
00229 else
00230 {
00231 s_ind = d->icurs->s_ind;
00232 e_ind = d->icurs->e_ind;
00233 }
00234
00235 for (int tind = s_ind; tind <= e_ind; tind++)
00236 {
00237 IDB_CHECK_INTR();
00238 Status is = Success;
00239 Object *o1 = 0;
00240
00241 oqmlBool must_release_o1;
00242
00243 if (xattr)
00244 {
00245 is = xattr->getValue((Agregat *)o, (Data *)&o1, 1, tind,
00246 isnull);
00247 if (is)
00248 {
00249 delete d->icurs;
00250 d->icurs = 0;
00251 return is;
00252 }
00253 must_release_o1 = oqml_False;
00254 }
00255 else
00256 {
00257 oqmlAtomList *al = new oqmlAtomList();
00258 s = ((oqmlMethodCall *)d->qlmth)->perform(db, ctx,
00259 o, o->getOid(),
00260 o->getClass(),
00261 &al);
00262 if (s) return Exception::make(IDB_OQL_ERROR, s->msg);
00263
00264 s = oqmlObjectManager::getObject(node, db, al->first, o1,
00265 oqml_False, oqml_False);
00266 if (s) return Exception::make(IDB_OQL_ERROR, s->msg);
00267 must_release_o1 = oqml_True;
00268 }
00269
00270 if (o1)
00271 {
00272 o1->setDatabase(db);
00273 is = oqmlIterGetValue(node, db, ctx, o1, dctx, n, pn+1, pdata,
00274 isnull, nb, ind, 0, size);
00275
00276 if (!is && nb == Attribute::directAccess)
00277 {
00278
00279
00280
00281
00282
00283
00284
00285
00286 if ((char *)*pdata)
00287 *pdata = (unsigned char *)strdup((char *)*pdata);
00288 else
00289 *pdata = (unsigned char *)strdup("");
00290
00291
00292
00293 oqmlGarbManager::add((char *)*pdata);
00294 }
00295
00296 if (must_release_o1)
00297 oqmlObjectManager::releaseObject(o1);
00298
00299 }
00300
00301 if (s_ind == e_ind)
00302 {
00303 delete d->icurs;
00304 d->icurs = 0;
00305 }
00306 else
00307 d->icurs->s_ind++;
00308
00309 if (!is || !d->icurs)
00310 return is;
00311 }
00312 }
00313
00314 static Status
00315 oqmlIterGetValueTerminal(oqmlNode *node,
00316 Database *db, oqmlContext *ctx, Object *o,
00317 oqmlDotContext *dctx, int n, int pn, Data* pdata,
00318 Bool *isnull, int nb, int ind, oqmlDotDesc *d,
00319 const Attribute *xattr, Size &size)
00320 {
00321 oqmlStatus *s;
00322 Status is;
00323
00324 if (!xattr && !d->qlmth)
00325 return Success;
00326
00327 if (!xattr)
00328 {
00329 oqmlAtomList *al = new oqmlAtomList();
00330 s = ((oqmlMethodCall *)d->qlmth)->perform(db, ctx,
00331 o, o->getOid(),
00332 o->getClass(),
00333 &al);
00334
00335 if (s) return Exception::make(IDB_OQL_ERROR, s->msg);
00336
00337 oqmlAtom *x = al->first;
00338 if (!x)
00339 return Success;
00340
00341 if ((OQML_IS_OID(x) && !OQML_ATOM_OIDVAL(x).isValid()) ||
00342 ((OQML_IS_OBJ(x) && !OQML_ATOM_OBJVAL(x))) ||
00343 x->as_null())
00344 *isnull = True;
00345
00346 Data val = 0; int len;
00347 x->getData(*pdata, &val, size, len);
00348
00349 if (nb == Attribute::directAccess)
00350 *(char **)*pdata = (char *)val;
00351 else if (val)
00352 {
00353 int len = strlen((char *)val)+1;
00354 if (len > d->key_len)
00355 {
00356 s = new oqmlStatus(node,
00357 "internal query error: string overflow: "
00358 "'%s'", val);
00359 return Exception::make(IDB_OQL_ERROR, s->msg);
00360 }
00361
00362 memcpy(*pdata, val, len);
00363 }
00364
00365 return Success;
00366 }
00367
00368 if (d->isref && !d->is_coll)
00369 {
00370 is = xattr->getOid((Agregat *)o, (Oid *)*pdata, 1, ind);
00371 if (is) return is;
00372 if (!((Oid *)*pdata)->isValid())
00373 *isnull = True;
00374
00375 return Success;
00376 }
00377 else if (nb != Attribute::directAccess && oqml_is_getcount(d->array))
00378 {
00379 if (oqml_is_wholecount(d->array))
00380 return Exception::make(IDB_ERROR, "cannot perform this query");
00381
00382 Size size;
00383 Status is = xattr->getSize(o, size);
00384 if (is) return is;
00385 memcpy(*pdata, &size, sizeof(size));
00386 *isnull = False;
00387 return Success;
00388 }
00389
00390 if (nb == Attribute::directAccess)
00391 is = xattr->getValue((Agregat *)o, pdata, nb, ind, isnull);
00392 else
00393 is = xattr->getValue((Agregat *)o, (Data *)*pdata, nb, ind, isnull);
00394
00395
00396
00397
00398 return is;
00399 }
00400
00401 static Status
00402 oqmlIterGetValue(oqmlNode *node,
00403 Database *db, oqmlContext *ctx, Object *o,
00404 oqmlDotContext *dctx, int n, int pn, Data* pdata,
00405 Bool *isnull, int nb, int ind, const Attribute *xattr,
00406 Size &size)
00407 {
00408 oqmlDotDesc *d = &dctx->desc[pn];
00409 oqmlStatus *s;
00410 Status is;
00411
00412 size = d->key_len;
00413
00414 *isnull = False;
00415
00416 if (d->attrname && (is = oqmlIterPrelim(node, db, ctx, o, d, pdata, xattr)))
00417 return is;
00418
00419 if (pn != n)
00420 return oqmlIterGetValueMiddle(node, db, ctx, o, dctx, n, pn,
00421 pdata, isnull, nb, ind, d, xattr, size);
00422
00423 return oqmlIterGetValueTerminal(node, db, ctx, o, dctx, n, pn,
00424 pdata, isnull, nb, ind, d, xattr, size);
00425 }
00426
00427 static oqmlStatus *
00428 oqmlCheckValue(Database *db, oqmlDotDesc *d,
00429 oqmlContext *ctx, oqmlDotContext *dctx,
00430 const Oid &oid,
00431 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
00432 const oqmlAtom *, int, void *),
00433 Bool isnull,
00434 oqmlAtom *start, oqmlAtom *end,
00435 void *user_data, Bool &ok)
00436 {
00437 oqmlAtomList *al = new oqmlAtomList();
00438 oqmlStatus *s = dctx->eval(db, ctx, new oqmlAtom_oid(oid), NULL, &al);
00439
00440 if (s)
00441 return s;
00442
00443 if (al)
00444 {
00445 oqmlAtom *a = al->first;
00446 unsigned char *key = (unsigned char *)(d->key->getKey());
00447
00448 while (a)
00449 {
00450 Data val = 0;
00451 Size size = d->key_len;
00452 int len;
00453 if (a->getData(key, &val, size, len, d->cls))
00454 {
00455 Data data = (val ? val : key);
00456 if ((*cmp)(data, (a->type.type == oqmlATOM_NULL ||
00457 isnull ? True : False),
00458 start, end, d->key_len, user_data))
00459 {
00460 ok = True;
00461 return oqmlSuccess;
00462 }
00463 }
00464
00465 a = a->next;
00466 }
00467 }
00468
00469 ok = False;
00470 return oqmlSuccess;
00471 }
00472
00473 #define IDX_USER_CMP
00474
00475 #ifdef IDX_USER_CMP
00476 struct CmpArg {
00477 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
00478 const oqmlAtom *, int, void *);
00479 oqmlAtom *start, *end;
00480 int key_len;
00481 void *user_data;
00482 CmpArg(oqmlBool (*_cmp)(Data, Bool, const oqmlAtom *,
00483 const oqmlAtom *, int, void *),
00484 oqmlAtom *_start, oqmlAtom *_end,
00485 int _key_len, void *_user_data) {
00486 cmp = _cmp;
00487 start = _start;
00488 end = _end;
00489 key_len = _key_len;
00490 user_data = _user_data;
00491 }
00492 };
00493
00494 static eyedbsm::Boolean
00495 idx_compare(const void *xkey, void *xarg)
00496 {
00497 CmpArg *arg = (CmpArg *)xarg;
00498 unsigned char *key = (unsigned char *)xkey;
00499
00500 return arg->cmp(key + sizeof(char), ISNULL(key[0]),
00501 arg->start, arg->end, arg->key_len, arg->user_data) ?
00502 eyedbsm::True : eyedbsm::False;
00503 }
00504 #endif
00505
00506 static oqmlStatus *
00507 oqmlMakeIter_idx_comp(oqmlNode *node,
00508 Database *db, oqmlContext *ctx, oqmlDotContext *dctx,
00509 int n, oqmlAtomList *alist, oqmlAtom *start,
00510 oqmlAtom *end,
00511 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
00512 const oqmlAtom *, int, void *),
00513 int depth,
00514 int thread_cnt,
00515 void *user_data,
00516 eyedbsm::Boolean sexcl, eyedbsm::Boolean eexcl)
00517 {
00518 oqmlDotDesc *d = &dctx->desc[n];
00519 int ind;
00520 Data s_val, e_val;
00521 Size size;
00522 int len;
00523 oqmlStatus *s;
00524 unsigned char *s_data, *e_data;
00525 int pn;
00526 oqmlBool mustCheck;
00527 Class *cls = (Class *)oqmlIterGetClass(db, dctx, n, pn, mustCheck);
00528
00529 memset(d->s_data, 0, d->key_len+sizeof(char));
00530
00531 size = d->key_len;
00532 if (!start)
00533 s_data = 0;
00534 else
00535 {
00536 d->make_key(start->getSize());
00537 if (!start->getData(d->s_data+sizeof(char), &s_val, size, len, cls))
00538 return oqmlSuccess;
00539 if (s_val)
00540 {
00541 if (strlen((char *)s_val) >= d->key_len)
00542 return oqmlSuccess;
00543 strcpy((char *)d->s_data+sizeof(char), (char *)s_val);
00544 }
00545 s_data = d->s_data;
00546 d->s_data[0] = idxISNULL(start);
00547 }
00548
00549 memset(d->e_data, 0, d->key_len+sizeof(char));
00550
00551 size = d->key_len;
00552 if (!end)
00553 e_data = 0;
00554 else
00555 {
00556 d->make_key(end->getSize());
00557 if (!end->getData (d->e_data+sizeof(char), &e_val, size, len, cls))
00558 return oqmlSuccess;
00559 if (e_val)
00560 {
00561 if (strlen((char *)e_val) >= d->key_len)
00562 return oqmlSuccess;
00563 strcpy((char *)d->e_data+sizeof(char), (char *)e_val);
00564 }
00565 e_data = d->e_data;
00566 d->e_data[0] = idxISNULL(end);
00567 }
00568
00569 Bool mustCheckType = (db->getVersionNumber() >= MULTIIDX_VERSION) ?
00570 False : True;
00571
00572 #ifdef IDX_USER_CMP
00573 CmpArg arg(cmp, start, end, d->key_len, user_data);
00574 #endif
00575
00576 for (int nidx = 0; nidx < d->idx_cnt; nidx++)
00577 {
00578 eyedbsm::Idx *idx = d->idxse[nidx];
00579
00580 IDB_LOG(IDB_LOG_IDX_SEARCH,
00581 ("[%d] Using Comp Index #%d '%s' between '%s' and '%s' "
00582 "[%s check value]%s\n", n,
00583 nidx, (d->idxs[nidx] ? d->idxs[nidx]->getAttrpath().c_str() : ""),
00584 (start ? start->getString() : "null"),
00585 (end ? end->getString() : "null"),
00586 (mustCheck ? "must" : "does not"),
00587 (!idx ? " SE index is null" : "")));
00588
00589 if (!idx)
00590 continue;
00591
00592 eyedbsm::IdxCursor *curs;
00593
00594 #ifdef IDX_USER_CMP
00595 if (idx->asHIdx())
00596 curs = new eyedbsm::HIdxCursor(idx->asHIdx(), s_data, e_data, sexcl, eexcl,
00597 idx_compare, &arg, thread_cnt);
00598 else
00599 curs = new eyedbsm::BIdxCursor(idx->asBIdx(), s_data, e_data, sexcl, eexcl,
00600 idx_compare, &arg);
00601 #else
00602 if (idx->asHIdx())
00603 curs = new eyedbsm::HIdxCursor(idx->asHIdx(), s_data, e_data, sexcl, eexcl,
00604 0, 0, thread_cnt);
00605 else
00606 curs = new eyedbsm::BIdxCursor(idx->asBIdx(), s_data, e_data, sexcl, eexcl);
00607 #endif
00608
00609 int nfound;
00610 for (nfound = 0; ; nfound++)
00611 {
00612 eyedbsm::Boolean found;
00613 Oid oid[2];
00614 *((char *)d->key->getKey()) = 0;
00615 eyedbsm::Status se;
00616 OQML_CHECK_INTR();
00617
00618 if ((se = curs->next(&found, oid, d->key)) == eyedbsm::Success)
00619 {
00620 if (!found)
00621 break;
00622
00623 unsigned char *key = (unsigned char *)(d->key->getKey());
00624
00625 IDB_LOG(IDB_LOG_IDX_SEARCH_DETAIL,
00626 ("[%d] Key Found %s '%s' (%s) => ", n,
00627 oid[0].toString(), key+sizeof(char),
00628 ISNULL(key[0]) ? "null data" : "not null data"));
00629
00630 #ifndef IDX_USER_CMP
00631 if (!((*cmp)(key + sizeof(char), ISNULL(key[0]),
00632 start, end, d->key_len, user_data)))
00633 {
00634 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL, ("don't match\n"));
00635 continue;
00636 }
00637 #endif
00638
00639 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL, ("matches\n"));
00640
00641 if (mustCheckType)
00642 {
00643 if (!oqmlCheckType(db, &oid[1], cls))
00644 continue;
00645 }
00646
00647 if (pn > 1)
00648 {
00649 oqmlAtom *r = new oqmlAtom_oid(oid[0], cls);
00650 s = oqmlMakeIter(node, db, ctx, dctx, pn-1, alist, r, r,
00651 equal_oid, depth+1, thread_cnt);
00652 if (s)
00653 {
00654 delete curs;
00655 return s;
00656 }
00657 }
00658 else if (!depth || pn != n)
00659 {
00660 Bool ok;
00661 if (mustCheck)
00662 {
00663 if (s = oqmlCheckValue(db, d, ctx, dctx, oid[0],
00664 cmp, ISNULL(key[0]),
00665 start, end, user_data, ok))
00666 {
00667 delete curs;
00668 return s;
00669 }
00670 }
00671 else
00672 ok = True;
00673
00674 if (ok)
00675 {
00676
00677 alist->append(new oqmlAtom_oid(oid[0], cls));
00678 OQML_CHECK_MAX_ATOMS(alist, ctx, delete curs);
00679 }
00680 }
00681 else
00682 {
00683 alist->append(new oqmlAtom_oid(oid[0], cls));
00684 OQML_CHECK_MAX_ATOMS(alist, ctx, delete curs);
00685 }
00686 }
00687 else
00688 {
00689 delete curs;
00690 return new oqmlStatus(node, eyedbsm::statusGet(se));
00691 }
00692 }
00693
00694 if (!nfound)
00695 IDB_LOG(IDB_LOG_IDX_SEARCH_DETAIL, ("[%d] No Key Found\n", n));
00696
00697 delete curs;
00698 }
00699
00700 return oqmlSuccess;
00701 }
00702
00703 static void
00704 computeOffset(oqmlDotDesc *d, int &offset, int &offset_ind)
00705 {
00706 #ifdef IDB_UNDEF_ENUM_HINT
00707 if (d->cls->asEnumClass())
00708 {
00709 offset = sizeof(char) + sizeof(char);
00710 offset_ind = sizeof(eyedblib::int32);
00711 return;
00712 }
00713 #endif
00714
00715 if (d->is_coll)
00716 {
00717 offset = 0;
00718 offset_ind = 0;
00719 return;
00720 }
00721
00722 offset = sizeof(char);
00723 offset_ind = sizeof(eyedblib::int32);
00724 }
00725
00726 static void
00727 promote_atom(oqmlDotDesc *d, oqmlAtom *&x)
00728 {
00729 if (!d->cls || !x) return;
00730
00731 if (x->as_double())
00732 {
00733 if (d->cls->asInt32Class() || d->cls->asInt16Class() || d->cls->asInt64Class())
00734 x = new oqmlAtom_int(x->as_double()->d);
00735 else if (d->cls->asCharClass())
00736 x = new oqmlAtom_char(x->as_double()->d);
00737
00738 return;
00739 }
00740
00741 if (x->as_int())
00742 {
00743 if (d->cls->asFloatClass())
00744 x = new oqmlAtom_double(x->as_int()->i);
00745 else if (d->cls->asCharClass())
00746 x = new oqmlAtom_char(x->as_int()->i);
00747
00748 return;
00749 }
00750
00751 if (x->as_char())
00752 {
00753 if (d->cls->asInt32Class() || d->cls->asInt16Class() || d->cls->asInt64Class())
00754 x = new oqmlAtom_char(x->as_char()->c);
00755 else if (d->cls->asFloatClass())
00756 x = new oqmlAtom_double(x->as_char()->c);
00757
00758 return;
00759 }
00760 }
00761
00762 static int
00763 oqmlMakeEntry(oqmlDotDesc *d, int ind, oqmlAtom *x, int offset,
00764 unsigned char *d_data, unsigned char *&data)
00765 {
00766 if (!x)
00767 {
00768 data = 0;
00769 return 1;
00770 }
00771
00772 if (!x->makeEntry(ind, d_data+offset, d->key_len, d->attr->getClass()))
00773 return 0;
00774
00775 d_data[0] = idxISNULL(x);
00776 #ifdef IDB_UNDEF_ENUM_HINT
00777 if (d->cls->asEnumClass())
00778 {
00779 if (idxISNULL(x))
00780 d_data[1] = 0;
00781 else
00782 d_data[1] = 1;
00783 }
00784 #endif
00785
00786 data = d_data;
00787 return 1;
00788 }
00789
00790 static int
00791 oqmlMakeEntries(oqmlDotDesc *d, int ind, oqmlAtom *&start, oqmlAtom *&end,
00792 int offset, unsigned char *&s_data, unsigned char *&e_data)
00793 {
00794 promote_atom(d, start);
00795 promote_atom(d, end);
00796
00797 if (offset)
00798 {
00799 if (!oqmlMakeEntry(d, ind, start, offset, d->s_data, s_data))
00800 return 0;
00801 if (!oqmlMakeEntry(d, ind, end, offset, d->e_data, e_data))
00802 return 0;
00803
00804 return 1;
00805 }
00806
00807 int len;
00808 Data val;
00809 Size key_len = d->key_len;
00810
00811 if (!start)
00812 s_data = 0;
00813 else if (!start->getData(d->s_data, &val, key_len, len,
00814 d->attr->getClass()))
00815 return 0;
00816
00817 if (!end)
00818 e_data = 0;
00819 else if (!end->getData(d->e_data, &val, key_len, len,
00820 d->attr->getClass()))
00821 return 0;
00822
00823 s_data = d->s_data;
00824 e_data = d->e_data;
00825 return 1;
00826 }
00827
00828 static oqmlStatus *
00829 oqml_add_coll_atom(oqmlNode *node, oqmlContext *ctx, const char *ident, oqmlAtom *atom)
00830 {
00831
00832
00833
00834
00835
00836 oqmlAtom *x;
00837 if (!ctx->getSymbol(ident, 0, &x) || !x->as_select())
00838 return new oqmlStatus(node, "internal error: expected select atom for %s",
00839 ident);
00840
00841 if (!x->as_select()->collatom)
00842 x->as_select()->collatom = new oqmlAtom_list(new oqmlAtomList());
00843
00844 oqmlAtomList *list = x->as_select()->collatom->list;
00845 if (!list->isIn(atom))
00846 list->append(atom->copy());
00847 return oqmlSuccess;
00848 }
00849
00850 static oqmlStatus *
00851 oqmlMakeIter_idx_item(oqmlNode *node, Database *db, oqmlContext *ctx,
00852 oqmlDotContext *dctx, int n,
00853 oqmlAtomList *alist, oqmlAtom *start, oqmlAtom *end,
00854 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
00855 const oqmlAtom *, int, void *),
00856 int depth,
00857 int thread_cnt,
00858 void *user_data, eyedbsm::Boolean sexcl, eyedbsm::Boolean eexcl)
00859 {
00860 oqmlDotDesc *d = &dctx->desc[n];
00861 int ind;
00862 oqmlStatus *s;
00863 unsigned char *s_data, *e_data;
00864 int pn;
00865 oqmlBool mustCheck;
00866 Class *cls = (Class *)oqmlIterGetClass(db, dctx, n, pn, mustCheck);
00867 int s_ind, e_ind;
00868
00869 s = d->evalInd(node, db, ctx, s_ind, e_ind, oqml_True, oqml_False);
00870 if (s) return s;
00871
00872 int offset;
00873 int offset_ind;
00874
00875 computeOffset(d, offset, offset_ind);
00876
00877 Bool mustCheckType = (db->getVersionNumber() >= MULTIIDX_VERSION) ?
00878 False : True;
00879
00880
00881
00882
00883
00884
00885
00886
00887 const char *requal_ident = (d->is_coll && dctx->dot->requal_ident) ?
00888 dctx->dot->requal_ident : 0;
00889
00890 for (ind = s_ind; ind <= e_ind; ind++)
00891 {
00892 OQML_CHECK_INTR();
00893
00894 if (!oqmlMakeEntries(d, ind, start, end, offset, s_data, e_data))
00895 continue;
00896
00897 for (int nidx = 0; nidx < d->idx_cnt; nidx++)
00898 {
00899 eyedbsm::Idx *idx = d->idxse[nidx];
00900
00901 IDB_LOG(IDB_LOG_IDX_SEARCH,
00902 ("[%d] Using Item Index #%d '%s' between '%s' and '%s' "
00903 "[%d, %d] [%s check value]%s\n", n,
00904 nidx, (d->idxs[nidx] ? d->idxs[nidx]->getAttrpath().c_str() : ""),
00905 (start ? start->getString() : "null"),
00906 (end ? end->getString() : "null"),
00907 s_ind, e_ind,
00908 (mustCheck ? "must" : "does not"),
00909 (!idx ? " SE index is null" : "")));
00910
00911 if (!idx)
00912 continue;
00913
00914 eyedbsm::IdxCursor *curs;
00915
00916 if (idx->asHIdx())
00917 curs = new eyedbsm::HIdxCursor(idx->asHIdx(), s_data, e_data,
00918 sexcl, eexcl, 0, 0, thread_cnt);
00919 else
00920 curs = new eyedbsm::BIdxCursor(idx->asBIdx(), s_data, e_data,
00921 sexcl, eexcl);
00922
00923 int nfound;
00924 for (nfound = 0; ; nfound++)
00925 {
00926 eyedbsm::Boolean found;
00927 Oid oid[2];
00928 eyedbsm::Status se;
00929 OQML_CHECK_INTR();
00930 if ((se = curs->next(&found, oid, d->key)) == eyedbsm::Success)
00931 {
00932 if (!found)
00933 break;
00934
00935 unsigned char *key = (unsigned char *)(d->key->getKey());
00936
00937 IDB_LOG(IDB_LOG_IDX_SEARCH_DETAIL,
00938 ("[%d] Key Found %s (%s) => ", n,
00939 oid[0].toString(),
00940 ISNULL(key[0]) ? "null data" : "not null data"));
00941
00942 if (!((*cmp)(key + offset_ind + offset,
00943 ISNULL(key[0]), start, end, d->key_len, user_data)))
00944 {
00945 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
00946 ("%s [index #%d]\n",
00947 (d->is_coll ? "not in collection" : "don't match"),
00948 ind));
00949 continue;
00950 }
00951
00952 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
00953 ("%s [index #%d]\n",
00954 (d->is_coll ? "is in collection" : "matches"),
00955 ind));
00956
00957 if (mustCheckType && !oqmlCheckType(db, &oid[1], cls))
00958 continue;
00959
00960 if (requal_ident)
00961 {
00962 s = oqml_add_coll_atom(node, ctx, requal_ident, start);
00963 if (s) return s;
00964 }
00965
00966 if (pn > 1)
00967 {
00968 oqmlAtom *r = new oqmlAtom_oid(oid[0], cls);
00969 s = oqmlMakeIter(node, db, ctx, dctx, pn-1, alist, r, r,
00970 equal_oid, depth+1, thread_cnt);
00971
00972 if (s)
00973 {
00974 delete curs;
00975 return s;
00976 }
00977 }
00978 else if (!depth || pn != n)
00979 {
00980 Bool ok;
00981 if (mustCheck)
00982 {
00983 if (s = oqmlCheckValue(db, d, ctx, dctx, oid[0],
00984 cmp, ISNULL(key[0]),
00985 start, end,
00986 user_data, ok))
00987 {
00988 delete curs;
00989 return s;
00990 }
00991 }
00992 else
00993 ok = True;
00994
00995 if (ok)
00996 {
00997 alist->append(new oqmlAtom_oid(oid[0], cls));
00998 OQML_CHECK_MAX_ATOMS(alist, ctx, delete curs);
00999 }
01000 }
01001 else
01002 {
01003 alist->append(new oqmlAtom_oid(oid[0], cls));
01004 OQML_CHECK_MAX_ATOMS(alist, ctx, delete curs);
01005 }
01006 }
01007 else
01008 {
01009 delete curs;
01010 return new oqmlStatus(node, eyedbsm::statusGet(se));
01011 }
01012 }
01013
01014 if (!nfound)
01015 IDB_LOG(IDB_LOG_IDX_SEARCH_DETAIL, ("[%d] No Key Found\n", n));
01016 delete curs;
01017 }
01018 }
01019
01020 return oqmlSuccess;
01021 }
01022
01023 static oqmlStatus *
01024 oqmlCollManage(oqmlNode *node, Database *db, oqmlContext *ctx,
01025 oqmlDotDesc *d, Object *o, Collection *&coll)
01026 {
01027 int ind;
01028 oqmlStatus *s;
01029 Status is;
01030
01031 if (d->array)
01032 {
01033 s = d->array->evalCollArray(node, db, ctx, &d->attr->getTypeModifier(),
01034 ind);
01035 if (s) return s;
01036 }
01037 else
01038 ind = 0;
01039
01040 const Attribute *xattr = o->getClass()->getAttributes()[d->attr->getNum()];
01041 if (xattr->isIndirect())
01042 {
01043 Oid colloid;
01044 is = xattr->getOid(o, &colloid, 1, ind);
01045 if (is) return new oqmlStatus(node, is);
01046 s = oqmlObjectManager::getObject(node, db, &colloid, (Object *&)coll,
01047 oqml_True, oqml_False);
01048 if (s) return s;
01049 }
01050 else
01051 {
01052 is = xattr->getValue(o, (Data *)&coll, 1, ind);
01053 if (is) return new oqmlStatus(node, is);
01054 }
01055
01056 if (coll && !coll->asCollection())
01057 return new oqmlStatus(node, "internal query error: "
01058 "collection expected, got %s",
01059 (coll ? coll->getClass()->getName() : "nil"));
01060
01061 if (coll)
01062 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
01063 ("collection %s at index #%d%s ",
01064 coll->asCollection()->getOidC().toString(), ind,
01065 coll->asCollection()->getOidC().isValid() ? " =>" : ""));
01066 else
01067 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
01068 ("collection NULL at index #%d ", ind));
01069
01070 return oqmlSuccess;
01071 }
01072
01073 #define SCHECK(S) \
01074 if (S) \
01075 { \
01076 if (o) oqmlObjectManager::releaseObject(o); \
01077 return S; \
01078 }
01079
01080
01081
01082 #define ICHECK(IS) \
01083 if (IS) \
01084 { \
01085 if (o) oqmlObjectManager::releaseObject(o); \
01086 Exception::setMode(omode); \
01087 if (omode == Exception::ExceptionMode) Exception::make(IDB_OQL_ERROR, (IS)->getDesc()); \
01088 return new oqmlStatus(IS); \
01089 }
01090
01091 static oqmlStatus *
01092 oqmlMakeIter_noidx(oqmlNode *node,
01093 Database *db, oqmlContext *ctx, oqmlDotContext *dctx, int n,
01094 oqmlAtomList *alist, oqmlAtom *start, oqmlAtom *end,
01095 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
01096 const oqmlAtom *, int, void *),
01097 int depth,
01098 int thread_cnt,
01099 void *user_data, eyedbsm::Boolean sexcl, eyedbsm::Boolean eexcl)
01100 {
01101 oqmlDotDesc *d = &dctx->desc[n];
01102 int ind;
01103 Status is;
01104 oqmlStatus *s;
01105 int pn;
01106 oqmlBool mustCheck;
01107 Class *cls = (Class *)oqmlIterGetClass(db, dctx, n, pn, mustCheck);
01108 oqmlDotDesc *dx = &dctx->desc[pn];
01109
01110 Iterator q((Class *)cls, True);
01111 Oid cl_oid = cls->getOid();
01112
01113 if (is = q.getStatus())
01114 return new oqmlStatus(node, is);
01115
01116 Oid oid;
01117 Bool found;
01118
01119 int s_ind, e_ind;
01120 s = d->evalInd(node, db, ctx, s_ind, e_ind, oqml_True, oqml_False);
01121 if (s) return s;
01122
01123 IDB_LOG(IDB_LOG_IDX_SEARCH,
01124 ("[%d] Using No Index between '%s' and '%s' [%d, %d]\n", n,
01125 (start ? start->getString() : "null"),
01126 (end ? end->getString() : "null"),
01127 s_ind, e_ind));
01128
01129 const char *requal_ident = (d->is_coll && dctx->dot->requal_ident) ?
01130 dctx->dot->requal_ident : 0;
01131
01132 Exception::Mode omode =
01133 Exception::setMode(Exception::StatusMode);
01134
01135 for (;;)
01136 {
01137 OQML_CHECK_INTR();
01138 is = q.scanNext(&found, &oid);
01139
01140 Object *o = 0;
01141 ICHECK(is);
01142
01143 if (!found)
01144 break;
01145
01146 IDB_LOG(IDB_LOG_IDX_SEARCH_DETAIL,
01147 ("[%d] Oid Found %s => ", n, oid.toString()));
01148
01149 s = oqmlObjectManager::getObject(node, db, oid, o, oqml_False);
01150
01151 if (s) continue;
01152
01153 if (dctx->ident_mode)
01154 {
01155 const char *name;
01156 if (dctx->iscoll)
01157 name = ((Collection *)o)->getName();
01158 else
01159 name = ((Class *)o)->getName();
01160
01161 if ((*cmp)((Data)name, False, start, end, strlen(name),
01162 user_data))
01163 alist->append(new oqmlAtom_oid(oid, cls));
01164
01165 oqmlObjectManager::releaseObject(o);
01166 continue;
01167 }
01168
01169 Collection *coll = 0;
01170 if (d->is_coll)
01171 {
01172 s = oqmlCollManage(node, db, ctx, d, o, coll);
01173 SCHECK(s);
01174 if (!coll || !coll->getOidC().isValid())
01175 {
01176 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL, ("\n"));
01177 continue;
01178 }
01179 }
01180
01181 int nn = 0;
01182 for (ind = s_ind; ind <= e_ind; ind++)
01183 {
01184 OQML_CHECK_INTR();
01185 int nb;
01186 Bool isnull;
01187 Data data = 0;
01188 is = Success;
01189
01190 delete dx->icurs;
01191 dx->icurs = 0;
01192
01193 int pp;
01194 for (pp = 0; ; nn++, pp++)
01195 {
01196 OQML_CHECK_INTR();
01197 const Attribute *xattr = 0;
01198 Size size;
01199
01200 if (d->mode == Attribute::composedMode)
01201 {
01202 data = 0;
01203 is = oqmlIterGetValue(node, db, ctx, o, dctx, n, pn,
01204 &data,
01205 &isnull, Attribute::directAccess,
01206 ind, xattr, size);
01207
01208 if (is && is->getStatus() ==
01209 IDB_OUT_OF_RANGE_ATTRIBUTE_ERROR)
01210 {
01211 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
01212 ("%s%s [index #%d] <out of range>\n",
01213 AND(nn),
01214 (d->is_coll ? "not in collection": "don't match"),
01215 ind));
01216 nn++;
01217 if (!dx->icurs)
01218 break;
01219 continue;
01220 }
01221
01222 ICHECK(is);
01223
01224 if (data)
01225 nb = strlen((char *)data) + 1;
01226 else
01227 nb = 0;
01228 }
01229 else
01230 {
01231 data = d->e_data;
01232 is = oqmlIterGetValue(node, db, ctx, o, dctx, n, pn,
01233 &data, &isnull, 1, ind, xattr,
01234 size);
01235
01236 if (is && is->getStatus() ==
01237 IDB_OUT_OF_RANGE_ATTRIBUTE_ERROR)
01238 {
01239 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
01240 ("%s%s [index #%d] <out of range>\n",
01241 AND(nn),
01242 (d->is_coll ? "not in collection": "don't match"),
01243 ind));
01244 nn++;
01245 if (!dx->icurs)
01246 break;
01247 continue;
01248 }
01249
01250 ICHECK(is);
01251 nb = size;
01252 }
01253
01254 Bool isin = False;
01255 if (d->is_coll && start)
01256 {
01257 Collection::ItemId where;
01258 is = coll->isIn(OQML_ATOM_OIDVAL(start), isin, &where);
01259 ICHECK(is);
01260 if (requal_ident)
01261 {
01262 s = oqml_add_coll_atom(node, ctx, requal_ident, start);
01263 if (s) return s;
01264 }
01265 }
01266
01267 if (isin || (*cmp)(data, isnull, start, end, nb, user_data))
01268 {
01269 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
01270 ("%s%s [index #%d]\n", AND(nn),
01271 (d->is_coll ? "is in collection" : "matches"),
01272 ind));
01273 if (pn > 1)
01274 {
01275 oqmlAtom *r = new oqmlAtom_oid(oid, cls);
01276 s = oqmlMakeIter(node, db, ctx, dctx, pn-1, alist, r, r,
01277 equal_oid, depth+1, thread_cnt);
01278 SCHECK(s);
01279 }
01280 else
01281 {
01282 alist->append(new oqmlAtom_oid(oid, cls));
01283 OQML_CHECK_MAX_ATOMS(alist, ctx, 0);
01284 }
01285 }
01286 else
01287 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL,
01288 ("%s%s [index #%d]\n",
01289 AND(nn),
01290 (d->is_coll ? "not in collection": "don't match"),
01291 ind));
01292
01293 if (!dx->icurs)
01294 break;
01295 }
01296
01297 if (is && is->getStatus() == IDB_OUT_OF_RANGE_ATTRIBUTE_ERROR)
01298 {
01299 if (!pp)
01300 break;
01301 is = Success;
01302 }
01303
01304 ICHECK(is);
01305 }
01306
01307 IDB_LOG_X(IDB_LOG_IDX_SEARCH_DETAIL, ("\n"));
01308 oqmlObjectManager::releaseObject(o);
01309 }
01310
01311 Exception::setMode(omode);
01312 return oqmlSuccess;
01313 }
01314
01315 static oqmlStatus *
01316 oqmlMakeIter(oqmlNode *node,
01317 Database *db, oqmlContext *ctx, oqmlDotContext *dctx, int n,
01318 oqmlAtomList *alist, oqmlAtom *start, oqmlAtom *end,
01319 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *,
01320 const oqmlAtom *, int, void *),
01321 int depth,
01322 int thread_cnt,
01323 void *user_data,
01324 eyedbsm::Boolean sexcl, eyedbsm::Boolean eexcl)
01325 {
01326 if (n < 0)
01327 return new oqmlStatus(node, "invalid query construct");
01328
01329 oqmlDotDesc *d = &dctx->desc[n];
01330
01331
01332 if (!depth)
01333 thread_cnt = getThreadCount(ctx);;
01334
01335 if (d->idx_cnt)
01336 {
01337 if (d->mode == Attribute::composedMode)
01338 return oqmlMakeIter_idx_comp(node, db, ctx, dctx, n, alist, start, end,
01339 cmp, depth, thread_cnt,
01340 user_data, sexcl, eexcl);
01341 else
01342 return oqmlMakeIter_idx_item(node, db, ctx, dctx, n, alist, start, end,
01343 cmp, depth, thread_cnt,
01344 user_data, sexcl, eexcl);
01345
01346 }
01347 else
01348 return oqmlMakeIter_noidx(node, db, ctx, dctx, n, alist, start, end,
01349 cmp, depth, thread_cnt,
01350 user_data, sexcl, eexcl);
01351 }
01352
01353 oqmlStatus *
01354 oqmlIndexIter(Database *db, oqmlContext *ctx, oqmlNode *node,
01355 oqmlDotContext *dctx, oqmlDotDesc *d,
01356 oqmlAtomList **alist)
01357 {
01358 const Class *cls = dctx->dot_type.cls ? dctx->dot_type.cls :
01359 d->attr->getClass();
01360 oqmlATOMTYPE atom_type = dctx->dot_type.type;
01361
01362 int offset = sizeof(char);
01363
01364 if (d->mode != Attribute::composedMode) {
01365 if (cls->asCollectionClass() && !d->attr->isIndirect())
01366 offset = 0;
01367 else {
01368 offset += sizeof(eyedblib::int32);
01369 #ifdef IDB_UNDEF_ENUM_HINT
01370 if (cls->asEnumClass())
01371 offset += sizeof(char);
01372 #endif
01373 }
01374 }
01375
01376
01377 int thread_cnt = 0;
01378 for (int n = 0; n < d->idx_cnt; n++)
01379 {
01380 eyedbsm::Idx *idx = d->idxse[n];
01381
01382 IDB_LOG(IDB_LOG_IDX_SEARCH,
01383 ("Using Index #%d '%s' for full search%s\n",
01384 n, (d->idxs[n] ? d->idxs[n]->getAttrpath().c_str() : ""),
01385 (!idx ? " SE index is null" : "")));
01386
01387 if (!idx)
01388 continue;
01389
01390 eyedbsm::IdxCursor *curs;
01391
01392 if (idx->asHIdx())
01393 curs = new eyedbsm::HIdxCursor(idx->asHIdx(), 0, 0, eyedbsm::False, eyedbsm::False, 0,
01394 0, thread_cnt);
01395 else
01396 curs = new eyedbsm::BIdxCursor(idx->asBIdx(), 0, 0, eyedbsm::False, eyedbsm::False);
01397
01398 for (;;)
01399 {
01400 eyedbsm::Boolean found;
01401 Oid oid[2];
01402 *((char *)d->key->getKey()) = 0;
01403 eyedbsm::Status se;
01404 OQML_CHECK_INTR();
01405
01406 if ((se = curs->next(&found, oid, d->key)) == eyedbsm::Success)
01407 {
01408 if (!found)
01409 break;
01410 unsigned char *key = (unsigned char *)(d->key->getKey());
01411 if (offset && ISNULL(key[0]))
01412 (*alist)->append(new oqmlAtom_null());
01413 else
01414 (*alist)->append(oqmlAtom::make_atom(key+offset,
01415 atom_type, cls));
01416
01417 OQML_CHECK_MAX_ATOMS(*alist, ctx, delete curs);
01418 }
01419 else
01420 {
01421 delete curs;
01422 return new oqmlStatus(node, eyedbsm::statusGet(se));
01423 }
01424 }
01425
01426 delete curs;
01427 }
01428
01429 return oqmlSuccess;
01430 }
01431
01432
01433 oqmlEqualIterator::oqmlEqualIterator(Database *_db, oqmlDotContext *_dctx,
01434 oqmlAtom *_start, oqmlAtom *_end, void *_ud) :
01435 oqmlIterator(_db, _dctx, _start, _end, _ud)
01436 {
01437 }
01438
01439 static oqmlBool equal_op(Data data, Bool isnull, const oqmlAtom *start,
01440 const oqmlAtom *end, int len_data, void *)
01441 {
01442 if (!start) return oqml_False;
01443 return start->compare(data, len_data, isnull, oqmlEQUAL);
01444 }
01445
01446 oqmlStatus *
01447 oqmlIterator::begin(oqmlContext *ctx)
01448 {
01449 s_dctx = dot_ctx;
01450 s_and_ctx = 0;
01451
01452
01453
01454 if (dot_ctx && dot_ctx->count == 0 && dot_ctx->tctx)
01455 {
01456 oqmlDotContext *dctx;
01457
01458 if (!(dctx = dot_ctx->tctx))
01459 return new oqmlStatus("fatal error in iterator");
01460
01461 s_and_ctx = ctx->getAndContext();
01462
01463 ctx->setAndContext(oqmlAtomList::andOids(dot_ctx->tlist, s_and_ctx));
01464
01465 dot_ctx = dctx;
01466
01467 return oqmlSuccess;
01468 }
01469
01470 return oqmlSuccess;
01471 }
01472
01473 void
01474 oqmlIterator::commit(oqmlContext *ctx)
01475 {
01476 ctx->setAndContext(s_and_ctx);
01477 dot_ctx = s_dctx;
01478 }
01479
01480 oqmlStatus *
01481 oqmlEqualIterator::eval(oqmlNode *node, oqmlContext *ctx,
01482 oqmlAtomList **xalist)
01483 {
01484 OQML_MAKE_RBAG(xalist, rlist);
01485
01486 oqmlStatus *s = begin(ctx);
01487
01488 if (s)
01489 return s;
01490
01491 oqmlAtomList *al = ctx->getAndContext();
01492
01493 if (al)
01494 {
01495 s = evalAnd(node, ctx, al, equal_op, rlist);
01496 commit(ctx);
01497 return s;
01498 }
01499
01500 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist, start,
01501 end, equal_op, 0);
01502 commit(ctx);
01503 return s;
01504 }
01505
01506 oqmlStatus *oqmlEqual::makeIterator(Database *db, oqmlDotContext *dctx,
01507 oqmlAtom *atom)
01508 {
01509 delete iter;
01510 iter = new oqmlEqualIterator(db, dctx, atom, atom);
01511 return oqmlSuccess;
01512 }
01513
01514
01515 oqmlDiffIterator::oqmlDiffIterator(Database *_db, oqmlDotContext *_dctx,
01516 oqmlAtom *_start, oqmlAtom *_end, void *_ud) :
01517 oqmlIterator(_db, _dctx, _start, _end, _ud)
01518 {
01519 }
01520
01521 static oqmlBool diff_op(Data data, Bool isnull, const oqmlAtom *,
01522 const oqmlAtom *, int len_data, void *ud)
01523 {
01524 return ((oqmlAtom *)ud)->compare(data, len_data, isnull, oqmlDIFF);
01525 }
01526
01527 oqmlStatus *
01528 oqmlDiffIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
01529 {
01530 OQML_MAKE_RBAG(xalist, rlist);
01531
01532 oqmlStatus *s = begin(ctx);
01533
01534 if (s)
01535 return s;
01536
01537 oqmlAtomList *al = ctx->getAndContext();
01538
01539 if (al)
01540 {
01541 s = evalAnd(node, ctx, al, diff_op, rlist);
01542 commit(ctx);
01543 return s;
01544 }
01545
01546 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist,
01547 start, end,
01548 diff_op, 0, 0, user_data);
01549 commit(ctx);
01550 return s;
01551 }
01552
01553 oqmlStatus *oqmlDiff::makeIterator(Database *db, oqmlDotContext *dctx,
01554 oqmlAtom *atom)
01555 {
01556 delete iter;
01557 iter = new oqmlDiffIterator(db, dctx, 0, 0, atom);
01558 return oqmlSuccess;
01559 }
01560
01561
01562 oqmlInfIterator::oqmlInfIterator(Database *_db, oqmlDotContext *_dctx,
01563 oqmlAtom *_start, oqmlAtom *_end, void *_ud) :
01564 oqmlIterator(_db, _dctx, _start, _end, _ud)
01565 {
01566 }
01567
01568 static oqmlBool sup_op(Data data, Bool isnull, const oqmlAtom *start,
01569 const oqmlAtom *end, int len_data, void *);
01570
01571 static oqmlBool inf_op(Data data, Bool isnull, const oqmlAtom *start,
01572 const oqmlAtom *end, int len_data, void *)
01573 {
01574 if (!end) return oqml_False;
01575
01576 return OQMLBOOL(end->compare(data, len_data, isnull, oqmlINF) &&
01577 (!start || start->compare(data, len_data, isnull, oqmlSUPEQ)));
01578 }
01579
01580 oqmlStatus *
01581 oqmlInfIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
01582 {
01583 assert(node->getType() == oqmlINF || node->getType() == oqmlSUP);
01584 OQML_MAKE_RBAG(xalist, rlist);
01585
01586 oqmlStatus *s = begin(ctx);
01587
01588 if (s)
01589 return s;
01590
01591 oqmlAtomList *al = ctx->getAndContext();
01592
01593 if (al)
01594 {
01595 s = evalAnd(node, ctx, al,
01596 (node->getType() == oqmlINF ? inf_op : sup_op), rlist);
01597 commit(ctx);
01598 return s;
01599 }
01600
01601 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1,
01602 rlist, start, end,
01603 (node->getType() == oqmlINF ? inf_op : sup_op),
01604 0, 0, 0, eyedbsm::False, eyedbsm::True);
01605 commit(ctx);
01606 return s;
01607 }
01608
01609 oqmlStatus *oqmlInf::makeIterator(Database *db, oqmlDotContext *dctx,
01610 oqmlAtom *atom)
01611 {
01612 delete iter;
01613
01614 if (type == oqmlINF)
01615 iter = new oqmlInfIterator(db, dctx, 0, atom);
01616 else
01617 iter = new oqmlSupIterator(db, dctx, atom, 0);
01618
01619 return oqmlSuccess;
01620 }
01621
01622
01623 oqmlInfEqIterator::oqmlInfEqIterator(Database *_db, oqmlDotContext *_dctx,
01624 oqmlAtom *_start, oqmlAtom *_end, void *_ud) :
01625 oqmlIterator(_db, _dctx, _start, _end, _ud)
01626 {
01627 }
01628
01629 static oqmlBool supeq_op(Data data, Bool isnull, const oqmlAtom *start,
01630 const oqmlAtom *end, int len_data, void *);
01631 static oqmlBool infeq_op(Data data, Bool isnull, const oqmlAtom *start,
01632 const oqmlAtom *end, int len_data, void *)
01633 {
01634 if (!end) return oqml_False;
01635
01636 return OQMLBOOL(end->compare(data, len_data, isnull, oqmlINFEQ) &&
01637 (!start || start->compare(data, len_data, isnull, oqmlSUPEQ)));
01638 }
01639
01640 oqmlStatus *
01641 oqmlInfEqIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
01642 {
01643 assert(node->getType() == oqmlINFEQ || node->getType() == oqmlSUPEQ);
01644 OQML_MAKE_RBAG(xalist, rlist);
01645
01646 oqmlStatus *s = begin(ctx);
01647
01648 if (s)
01649 return s;
01650
01651 oqmlAtomList *al = ctx->getAndContext();
01652 if (al) {
01653 s = evalAnd(node, ctx, al,
01654 (node->getType() == oqmlINFEQ ? infeq_op : supeq_op),
01655 rlist);
01656 commit(ctx);
01657 return s;
01658 }
01659
01660 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1,
01661 rlist, start, end,
01662 (node->getType() == oqmlINFEQ ? infeq_op : supeq_op), 0);
01663 commit(ctx);
01664 return s;
01665 }
01666
01667 oqmlStatus *oqmlInfEq::makeIterator(Database *db, oqmlDotContext *dctx,
01668 oqmlAtom *atom)
01669 {
01670 delete iter;
01671 if (type == oqmlINFEQ)
01672 iter = new oqmlInfEqIterator(db, dctx, 0, atom);
01673 else
01674 iter = new oqmlSupEqIterator(db, dctx, atom, 0);
01675
01676 return oqmlSuccess;
01677 }
01678
01679
01680 oqmlSupIterator::oqmlSupIterator(Database *_db, oqmlDotContext *_dctx,
01681 oqmlAtom *_start, oqmlAtom *_end, void *_ud) :
01682 oqmlIterator(_db, _dctx, _start, _end, _ud)
01683 {
01684 }
01685
01686 static oqmlBool sup_op(Data data, Bool isnull, const oqmlAtom *start,
01687 const oqmlAtom *end, int len_data, void *)
01688 {
01689 if (!start) return oqml_False;
01690
01691 return OQMLBOOL(start->compare(data, len_data, isnull, oqmlSUP) &&
01692 (!end || end->compare(data, len_data, isnull, oqmlINFEQ)));
01693 }
01694
01695 oqmlStatus *
01696 oqmlSupIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
01697 {
01698 assert(node->getType() == oqmlSUP || node->getType() == oqmlINF);
01699 OQML_MAKE_RBAG(xalist, rlist);
01700
01701 oqmlStatus *s = begin(ctx);
01702
01703 if (s)
01704 return s;
01705
01706 oqmlAtomList *al = ctx->getAndContext();
01707
01708 if (al)
01709 {
01710 s = evalAnd(node, ctx, al,
01711 (node->getType() == oqmlSUP ? sup_op : inf_op), rlist);
01712 commit(ctx);
01713 return s;
01714 }
01715
01716 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1,
01717 rlist, start, end,
01718 (node->getType() == oqmlSUP ? sup_op : inf_op), 0, 0, 0,
01719 eyedbsm::True, eyedbsm::False);
01720 commit(ctx);
01721 return s;
01722 }
01723
01724 oqmlStatus *oqmlSup::makeIterator(Database *db, oqmlDotContext *dctx,
01725 oqmlAtom *atom)
01726 {
01727 delete iter;
01728
01729 if (type == oqmlSUP)
01730 iter = new oqmlSupIterator(db, dctx, atom, 0);
01731 else
01732 iter = new oqmlInfIterator(db, dctx, 0, atom);
01733
01734 return oqmlSuccess;
01735 }
01736
01737
01738 oqmlSupEqIterator::oqmlSupEqIterator(Database *_db, oqmlDotContext *_dctx,
01739 oqmlAtom *_start, oqmlAtom *_end,
01740 void *_ud) :
01741 oqmlIterator(_db, _dctx, _start, _end, _ud)
01742 {
01743 }
01744
01745 #define XSTROPT
01746
01747 struct xString {
01748 xString(const char *_data, bool capstr = true) {
01749 #ifdef XSTROPT
01750 if (strlen(_data) >= sizeof sdata)
01751 data = new char[strlen(_data)+1];
01752 else
01753 data = sdata;
01754 #else
01755 data = new char[strlen(_data)+1];
01756 #endif
01757
01758 if (capstr)
01759 capstring(data, _data);
01760 else
01761 strcpy(data, _data);
01762 }
01763
01764 ~xString() {
01765 #ifdef XSTROPT
01766 if (data != sdata)
01767 #endif
01768 delete [] data;
01769 }
01770
01771 static void capstring(char *dest, const char *src) {
01772 char c;
01773 while (c = *src++)
01774 *dest++ = (c >= 'a' && c <= 'z') ? c + 'A' - 'a' : c;
01775 *dest = 0;
01776 }
01777
01778 #ifdef XSTROPT
01779 char sdata[128];
01780 #endif
01781 char *data;
01782 };
01783
01784 static oqmlBool supeq_op(Data data, Bool isnull, const oqmlAtom *start,
01785 const oqmlAtom *end, int len_data, void *capstr)
01786 {
01787 if (!start) return oqml_False;
01788
01789 if (capstr) {
01790 xString s((const char *)data);
01791 return OQMLBOOL(start->compare((Data)s.data, len_data, isnull,
01792 oqmlSUPEQ) &&
01793 (!end || end->compare((Data)s.data, len_data, isnull,
01794 oqmlINFEQ)));
01795 }
01796 return OQMLBOOL(start->compare(data, len_data, isnull, oqmlSUPEQ) &&
01797 (!end || end->compare(data, len_data, isnull, oqmlINFEQ)));
01798 }
01799
01800 oqmlStatus *
01801 oqmlSupEqIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
01802 {
01803
01804
01805
01806
01807 OQML_MAKE_RBAG(xalist, rlist);
01808
01809 oqmlStatus *s = begin(ctx);
01810
01811 if (s)
01812 return s;
01813
01814 oqmlAtomList *al = ctx->getAndContext();
01815 if (al) {
01816 s = evalAnd(node, ctx, al,
01817 (node->getType() == oqmlSUPEQ ||
01818 node->getType() == oqmlREGCMP ? supeq_op : infeq_op),
01819 rlist);
01820 commit(ctx);
01821 return s;
01822 }
01823
01824 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1,
01825 rlist, start, end,
01826 (node->getType() == oqmlSUPEQ ||
01827 node->getType() == oqmlREGCMP ? supeq_op : infeq_op),
01828 0, 0, user_data, eyedbsm::False, eyedbsm::True);
01829 commit(ctx);
01830 return s;
01831 }
01832
01833 oqmlStatus *oqmlSupEq::makeIterator(Database *db, oqmlDotContext *dctx,
01834 oqmlAtom *atom)
01835 {
01836 delete iter;
01837
01838 if (type == oqmlSUPEQ)
01839 iter = new oqmlSupEqIterator(db, dctx, atom, 0);
01840 else
01841 iter = new oqmlInfEqIterator(db, dctx, 0, atom);
01842
01843 return oqmlSuccess;
01844 }
01845
01846
01847 oqmlSubStrIterator::oqmlSubStrIterator(Database *_db, oqmlDotContext *_dctx,
01848 oqmlAtom *_start, oqmlAtom *_end,
01849 void *_ud) :
01850 oqmlIterator(_db, _dctx, _start, _end, _ud)
01851 {
01852 }
01853
01854 static oqmlBool substr_op(Data data, Bool isnull, const oqmlAtom *,
01855 const oqmlAtom *, int len_data, void *udata)
01856 {
01857 if (isnull) return oqml_False;
01858
01859 const char *str = OQML_ATOM_STRVAL((oqmlAtom *)udata);
01860
01861 if (*str == CI) {
01862 xString s((const char *)data);
01863 return OQMLBOOL(strstr((const char *)s.data, str+1));
01864 }
01865
01866 return OQMLBOOL(strstr((const char *)data, str+1));
01867 }
01868
01869 oqmlStatus *
01870 oqmlSubStrIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
01871 {
01872 OQML_MAKE_RBAG(xalist, rlist);
01873
01874 oqmlStatus *s = begin(ctx);
01875
01876 if (s)
01877 return s;
01878
01879 oqmlAtomList *al = ctx->getAndContext();
01880 if (al) {
01881 s = evalAnd(node, ctx, al, substr_op, rlist);
01882 commit(ctx);
01883 return s;
01884 }
01885
01886 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1,
01887 rlist, start, end, substr_op,
01888 0, 0, user_data, eyedbsm::False, eyedbsm::True);
01889 commit(ctx);
01890 return s;
01891 }
01892
01893
01894 oqmlBetweenIterator::oqmlBetweenIterator(Database *_db,
01895 oqmlDotContext *_dctx,
01896 oqmlAtom *_start, oqmlAtom *_end,
01897 void *_ud) :
01898 oqmlIterator(_db, _dctx, _start, _end, _ud)
01899 {
01900 }
01901
01902 static oqmlBool between_op(Data data, Bool isnull, const oqmlAtom *start,
01903 const oqmlAtom *end, int len_data, void *ud)
01904 {
01905 oqmlAtom *atom = (oqmlAtom *)ud;
01906 assert(atom->as_range());
01907
01908 if (!start) return oqml_False;
01909 return OQMLBOOL(start->compare(data, len_data, isnull,
01910 atom->as_range()->from_incl ? oqmlSUPEQ : oqmlSUP) &&
01911 end->compare(data, len_data, isnull,
01912 atom->as_range()->to_incl ? oqmlINFEQ : oqmlINF));
01913 }
01914
01915 oqmlStatus *
01916 oqmlBetweenIterator::eval(oqmlNode *node, oqmlContext *ctx,
01917 oqmlAtomList **xalist)
01918 {
01919 OQML_MAKE_RBAG(xalist, rlist);
01920
01921 oqmlStatus *s = begin(ctx);
01922
01923 if (s)
01924 return s;
01925
01926 oqmlAtomList *al = ctx->getAndContext();
01927
01928 if (al)
01929 {
01930 s = evalAnd(node, ctx, al, between_op, rlist);
01931 commit(ctx);
01932 return s;
01933 }
01934
01935 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist, start,
01936 end, between_op, 0, 0, user_data);
01937 commit(ctx);
01938 return s;
01939 }
01940
01941 oqmlStatus *oqmlBetween::makeIterator(Database *db, oqmlDotContext *dctx,
01942 oqmlAtom *atom)
01943 {
01944 assert(atom->as_range());
01945
01946 delete iter;
01947 iter = new oqmlBetweenIterator(db, dctx, atom->as_range()->from,
01948 atom->as_range()->to, atom);
01949 return oqmlSuccess;
01950 }
01951
01952
01953
01954 oqmlNotBetweenIterator::oqmlNotBetweenIterator(Database *_db,
01955 oqmlDotContext *_dctx,
01956 oqmlAtom *_start, oqmlAtom *_end,
01957 void *_ud) :
01958 oqmlIterator(_db, _dctx, _start, _end, _ud)
01959 {
01960 }
01961
01962 static oqmlBool not_between_op(Data data, Bool isnull,
01963 const oqmlAtom *,
01964 const oqmlAtom *, int len_data, void *ud)
01965 {
01966 oqmlAtom *atom = (oqmlAtom *)ud;
01967 assert(atom->as_range());
01968
01969 oqmlAtom *start = atom->as_range()->from;
01970 oqmlAtom *end = atom->as_range()->to;
01971
01972 return OQMLBOOL(start->compare(data, len_data, isnull,
01973 atom->as_range()->from_incl ? oqmlINF : oqmlINFEQ) ||
01974 end->compare(data, len_data, isnull,
01975 atom->as_range()->to_incl ? oqmlSUP : oqmlSUPEQ));
01976 }
01977
01978 oqmlStatus *
01979 oqmlNotBetweenIterator::eval(oqmlNode *node, oqmlContext *ctx,
01980 oqmlAtomList **xalist)
01981 {
01982 OQML_MAKE_RBAG(xalist, rlist);
01983
01984 oqmlStatus *s = begin(ctx);
01985
01986 if (s)
01987 return s;
01988
01989 oqmlAtomList *al = ctx->getAndContext();
01990
01991 if (al)
01992 {
01993 s = evalAnd(node, ctx, al, not_between_op, rlist);
01994 commit(ctx);
01995 return s;
01996 }
01997
01998 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist,
01999 start, end,
02000 not_between_op, 0, 0, user_data);
02001 commit(ctx);
02002 return s;
02003 }
02004
02005 oqmlStatus *oqmlNotBetween::makeIterator(Database *db, oqmlDotContext *dctx,
02006 oqmlAtom *atom)
02007 {
02008 delete iter;
02009 iter = new oqmlNotBetweenIterator(db, dctx, 0, 0, atom);
02010 return oqmlSuccess;
02011 }
02012
02013
02014
02015 oqmlRegCmpIterator::oqmlRegCmpIterator(Database *_db, oqmlDotContext *_dctx,
02016 oqmlAtom *_start, oqmlAtom *_end, void *_ud) : oqmlIterator(_db, _dctx, _start, _end, _ud)
02017 {
02018 }
02019
02020 static oqmlBool regcmp_op(Data data, Bool isnull, const oqmlAtom *start,
02021 const oqmlAtom *end, int len_data, void *re)
02022 {
02023 #ifdef USE_LIBGEN
02024 return OQMLBOOL(regex((char *)re, (char *)data) != 0);
02025 #endif
02026 return OQMLBOOL( regexec( (regex_t *)re, (char *)data, 0, (regmatch_t *)0, 0) == 0 );
02027 }
02028
02029 static Bool
02030 meta_chars_in(const char *s)
02031 {
02032 char c;
02033
02034 while (c = *s++)
02035 if (c == '[' || c == ']' || c == '*' || c == '.' || c == '(' ||
02036 c == ')' || c == '\\' || c == '$')
02037 return True;
02038
02039 return False;
02040 }
02041
02042 oqmlIterator *
02043 oqmlRegex::makeIter(Database *db, oqmlDotContext *dctx,
02044 oqmlAtom *atom, bool capstr)
02045 {
02046 const char *s = OQML_ATOM_STRVAL(atom);
02047
02048 if (!meta_chars_in(s)) {
02049 if (*s == '^') {
02050 const char *start = &s[1];
02051 char *end = strdup(start);
02052 ++end[strlen(end)-1];
02053
02054 xString xstart(start, capstr);
02055 xString xend(end, capstr);
02056
02057 oqmlIterator *i = new oqmlSupEqIterator(db, dctx,
02058 new oqmlAtom_string(xstart.data),
02059 new oqmlAtom_string(xend.data),
02060 (void *)capstr);
02061 free(end);
02062 return i;
02063 }
02064
02065 xString xs(s, capstr);
02066 return new oqmlSubStrIterator(db, dctx, 0, 0,
02067 new oqmlAtom_string
02068 ((str_convert(capstr ? CI : CS) + xs.data).c_str()));
02069 }
02070
02071 if (capstr)
02072 return new oqmlRegICmpIterator(db, dctx, 0, 0, re);
02073
02074 return new oqmlRegCmpIterator(db, dctx, 0, 0, re);
02075 }
02076
02077 oqmlStatus *
02078 oqmlRegCmpIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
02079 {
02080 OQML_MAKE_RBAG(xalist, rlist);
02081
02082 oqmlStatus *s = begin(ctx);
02083
02084 if (s)
02085 return s;
02086
02087 oqmlAtomList *al = ctx->getAndContext();
02088 if (al)
02089 {
02090 s = evalAnd(node, ctx, al, regcmp_op, rlist);
02091 commit(ctx);
02092 return s;
02093 }
02094
02095 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist, start, end,
02096 (start ? supeq_op : regcmp_op), 0, 0, user_data,
02097 eyedbsm::False, (start ? eyedbsm::True : eyedbsm::False));
02098 commit(ctx);
02099 return s;
02100 }
02101
02102 oqmlStatus *oqmlRegCmp::makeIterator(Database *db, oqmlDotContext *dctx,
02103 oqmlAtom *atom)
02104 {
02105 delete iter;
02106 iter = makeIter(db, dctx, atom, false);
02107 return oqmlSuccess;
02108 }
02109
02110
02111 oqmlRegICmpIterator::oqmlRegICmpIterator(Database *_db, oqmlDotContext *_dctx,
02112 oqmlAtom *_start, oqmlAtom *_end, void *_ud) : oqmlIterator(_db, _dctx, _start, _end, _ud)
02113 {
02114 }
02115
02116 static oqmlBool
02117 regicmp_op(Data xdata, Bool isnull, const oqmlAtom *start,
02118 const oqmlAtom *end, int len_data, void *re)
02119 {
02120 xString s((const char *)xdata);
02121
02122 #ifdef USE_LIBGEN
02123 return OQMLBOOL(regex((char *)re, s.data) != 0);
02124 #endif
02125 return OQMLBOOL( regexec( (regex_t *)re, s.data, 0, (regmatch_t *)0, 0) == 0);
02126 }
02127
02128 oqmlStatus *
02129 oqmlRegICmpIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
02130 {
02131 OQML_MAKE_RBAG(xalist, rlist);
02132
02133 oqmlStatus *s = begin(ctx);
02134
02135 if (s)
02136 return s;
02137
02138 oqmlAtomList *al = ctx->getAndContext();
02139 if (al)
02140 {
02141 s = evalAnd(node, ctx, al, regicmp_op, rlist);
02142 commit(ctx);
02143 return s;
02144 }
02145
02146 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist, start, end,
02147 regicmp_op, 0, 0, user_data);
02148 commit(ctx);
02149 return s;
02150 }
02151
02152 oqmlStatus *oqmlRegICmp::makeIterator(Database *db, oqmlDotContext *dctx,
02153 oqmlAtom *atom)
02154 {
02155 delete iter;
02156 iter = makeIter(db, dctx, atom, true);
02157 return oqmlSuccess;
02158 }
02159
02160
02161 oqmlRegDiffIterator::oqmlRegDiffIterator(Database *_db, oqmlDotContext *_dctx,
02162 oqmlAtom *_start, oqmlAtom *_end, void *_ud) : oqmlIterator(_db, _dctx, _start, _end, _ud)
02163 {
02164 }
02165
02166 static oqmlBool regdiff_op(Data data, Bool isnull, const oqmlAtom *start,
02167 const oqmlAtom *end, int len_data, void *re)
02168 {
02169 #ifdef USE_LIBGEN
02170 return OQMLBOOL(regex((char *)re, (char *)data) == 0);
02171 #endif
02172 return OQMLBOOL( regexec( (regex_t *)re, (char *)data, 0, (regmatch_t *)0, 0) != 0);
02173 }
02174
02175 oqmlStatus *
02176 oqmlRegDiffIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
02177 {
02178 OQML_MAKE_RBAG(xalist, rlist);
02179
02180 oqmlStatus *s = begin(ctx);
02181
02182 if (s)
02183 return s;
02184
02185 oqmlAtomList *al = ctx->getAndContext();
02186 if (al)
02187 {
02188 s = evalAnd(node, ctx, al, regdiff_op, rlist);
02189 commit(ctx);
02190 return s;
02191 }
02192
02193 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist, start, end,
02194 regdiff_op, 0, 0, user_data);
02195 commit(ctx);
02196 return s;
02197 }
02198
02199 oqmlStatus *oqmlRegDiff::makeIterator(Database *db, oqmlDotContext *dctx,
02200 oqmlAtom *atom)
02201 {
02202 delete iter;
02203 iter = new oqmlRegDiffIterator(db, dctx, 0, 0, re);
02204 return oqmlSuccess;
02205 }
02206
02207
02208 oqmlRegIDiffIterator::oqmlRegIDiffIterator(Database *_db, oqmlDotContext *_dctx,
02209 oqmlAtom *_start, oqmlAtom *_end, void *_ud) : oqmlIterator(_db, _dctx, _start, _end, _ud)
02210 {
02211 }
02212
02213 static oqmlBool
02214 regidiff_op(Data xdata, Bool isnull, const oqmlAtom *start,
02215 const oqmlAtom *end, int len_data, void *re)
02216 {
02217 xString s((const char *)xdata);
02218
02219 #ifdef USE_LIBGEN
02220 return OQMLBOOL(regex((char *)re, s.data) == 0);
02221 #endif
02222 return OQMLBOOL( regexec( (regex_t *)re, s.data, 0, (regmatch_t *)0, 0) != 0);
02223 }
02224
02225 oqmlStatus *
02226 oqmlRegIDiffIterator::eval(oqmlNode *node, oqmlContext *ctx, oqmlAtomList **xalist)
02227 {
02228 OQML_MAKE_RBAG(xalist, rlist);
02229
02230 oqmlStatus *s = begin(ctx);
02231
02232 if (s)
02233 return s;
02234
02235 oqmlAtomList *al = ctx->getAndContext();
02236 if (al)
02237 {
02238 s = evalAnd(node, ctx, al, regidiff_op, rlist);
02239 commit(ctx);
02240 return s;
02241 }
02242
02243 s = oqmlMakeIter(node, db, ctx, dot_ctx, dot_ctx->count - 1, rlist, start, end,
02244 regidiff_op, 0, 0, user_data);
02245 commit(ctx);
02246 return s;
02247 }
02248
02249 oqmlStatus *oqmlRegIDiff::makeIterator(Database *db, oqmlDotContext *dctx,
02250 oqmlAtom *atom)
02251 {
02252 delete iter;
02253 iter = new oqmlRegIDiffIterator(db, dctx, 0, 0, re);
02254 return oqmlSuccess;
02255 }
02256
02257
02258
02259 oqmlIterator::oqmlIterator(Database *_db,
02260 oqmlDotContext *_dctx, oqmlAtom *_start,
02261 oqmlAtom *_end, void *_ud)
02262 {
02263 db = _db;
02264 dot_ctx = _dctx;
02265
02266 start = (_start ? _start->copy() : 0);
02267 end = (_end ? _end->copy() : 0);
02268 user_data = _ud;
02269 }
02270
02271 oqmlStatus *
02272 oqmlIterator::getValue(oqmlNode *node,
02273 oqmlContext *ctx, const Oid *oid, Data buff,
02274 Data &data, int &len, Bool &isnull)
02275 {
02276 oqmlAtomList *alist;
02277 Object *o;
02278 oqmlStatus *s;
02279
02280 isnull = False;
02281 s = oqmlObjectManager::getObject(node, db, oid, o, oqml_False);
02282 if (s) return s;
02283
02284 alist = new oqmlAtomList();
02285 s = dot_ctx->eval_perform(db, ctx, o, 0, 1, &alist);
02286
02287 oqmlObjectManager::releaseObject(o);
02288
02289 if (s)
02290 return s;
02291
02292 if (alist->cnt != 1)
02293 {
02294 len = 0;
02295 data = buff;
02296 memset(buff, 0, 16);
02297 return oqmlSuccess;
02298 }
02299
02300 oqmlAtom *value = alist->first;
02301 if (value->as_null())
02302 {
02303 isnull = True;
02304 return oqmlSuccess;
02305 }
02306
02307 Data val;
02308 Size size;
02309
02310 size = 16;
02311
02312 if (value->getData(buff, &val, size, len))
02313 data = (val ? val : buff);
02314
02315 len = size;
02316 return oqmlSuccess;
02317 }
02318
02319 oqmlStatus *
02320 oqmlIterator::evalAndRealize(oqmlNode *node, oqmlContext *ctx,
02321 oqmlAtom *a,
02322 oqmlBool (*cmp)(Data, Bool,
02323 const oqmlAtom *,
02324 const oqmlAtom *,
02325 int, void *),
02326 oqmlAtomList *alist)
02327 {
02328 oqmlStatus *s;
02329
02330 if (OQML_IS_COLL(a))
02331 {
02332 oqmlAtom *x = OQML_ATOM_COLLVAL(a)->first;
02333 while (x)
02334 {
02335 s = evalAndRealize(node, ctx, x, cmp, alist);
02336 if (s) return s;
02337 x = x->next;
02338 }
02339
02340 return oqmlSuccess;
02341 }
02342
02343 if (a->type.type != oqmlATOM_OID)
02344 return new oqmlStatus(node, "oid expected, got %s",
02345 a->type.getString());
02346
02347 unsigned char buff[16];
02348 int len_data;
02349 Data data;
02350 Oid oid = ((oqmlAtom_oid *)a)->oid;
02351 Bool isnull;
02352
02353 s = getValue(node, ctx, &oid, buff, data, len_data, isnull);
02354
02355 if (s) return s;
02356
02357 if ((*cmp)(data, isnull, start, end, len_data, user_data))
02358 alist->append(new oqmlAtom_oid(oid));
02359
02360 return oqmlSuccess;
02361 }
02362
02363 oqmlStatus *
02364 oqmlIterator::evalAnd(oqmlNode *node,
02365 oqmlContext *ctx, oqmlAtomList *al,
02366 oqmlBool (*cmp)(Data, Bool, const oqmlAtom *, const oqmlAtom *,
02367 int, void *), oqmlAtomList *alist)
02368 {
02369 return evalAndRealize(node, ctx, al->first, cmp, alist);
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386 }
02387
02388 oqmlStatus *oqmlComp::compile(Database *db, oqmlContext *ctx)
02389 {
02390 oqmlStatus *s;
02391
02392 s = compCompile(db, ctx, opstr, qleft, qright, this, &cst_atom, &eval_type);
02393
02394 if (s)
02395 return s;
02396
02397 if (isConstant())
02398 return eval(db, ctx, &cst_list);
02399
02400 return oqmlSuccess;
02401 }
02402
02403 oqmlStatus *oqmlComp::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
02404 {
02405 if (cst_list)
02406 {
02407 *alist = new oqmlAtomList(cst_list);
02408 return oqmlSuccess;
02409 }
02410
02411 oqmlStatus *s;
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422 s = compEval(db, ctx, opstr, qleft, qright, alist, this, cst_atom);
02423
02424 if (s)
02425 return s;
02426
02427 return oqmlSuccess;
02428 }
02429
02430 void oqmlComp::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
02431 {
02432 *at = eval_type;
02433 }
02434
02435 oqmlBool oqmlComp::isConstant() const
02436 {
02437 return OQMLBOOL(qleft->isConstant() && qright->isConstant());
02438 }
02439
02440 oqmlBool oqmlComp::appearsMoreOftenThan(oqmlComp *ql) const
02441 {
02442 oqmlDotContext *dot_ctx1 = 0, *dot_ctx2 = 0;
02443
02444 if (qleft->asDot())
02445 dot_ctx1 = qleft->asDot()->getDotContext();
02446
02447 if (ql->qleft->asDot())
02448 dot_ctx2 = ql->qleft->asDot()->getDotContext();
02449
02450 if (dot_ctx1 && dot_ctx2)
02451 {
02452 oqmlBool isidx1 = OQMLBOOL(dot_ctx1->desc[dot_ctx1->count - 1].idx_cnt);
02453 oqmlBool isidx2 = OQMLBOOL(dot_ctx2->desc[dot_ctx1->count - 1].idx_cnt);
02454
02455 if (isidx1 && !isidx2)
02456 return oqml_False;
02457 if (!isidx1 && isidx2)
02458 return oqml_True;
02459
02460 if (type == oqmlEQUAL)
02461 return oqml_False;
02462
02463 if (ql->getType() == oqmlEQUAL)
02464 return oqml_True;
02465 }
02466
02467 return oqml_False;
02468 }
02469
02470 oqmlStatus *oqmlRegex::compile(Database *db, oqmlContext *ctx)
02471 {
02472 return compCompile(db, ctx, opstr, qleft, qright, this, &cst_atom,
02473 &eval_type);
02474 }
02475
02476 oqmlStatus *
02477 oqmlRegex::eval_realize(oqmlAtom *a, oqmlAtomList **alist)
02478 {
02479 char *str;
02480 oqmlBool isnull;
02481
02482 if (a->type.type == oqmlATOM_NULL)
02483 isnull = oqml_True;
02484 else if (a->type.type == oqmlATOM_STRING) {
02485 str = strdup(OQML_ATOM_STRVAL(a));
02486 isnull = oqml_False;
02487 }
02488 else
02489 return oqmlStatus::expected(this, "string", a->type.getString());
02490
02491
02492 if (!isnull && (type == oqmlREGICMP || type == oqmlREGIDIFF))
02493 oqml_capstring((char *)str);
02494
02495 int r;
02496
02497 if (isnull)
02498 r = 0;
02499 else {
02500 #ifdef USE_LIBGEN
02501 r = (regex((char *)re, str) != 0);
02502 #endif
02503 r = (regexec( re, (char *)str, 0, (regmatch_t *)0, 0) == 0);
02504 }
02505
02506 if (type == oqmlREGDIFF || type == oqmlREGIDIFF)
02507 r = !r;
02508
02509 *alist = new oqmlAtomList(new oqmlAtom_bool(OQMLBOOL(r)));
02510
02511 if (!isnull) free(str);
02512
02513 return oqmlSuccess;
02514 }
02515
02516 oqmlStatus *
02517 oqmlRegex::complete(Database *db, oqmlContext *ctx, oqmlAtom *atom)
02518 {
02519 cst_atom = atom;
02520
02521 if (cst_atom->type.type != oqmlATOM_STRING)
02522 return new oqmlStatus(this, "invalid operand type %s.", opstr,
02523 cst_atom->type.getString());
02524
02525 int r;
02526
02527 #ifdef USE_LIBGEN
02528 free(re);
02529 if (type == oqmlREGCMP || type == oqmlREGDIFF)
02530 re = regcmp(OQML_ATOM_STRVAL(cst_atom), (char *)0);
02531 else {
02532 char *buf = strdup(OQML_ATOM_STRVAL(cst_atom));
02533 oqml_capstring(buf);
02534 re = regcmp(buf, (char *)0);
02535 free(buf);
02536 }
02537
02538 r = (re == NULL);
02539 #endif
02540 re = (regex_t *)malloc( sizeof( regex_t));
02541 assert( re != 0);
02542
02543 if (type == oqmlREGCMP || type == oqmlREGDIFF)
02544 r = regcomp( re, OQML_ATOM_STRVAL(cst_atom), 0);
02545 else {
02546 char *buf = strdup(OQML_ATOM_STRVAL(cst_atom));
02547 oqml_capstring(buf);
02548 r = regcomp( re, buf, 0);
02549 free(buf);
02550 }
02551
02552 if (r)
02553 return new oqmlStatus(this, "invalid regular expression '%s'.",
02554 opstr, OQML_ATOM_STRVAL(cst_atom));
02555
02556 return oqmlSuccess;
02557 }
02558
02559 oqmlStatus *oqmlRegex::eval(Database *db, oqmlContext *ctx,
02560 oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
02561 {
02562 oqmlStatus *s;
02563 oqmlAtomList *al_left;
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574 oqmlAtomList *al;
02575 s = qright->eval(db, ctx, &al);
02576
02577 if (s)
02578 return s;
02579
02580 if (al->cnt != 1)
02581 return new oqmlStatus(this, "invalid operand.", opstr);
02582
02583 cst_atom = al->first;
02584 s = complete(db, ctx, cst_atom);
02585 if (s) return s;
02586
02587 if (!ctx->isSelectContext())
02588 {
02589 if (evalDone)
02590 {
02591 *alist = new oqmlAtomList(new oqmlAtom_bool(oqml_True));
02592 return oqmlSuccess;
02593 }
02594
02595 if (needReinit)
02596 {
02597 s = reinit(db, ctx);
02598 if (s) return s;
02599 needReinit = oqml_False;
02600 }
02601
02602 s = qleft->eval(db, ctx, &al_left);
02603 if (s) return s;
02604 return eval_realize(al_left->first, alist);
02605 }
02606
02607 s = qleft->eval(db, ctx, &al_left, this, cst_atom);
02608
02609 if (s)
02610 return s;
02611
02612 if (iter)
02613 {
02614 s = iter->eval(this, ctx, alist);
02615 if (s) return s;
02616
02617 if (ctx->isOverMaxAtoms())
02618 return oqmlSuccess;
02619
02620 evalDone = oqml_True;
02621
02622 if (qleft->asDot())
02623 {
02624 s = qleft->asDot()->populate(db, ctx, *alist, oqml_False);
02625 if (s) return s;
02626 }
02627
02628 return oqmlSuccess;
02629 }
02630
02631 return eval_realize(al_left->first, alist);
02632 }
02633 }