oqlarr.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 #include "oql_p.h"
00030 
00031 #define MAX_RANGE (int)0x0A000000
00032 
00033 namespace eyedb {
00034 
00035   oqmlBool
00036   oqml_is_getcount(oqml_ArrayList *arr)
00037   {
00038     if (!arr)
00039       return oqml_False;
00040     return arr->is_getcount;
00041   }
00042 
00043   oqmlBool
00044   oqml_is_wholecount(oqml_ArrayList *arr)
00045   {
00046     if (!arr)
00047       return oqml_False;
00048     return OQMLBOOL(arr->is_getcount && arr->is_wholecount);
00049   }
00050 
00051   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00052   //
00053   // private utility methods
00054   //
00055   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00056 
00057   static oqmlStatus *
00058   oqml_wait_for_int(oqmlNode *node, Database *db,
00059                     oqmlContext *ctx, oqmlNode *ql)
00060   {
00061     oqmlAtomType type;
00062     oqmlStatus *s;
00063 
00064     if (ql->getType() != oqmlIDENT)
00065       {
00066         s = ql->compile(db, ctx);
00067         if (s)
00068           return s;
00069 
00070         if (ql->isConstant())
00071           {
00072             ql->evalType(db, ctx, &type);
00073             if (type.type != oqmlATOM_INT)
00074               return oqmlStatus::expected(node, "integer", type.getString());
00075           }
00076       }
00077 
00078     return oqmlSuccess;
00079   }
00080 
00081 
00082   static oqmlStatus *
00083   oqml_wait_for_int(oqmlNode *node, Database *db, oqmlContext *ctx,
00084                     oqmlNode *ql, int *i)
00085   {
00086     oqmlStatus *s;
00087     oqmlAtomList *alist;
00088 
00089     s = ql->eval(db, ctx, &alist);
00090 
00091     if (s)
00092       return s;
00093 
00094     if (alist->cnt != 1)
00095       return new oqmlStatus(node, "integer expected");
00096 
00097     if (alist->first->type.type != oqmlATOM_INT)
00098       return oqmlStatus::expected(node, "integer",
00099                                   alist->first->type.getString());
00100 
00101     *i = ((oqmlAtom_int *)(alist->first))->i;
00102     return oqmlSuccess;
00103   }
00104 
00105   static inline int 
00106   oqml_getinc(const TypeModifier *tmod, int n)
00107   {
00108     int inc = 1;
00109     for (int i = tmod->ndims-1; i > n; i--)
00110       inc *= tmod->dims[i];
00111 
00112     return inc;
00113   }
00114 
00115   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00116   //
00117   // oqmlArray methods and subclass methods
00118   //
00119   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00120 
00121   /*
00122     x := "hello";
00123     x[0]   -> 'h'
00124     x[0:1] -> list('h', 'e')
00125     x[?]   -> list('h', 'e', 'l', 'l', 'o', '\000')
00126 
00127     list(1, 2, 3)[0] -> 1
00128     list(1, 2, 3)[?] -> list(1, 2, 3)
00129   
00130     list(1, list(2, 3), 4)[1] -> list(2, 3)
00131     list(1, list(2, 3), 4)[1][1] -> 3
00132   
00133     list(1, "hello", 2)[1][0] -> 'h'
00134     list(1, "hello", 2)[1:2][0] -> error
00135   */
00136 
00137   // -----------------------------------------------------------------------
00138   //
00139   // oqml_ArrayLink methods
00140   //
00141   // -----------------------------------------------------------------------
00142 
00143   struct oqmlLinkItem {
00144     int from, to;
00145     oqmlBool untilEnd;
00146     oqmlBool wholeRange;
00147     oqmlLinkItem() {
00148       from = to = 0;
00149       untilEnd = wholeRange = oqml_False;
00150     }
00151   };
00152 
00153   oqml_ArrayLink::oqml_ArrayLink(oqmlBool _wholeCount)
00154   {
00155     qleft = 0;
00156     qright = 0;
00157     next = 0;
00158     wholeCount = _wholeCount;
00159     wholeRange = oqml_False;
00160   }
00161 
00162   oqml_ArrayLink::oqml_ArrayLink(oqmlNode *_qleft, oqmlNode *_qright)
00163   {
00164     if (_qleft)
00165       {
00166         qleft = _qleft;
00167         qright = _qright;
00168         wholeRange = oqml_False;
00169         next = 0;
00170         return;
00171       }
00172 
00173     qleft = new oqmlInt((long long)0);
00174     qright = new oqmlInt(MAX_RANGE);
00175     wholeRange = oqml_True;
00176     next = 0;
00177   }
00178 
00179   oqmlBool
00180   oqml_ArrayLink::hasIdent(const char *_ident)
00181   {
00182     return OQMLBOOL((qleft && qleft->hasIdent(_ident)) ||
00183                     (qright && qright->hasIdent(_ident)));
00184   }
00185 
00186   oqmlBool
00187   oqml_ArrayLink::isGetCount() const
00188   {
00189     return OQMLBOOL(!qleft && !qright);
00190   }
00191 
00192   std::string
00193   oqml_ArrayLink::toString() const
00194   {
00195     if (isGetCount())
00196       return wholeCount ? "[!!]" : "[!]";
00197 
00198     if (wholeRange)
00199       return "[?]";
00200 
00201     return std::string("[") +
00202       (qleft ? qleft->toString() : std::string("")) +
00203       (qright ? std::string(":") + qright->toString() : std::string("")) + "]";
00204   }
00205 
00206   oqmlStatus *
00207   oqml_ArrayLink::compile(Database *db, oqmlContext *ctx)
00208   {
00209     oqmlStatus *s;
00210     if (qleft)
00211       {
00212         s = qleft->compile(db, ctx);
00213         if (s) return s;
00214       }
00215 
00216     if (qright)
00217       return qright->compile(db, ctx);
00218     return oqmlSuccess;
00219   }
00220 
00221   static oqmlStatus *
00222   oqml_eval_link(oqmlNode *node, Database *db, oqmlContext *ctx, oqmlNode *ql, int &val, oqmlBool &untilEnd)
00223   {
00224     if (ql->getType() == oqmlIDENT &&
00225         !strcmp(((oqmlIdent *)ql)->getName(), "$")) {
00226       val = MAX_RANGE;
00227       untilEnd = oqml_True;
00228       return oqmlSuccess;
00229     }
00230 
00231     oqmlAtomList *al;
00232     oqmlStatus *s = ql->eval(db, ctx, &al);
00233     if (s) return s;
00234 
00235     if (al->cnt == 0)
00236       return new oqmlStatus(node, "invalid right operand: "
00237                             "integer expected.");
00238 
00239     if (al->cnt != 1 || !al->first->as_int())
00240       return new oqmlStatus(node, "invalid right operand: "
00241                             "integer expected, got '%s'.",
00242                             al->first->type.getString());
00243 
00244     val = OQML_ATOM_INTVAL(al->first);
00245     untilEnd = oqml_False;
00246     return oqmlSuccess;
00247   }
00248 
00249   oqmlStatus *
00250   oqml_ArrayLink::eval(oqmlNode *node, Database *db, oqmlContext *ctx,
00251                        oqmlLinkItem &item)
00252   {
00253     if (wholeRange) {
00254       item.from = 0;
00255       item.to = MAX_RANGE;
00256       item.wholeRange = oqml_True;
00257       return oqmlSuccess;
00258     }
00259 
00260     item.wholeRange = oqml_False;
00261     oqmlStatus *s;
00262 
00263     oqmlBool dummy;
00264     s = oqml_eval_link(node, db, ctx, qleft, item.from, dummy);
00265     if (s) return s;
00266 
00267     if (qright)
00268       return oqml_eval_link(node, db, ctx, qright, item.to, item.untilEnd);
00269 
00270     item.to = item.from;
00271     return oqmlSuccess;
00272   }
00273 
00274   void
00275   oqml_ArrayLink::lock()
00276   {
00277     if (qleft) qleft->lock();
00278     if (qright) qright->lock();
00279   }
00280 
00281   void
00282   oqml_ArrayLink::unlock()
00283   {
00284     if (qleft) qleft->unlock();
00285     if (qright) qright->unlock();
00286   }
00287 
00288   oqml_ArrayLink::~oqml_ArrayLink()
00289   {
00290   }
00291 
00292   // -----------------------------------------------------------------------
00293   //
00294   // oqml_ArrayList methods
00295   //
00296   // -----------------------------------------------------------------------
00297 
00298   oqml_ArrayList::oqml_ArrayList()
00299   {
00300     count = 0;
00301     first = last = 0;
00302     is_getcount = oqml_False;
00303     is_wholecount = oqml_False;
00304     wholeRange = oqml_True;
00305   }
00306 
00307   void oqml_ArrayList::add(oqml_ArrayLink *link)
00308   {
00309     if (last)
00310       last->next = link;
00311     else
00312       first = link;
00313 
00314     if (!is_getcount)
00315       {
00316         is_getcount = link->isGetCount();
00317         is_wholecount = link->wholeCount;
00318       }
00319 
00320     if (!link->wholeRange)
00321       wholeRange = oqml_False;
00322 
00323     last = link;
00324     count++;
00325   }
00326 
00327   oqmlBool
00328   oqml_ArrayList::hasIdent(const char *_ident)
00329   {
00330     oqml_ArrayLink *l = first;
00331 
00332     while (l)
00333       {
00334         if (l->hasIdent(_ident))
00335           return oqml_True;
00336         l = l->next;
00337       }
00338 
00339     return oqml_False;
00340   }
00341 
00342   std::string
00343   oqml_ArrayList::toString() const
00344   {
00345     oqml_ArrayLink *l = first;
00346     std::string s = "";
00347     while (l)
00348       {
00349         s += l->toString();
00350         l = l->next;
00351       }
00352 
00353     return s;
00354   }
00355 
00356   oqmlStatus *
00357   oqml_ArrayList::compile(Database *db, oqmlContext *ctx)
00358   {
00359     if (is_getcount)
00360       return oqmlSuccess;
00361 
00362     oqmlStatus *s;
00363     oqml_ArrayLink *l = first;
00364 
00365     while (l)
00366       {
00367         s = l->compile(db, ctx);
00368         if (s) return s;
00369         l = l->next;
00370       }
00371 
00372     return oqmlSuccess;
00373   }
00374 
00375   oqmlNode *oqmlArray::getLeft()
00376   {
00377     return ql;
00378   }
00379 
00380   oqml_ArrayList *oqmlArray::getArrayList()
00381   {
00382     return list;
00383   }
00384 
00385   oqmlStatus *
00386   oqml_ArrayList::eval(oqmlNode *node, Database *db, oqmlContext *ctx,
00387                        oqmlLinkItem *&items, int &item_cnt)
00388   {
00389     oqmlStatus *s;
00390     oqml_ArrayLink *l = first;
00391 
00392     item_cnt = count;
00393     items = new oqmlLinkItem[count];
00394 
00395     for (int i = 0; l ; i++)
00396       {
00397         s = l->eval(node, db, ctx, items[i]);
00398         if (s) return s;
00399         l = l->next;
00400       }
00401 
00402     return oqmlSuccess;
00403   }
00404 
00405   oqmlStatus *
00406   oqml_ArrayList::checkCollArray(oqmlNode *node, const Class *cls,
00407                                  const char *attrname)
00408   {
00409     if (!last->wholeRange && !cls->asCollArrayClass())
00410       return new oqmlStatus(node, "non array collection invalid operator: "
00411                             "'%s%s'", attrname, toString().c_str());
00412     oqml_ArrayLink *l = first;
00413     while (l != last)
00414       {
00415         if (l->qright)
00416           return new oqmlStatus(node, "collection attribute contents '%s[%s]': "
00417                                 "value ranges are not valid "
00418                                 "for intermediate dimensions",
00419                                 attrname, toString().c_str());
00420 
00421         l = l->next;
00422       }
00423 
00424     return oqmlSuccess;
00425   }
00426 
00427   oqmlStatus *
00428   oqml_ArrayList::eval(oqmlNode *node, Database *db, oqmlContext *ctx,
00429                        const char *clname,
00430                        const char *attrname, const TypeModifier *tmod,
00431                        int *s_ind, int *e_ind, oqmlBool nocheck)
00432   {
00433     *s_ind = 0;
00434     *e_ind = 0;
00435 
00436     if (is_getcount)
00437       return oqmlSuccess;
00438 
00439     oqmlStatus *s;
00440     int i;
00441     int n = 0;
00442     oqml_ArrayLink *l = first;
00443 
00444     while (l)
00445       {
00446         int incdim = oqml_getinc(tmod, n);
00447         s = oqml_wait_for_int(node, db, ctx, l->qleft, &i);
00448 
00449         if (s)
00450           return s;
00451 
00452         int maxdim = (tmod && tmod->dims ? tmod->dims[n] : 0); // added test on tmod 17/01/01
00453 
00454         if (maxdim > 0 && i >= maxdim)
00455           {
00456             if (nocheck)
00457               i = maxdim-1;
00458             else
00459               return new oqmlStatus(node, "attribute '%s' in class '%s' : "
00460                                     "out of range dimension #%d: "
00461                                     "maximum allowed is %d <got %d>",
00462                                     attrname, clname,
00463                                     n, maxdim-1, i);
00464           }
00465 
00466         *s_ind += i * incdim;
00467 
00468         if (l->qright)
00469           {
00470             s = oqml_wait_for_int(node, db, ctx, l->qright, &i);
00471 
00472             if (s)
00473               return s;
00474 
00475             if (i == -1)
00476               {
00477                 if (maxdim > 0)
00478                   i = maxdim-1;
00479                 else
00480                   i = 10000000;
00481               }
00482             else if (maxdim > 0 && i >= maxdim)
00483               {
00484                 if (nocheck)
00485                   i = maxdim-1;
00486                 else
00487                   return new oqmlStatus(node, "attribute '%s' in class '%s' : "
00488                                         "out of range dimension #%d: "
00489                                         "maximum allowed is %d, got %d)",
00490                                         attrname, clname,
00491                                         n, maxdim, i);
00492               }
00493 
00494             *e_ind += i * incdim;
00495           }
00496         else
00497           *e_ind += i * incdim;
00498 
00499         l = l->next;
00500         n++;
00501       }
00502 
00503     return oqmlSuccess;
00504   }
00505 
00506   oqmlStatus *
00507   oqml_ArrayList::evalCollArray(oqmlNode *node, Database *db,
00508                                 oqmlContext *ctx,
00509                                 const TypeModifier *tmod, int &ind)
00510   {
00511     oqmlStatus *s;
00512     oqml_ArrayLink *l = first;
00513 
00514     ind = 0;
00515 
00516     for (int n = 0; l != last; n++)
00517       {
00518         int incdim = oqml_getinc(tmod, n);
00519         int i;
00520         s = oqml_wait_for_int(node, db, ctx, l->qleft, &i);
00521 
00522         if (s) return s;
00523 
00524         int maxdim = tmod->dims[n];
00525 
00526         if (maxdim > 0 && i >= maxdim)
00527           return new oqmlStatus(node, "out of range dimension #%d: "
00528                                 "maximum allowed is %d, got %d",
00529                                 n, maxdim, i);
00530 
00531         ind += i * incdim;
00532 
00533         l = l->next;
00534         n++;
00535       }
00536 
00537     return oqmlSuccess;
00538   }
00539 
00540   void
00541   oqml_ArrayList::lock()
00542   {
00543     oqml_ArrayLink *l = first;
00544     while (l)
00545       {
00546         l->lock();
00547         l = l->next;
00548       }
00549   }
00550 
00551   void
00552   oqml_ArrayList::unlock()
00553   {
00554     oqml_ArrayLink *l = first;
00555     while (l)
00556       {
00557         l->unlock();
00558         l = l->next;
00559       }
00560   }
00561 
00562   oqml_ArrayList::~oqml_ArrayList()
00563   {
00564     oqml_ArrayLink *l = first;
00565     while (l)
00566       {
00567         oqml_ArrayLink *next = l->next;
00568         delete l;
00569         l = next;
00570       }
00571   }
00572 
00573   // -----------------------------------------------------------------------
00574   //
00575   // oqmlArray methods
00576   //
00577   // -----------------------------------------------------------------------
00578 
00579   oqmlArray::oqmlArray(oqmlNode * _ql) : oqmlNode(oqmlARRAY)
00580   {
00581     ql = _ql;
00582     list = new oqml_ArrayList();
00583     delegationArray = oqml_False;
00584     returnStruct = oqml_True;
00585   }
00586 
00587   oqmlArray::oqmlArray(oqmlNode * _ql, oqml_ArrayList *_list,
00588                        oqmlBool _returnStruct) : oqmlNode(oqmlARRAY)
00589   {
00590     ql = _ql;
00591     list = _list;
00592     delegationArray = oqml_True;
00593     returnStruct = _returnStruct;
00594   }
00595 
00596   oqmlStatus *
00597   oqmlArray::evalMake(Database *db, oqmlContext *ctx, Object *o,
00598                       oqml_ArrayList *list, oqmlBool returnStruct, oqmlAtomList **alist)
00599   {
00600     oqmlArray *array = new oqmlArray(new oqmlObject(o, 0), list,
00601                                      returnStruct);
00602     oqmlStatus *s = array->compile(db, ctx);
00603     if (s) return s;
00604     return array->eval(db, ctx, alist);
00605   }
00606 
00607   oqmlArray::~oqmlArray()
00608   {
00609     if (!delegationArray)
00610       delete list;
00611   }
00612 
00613   void oqmlArray::add(oqml_ArrayLink *link)
00614   {
00615     list->add(link);
00616   }
00617 
00618   oqmlStatus *oqmlArray::compile(Database *db, oqmlContext *ctx)
00619   {
00620     oqmlDotContext *dctx = ctx->getDotContext();
00621     oqmlStatus *s;
00622 
00623     if (!dctx)
00624       {
00625         s = ql->compile(db, ctx);
00626         if (s) return s;
00627         return list->compile(db, ctx);
00628       }
00629 
00630     if (ql->getType() == oqmlIDENT)
00631       {
00632         const char *name = ((oqmlIdent *)ql)->getName();
00633         oqmlDotDesc *desc = &dctx->desc[dctx->count-1];
00634       
00635         Class *cls = (Class *)desc->cls;
00636 
00637         Attribute *attr = (Attribute *)desc->attr;
00638         if (cls) // test added the 24/01/00
00639           {
00640             attr = (Attribute *)cls->getAttribute(name);
00641           
00642             if (!attr)
00643               return new oqmlStatus(this, "attribute '%s' not "
00644                                     "found in class '%s'", name, cls->getName());
00645           }
00646       
00647         if (!list->is_getcount)
00648           {
00649             oqml_ArrayLink *l = list->first;
00650 
00651             while (l)
00652               {
00653                 s = oqml_wait_for_int(this, db, ctx, l->qleft);
00654               
00655                 if (s)
00656                   return s;
00657 
00658                 if (l->qright)
00659                   {
00660                     s = oqml_wait_for_int(this, db, ctx, l->qright);
00661                   
00662                     if (s)
00663                       return s;
00664                   }
00665               
00666                 l = l->next;
00667               }
00668           }
00669 
00670         s = dctx->add(db, ctx, attr, list, (char *)name, 0, 0, 0);
00671         if (s)
00672           return s;
00673         eval_type = dctx->dot_type;
00674         return oqmlSuccess;
00675       }
00676 
00677     return new oqmlStatus(this, "currently cannot deal with no ident left "
00678                           "part in array");
00679   }
00680 
00681 #define MAKELEFTVALUE(X) \
00682 do { \
00683   if (ridx) \
00684   { \
00685     if (dim == item_cnt - 1) \
00686       { \
00687         if (n != 0) \
00688         { \
00689           delete[] items; \
00690           return new oqmlStatus(this, "invalid left value."); \
00691         } \
00692         *ridx = idx; \
00693         *ra = x; \
00694       } \
00695     else \
00696       xlist->append(X); \
00697   } \
00698   else \
00699     xlist->append(X); \
00700 } while(0)
00701 
00702   oqmlStatus *
00703   oqmlArray::checkRange(oqmlLinkItem *items, int dim, int idx, int len,
00704                         oqmlBool &stop, const char *msg)
00705   {
00706     if (idx >= len && items[dim].untilEnd)
00707       {
00708         stop = oqml_True;
00709         return oqmlSuccess;
00710       }
00711 
00712     if (idx < 0 || idx >= len)
00713       {
00714         if (!items[dim].wholeRange)
00715           {
00716             delete[] items;
00717             return new oqmlStatus(this, "out of bounds "
00718                                   "value, %d, for %s", idx, msg);
00719           }
00720         stop = oqml_True;
00721         return oqmlSuccess;
00722       }
00723 
00724     stop = oqml_False;
00725     return oqmlSuccess;
00726   }
00727 
00728   oqmlStatus *
00729   oqmlArray::evalRealize_1(Database *db, oqmlContext *ctx,
00730                            oqmlAtom *x, oqmlAtomList **alist, oqmlAtom **ra,
00731                            int *ridx)
00732   {
00733     static const char fmt[] = "invalid operand, "
00734       "string, collection or struct.";
00735 
00736     if (ridx)
00737       return new oqmlStatus(this, "invalid left operand");
00738 
00739     if (!x->as_string() && !x->as_coll() && !x->as_struct())
00740       return new oqmlStatus(this, fmt);
00741 
00742     if (x->as_string())
00743       {
00744         if (alist)
00745           *alist =
00746             new oqmlAtomList(new oqmlAtom_int(OQML_ATOM_STRLEN(x)));
00747         return oqmlSuccess;
00748       }
00749 
00750     if (x->as_coll())
00751       {
00752         if (alist)
00753           *alist =
00754             new oqmlAtomList(new oqmlAtom_int(OQML_ATOM_COLLVAL(x)->cnt));
00755         return oqmlSuccess;
00756       }
00757 
00758     if (x->as_struct())
00759       {
00760         if (alist)
00761           *alist =
00762             new oqmlAtomList(new oqmlAtom_int(x->as_struct()->attr_cnt));
00763         return oqmlSuccess;
00764       }
00765 
00766     return new oqmlStatus(this, fmt);
00767   }
00768 
00769 
00770   oqmlStatus *oqmlArray::evalRealize_2(Database *db, oqmlContext *ctx,
00771                                        oqmlAtom *x, oqmlAtomList **alist,
00772                                        oqmlAtom **ra, int *ridx)
00773   {
00774     static const char fmt[] = "invalid%soperand, "
00775       "string, list, array or struct.";
00776 
00777     oqmlLinkItem *items = 0;
00778     int item_cnt;
00779     oqmlStatus *s;
00780 
00781     s = list->eval(this, db, ctx, items, item_cnt);
00782 
00783     if (s) return s;
00784 
00785     if (ridx) {
00786       *ridx = -1;
00787       *ra = 0;
00788     }
00789 
00790     if (!x->as_string() && !x->as_list() && !x->as_array() &&
00791         !x->as_struct() && !OQML_IS_OBJECT(x))
00792       return new oqmlStatus(this, fmt, ridx ? " left " : " ");
00793 
00794     for (int dim = 0; dim < item_cnt; dim++) {
00795       oqmlAtomList *xlist = new oqmlAtomList();
00796       oqmlBool stop;
00797 
00798       if (!x)
00799         break;
00800 
00801       if (x->as_string()) {
00802         const char *str = OQML_ATOM_STRVAL(x);
00803         int len = OQML_ATOM_STRLEN(x) + (ridx ? 0 : 1);
00804         for (int idx = items[dim].from, n = 0; idx <= items[dim].to; idx++,
00805                n++) {
00806           // WARNING: the OQL library function 'strlen' is
00807           // very penalised with the construct:
00808           // 'std::string("string \"") + str + "\"")'
00809           // because for each recursion, the construction of this string
00810           // is called although it is not necessary.
00811           s = checkRange(items, dim, idx, len, stop,
00812                          //std::string("string \"") + str + "\"");
00813                          str);
00814           if (s) return s;
00815           if (stop) break;
00816         
00817           MAKELEFTVALUE(new oqmlAtom_char(str[idx]));
00818         }
00819       }
00820       else if (x->as_list() || x->as_array()) {
00821         oqmlAtomList *alist = OQML_ATOM_COLLVAL(x);
00822         for (int idx = items[dim].from, n = 0; idx <= items[dim].to; idx++,
00823                n++) {
00824           s = checkRange(items, dim, idx, alist->cnt, stop, "list");
00825           if (s) return s;
00826           if (stop) break;
00827         
00828           MAKELEFTVALUE(alist->getAtom(idx)->copy());
00829         }
00830       }
00831       else if (x->as_struct()) {
00832         oqmlAtom_struct *astruct = x->as_struct();
00833         for (int idx = items[dim].from, n = 0; idx <= items[dim].to; idx++,
00834                n++) {
00835           s = checkRange(items, dim, idx, astruct->attr_cnt, stop, "struct");
00836           if (s) return s;
00837           if (stop) break;
00838         
00839           MAKELEFTVALUE(astruct->attr[idx].value->copy());
00840         }
00841       }
00842       else if (OQML_IS_OBJECT(x)) {
00843         OQL_CHECK_OBJ(x);
00844         Object *o = 0;
00845         s = oqmlObjectManager::getObject(this, db, x, o, oqml_True,
00846                                          oqml_True);
00847         if (s) return s;
00848         if (!o->asCollArray())
00849           return new oqmlStatus(this, "only support array collection");
00850       
00851         Bool is_ref;
00852         (void)o->getClass()->asCollectionClass()->getCollClass(&is_ref);
00853         if (!is_ref)
00854           return new oqmlStatus(this, "only support collection array of "
00855                                 "objects");
00856         if (ridx) {
00857           if (items[dim].from != items[dim].to)
00858             return new oqmlStatus(this, "invalid left value");
00859           int n = 0;
00860           int idx = items[dim].from;
00861           if (OQML_IS_OBJ(x))
00862             MAKELEFTVALUE(new oqmlAtom_oid(OQML_ATOM_OBJVAL(x)->getOid()));
00863           else
00864             MAKELEFTVALUE(x->copy());
00865           continue;
00866         }
00867       
00868         Status is = Success;
00869         for (int idx = items[dim].from, n = 0; idx <= items[dim].to; idx++,
00870                n++) {
00871           if (n >= o->asCollArray()->getTop())
00872             break;
00873           if (dim == item_cnt - 1) {
00874             Oid obj_oid;
00875             is = o->asCollArray()->retrieveAt(idx, obj_oid);
00876             if (is) break;
00877 
00878             if (returnStruct && items[dim].from != items[dim].to)
00879               xlist->append(oqml_make_struct_array(db, ctx, idx, new oqmlAtom_oid(obj_oid)));
00880             else
00881               xlist->append(new oqmlAtom_oid(obj_oid));
00882           }
00883           else {
00884             xlist->append(oqmlObjectManager::registerObject(o));
00885           }
00886         }
00887       
00888         if (is) return new oqmlStatus(this, is);
00889       }
00890       else {
00891         delete[] items;
00892         return new oqmlStatus(this, fmt, ridx ? " left " : " ");
00893       }
00894     
00895       if (xlist->cnt > 1) {
00896         if (x->as_array())
00897           x = new oqmlAtom_array(xlist);
00898         else
00899           x = new oqmlAtom_list(xlist);
00900       }
00901       else
00902         x = xlist->first;
00903     }
00904   
00905     if (alist)
00906       *alist = new oqmlAtomList(x);
00907 
00908     delete[] items;
00909     return oqmlSuccess;
00910   }
00911 
00912 
00913   oqmlStatus *oqmlArray::evalRealize(Database *db, oqmlContext *ctx,
00914                                      oqmlAtomList **alist, oqmlAtom **ra,
00915                                      int *ridx)
00916   {
00917     oqmlStatus *s;
00918 
00919     oqmlAtomList *alleft;
00920     s = ql->eval(db, ctx, &alleft);
00921 
00922     if (s)
00923       return s;
00924 
00925     if (alleft->cnt != 1)
00926       return new oqmlStatus(this, "invalid left operand.");
00927 
00928     oqmlAtom *x = alleft->first;
00929     if (list->is_getcount)
00930       {
00931         if (list->is_wholecount)
00932           return new oqmlStatus(this, "invalid operand");
00933         return evalRealize_1(db, ctx, x, alist, ra, ridx);
00934       }
00935 
00936     return evalRealize_2(db, ctx, x, alist, ra, ridx);
00937   }
00938 
00939   oqmlStatus *oqmlArray::eval(Database *db, oqmlContext *ctx,
00940                               oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00941   {
00942     return evalRealize(db, ctx, alist, 0, 0);
00943   }
00944 
00945   oqmlStatus *oqmlArray::evalLeft(Database *db, oqmlContext *ctx,
00946                                   oqmlAtom **ra, int &ridx)
00947   {
00948     return evalRealize(db, ctx, 0, ra, &ridx);
00949   }
00950 
00951   void oqmlArray::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00952   {
00953     *at = eval_type;
00954   }
00955 
00956   oqmlBool oqmlArray::isConstant() const
00957   {
00958     return oqml_False;
00959   }
00960 
00961   oqmlBool
00962   oqmlArray::hasIdent(const char *_ident)
00963   {
00964     return OQMLBOOL(((ql && ql->hasIdent(_ident)) ||
00965                      (list && list->hasIdent(_ident))));
00966   }
00967 
00968   std::string
00969   oqmlArray::toString(void) const
00970   {
00971     return ql->toString() + list->toString();
00972   }
00973 
00974   void
00975   oqmlArray::lock()
00976   {
00977     oqmlNode::lock();
00978     ql->lock();
00979     list->lock();
00980   }
00981 
00982   void
00983   oqmlArray::unlock()
00984   {
00985     oqmlNode::unlock();
00986     ql->unlock();
00987     list->unlock();
00988   }
00989 }

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