oqliter.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <assert.h>
00029 
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   // optimisation added the 4/9/99
00091   if (cls->getOid() == *cloid)
00092     return oqml_True;
00093 
00094   // ici, on pourrait ajouter une methode dans Class:
00095   // Bool Class::isSuperClassOf(const Oid &)
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       // added the 17/11/99
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 // MIND: Cette fonction est fausse en ce qui concerne la boucle
00153 // d'indice: en effet, elle est appelée depuis makeiter_noidx:
00154 // elle fait une boucle se `s_ind' a `e_ind' puis retourne 
00155 // le derniere valeur de `data' qu'elle a trouvé: c'est totalement
00156 // faux. 22/08/98
00157 //
00158 // En fait, il semble que cela ne marche pas dans les cas suivants:
00159 // X.y[range].z ou `y' est un agregat direct.
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       if (!xattr)
00175         printf("WARNING NO ATTRIBUTE %s for class %s\n",
00176                d->attrname, o->getClass()->getName());
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); // idem
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               // changed (back again!?) the 16/11/99
00279               /*
00280                 if (*(char **)*pdata)
00281                 *(char **)*pdata = strdup(*(char **)*pdata);
00282                 else
00283                 *(char **)*pdata = strdup("");
00284                 oqmlGarbManager::add(*(char **)*pdata);
00285                 */
00286               if ((char *)*pdata)
00287                 *pdata = (unsigned char *)strdup((char *)*pdata);
00288               else
00289                 *pdata = (unsigned char *)strdup("");
00290 
00291               // BUG CORRECTED THE 11/02/02!!!!
00292               //oqmlGarbManager::add((char *)pdata);
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   /* MIND: c'est ici que doit se faire la comparaison et l'ajout
00396          eventuel dans la liste d'oids! */
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                       //printf("INSERTING[%d] %s\n", nfound, oid[0].toString());
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   printf("\n+++++ MUST ADD %s to identifier %s ++++++\n\n",
00833          atom->getString(), ident);
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   printf("dctx->dot %s requal_ident = %s, is_coll = %d\n",
00882          (const char *)dctx->dot->toString(),
00883          dctx->dot->requal_ident ? dctx->dot->requal_ident : "no requal ident",
00884          d->is_coll);
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 //  if (omode == Exception::ExceptionMode) throw *IS; \
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   //if (n == dctx->count - 1) {
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   //int thread_cnt = getThreadCount(ctx);
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 // EQUAL
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   //  if (dot_ctx && dot_ctx->count == 0)
01453   // changed the 22/04/99
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 // DIFF
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 // INF
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 // INFEQ
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 // SUP
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 // SUPEQ
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   assert(node->getType() == oqmlSUPEQ || node->getType() == oqmlINFEQ ||
01805          node->getType() == oqmlREGCMP || node->getType() == oqmlREGICMP);
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 // SubStr
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 // BETWEEN
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 // NOT BETWEEN
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 // REGCMP
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 // REGICMP
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 // REGDIFF
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 // REGIDiff
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 // utils
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   oqmlStatus *s;
02372   oqmlAtom *a = al->first;
02373 
02374   while (a)
02375     {
02376       oqmlAtom *next = a->next;
02377 
02378       s = evalAndRealize(node, ctx, a, cmp, alist);
02379       if (s) return s;
02380 
02381       a = next;
02382     }
02383 
02384   return oqmlSuccess;
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   printf("evaluating oqmlComp => %s context='%s %s %s' [iterator %d]\n",
02415          (const char *)toString(),
02416          ctx->isSelectContext() ? "select" : "not select",
02417          ctx->isPrevalContext() ? "preval" : "not preval",
02418          ctx->isWhereContext() ? "where" : "not where",
02419          getIterator());
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   printf("evaluating oqmlRegex => %s context='%s %s %s' [iterator %d]\n",
02567          (const char *)toString(),
02568          ctx->isSelectContext() ? "select" : "not select",
02569          ctx->isPrevalContext() ? "preval" : "not preval",
02570          ctx->isWhereContext() ? "where" : "not where",
02571          getIterator());
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 }

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