oqlop.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 <unistd.h>
00026 #include <fcntl.h>
00027 #include <wctype.h>
00028 #include <sys/stat.h>
00029 
00030 #include "oql_p.h"
00031 
00032 // PATCH p2312
00033 
00034 namespace eyedb {
00035 
00036 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00037 //
00038 // oqmlAdd operator methods
00039 //
00040 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00041 
00042 oqmlAdd::oqmlAdd(oqmlNode * _qleft, oqmlNode * _qright, oqmlBool _unary) :
00043   oqmlNode(oqmlADD)
00044 {
00045   qleft = _qleft;
00046   qright = _qright;
00047   unary = _unary;
00048 }
00049 
00050 oqmlAdd::oqmlAdd(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlADD)
00051 {
00052   qleft = _qleft;
00053   qright = _qright;
00054   unary = oqml_False;
00055 }
00056 
00057 oqmlAdd::~oqmlAdd()
00058 {
00059 }
00060 
00061 oqmlStatus *oqmlAdd::compile(Database *db, oqmlContext *ctx)
00062 {
00063   oqmlBool iscts;
00064   oqmlStatus *s;
00065 
00066   s = binopCompile(db, ctx, "+", qleft, qright, eval_type,
00067                    oqmlDoubleConcatOK, iscts);
00068 
00069   if (s)
00070     return s;
00071 
00072   if (isConstant() && !cst_list)
00073     {
00074       oqmlAtomList *al;
00075       s = eval(db, ctx, &al);
00076       if (s) return s;
00077       cst_list = al->copy();
00078       if (isLocked())
00079         oqmlLock(cst_list, oqml_True);
00080     }
00081 
00082   return oqmlSuccess;
00083 }
00084 
00085 oqmlStatus *oqmlAdd::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00086 {
00087   if (cst_list) {
00088     *alist = new oqmlAtomList(cst_list);
00089     return oqmlSuccess;
00090   }
00091 
00092   oqmlAtomList *al_left, *al_right;
00093   oqmlStatus *s = binopEval(db, ctx, "+", eval_type,
00094                             qleft, qright, oqmlDoubleConcatOK,
00095                             &al_left, &al_right);
00096 
00097   if (s)
00098     return s;
00099 
00100   oqmlAtom *aleft = al_left->first, *aright = al_right->first;
00101 
00102   oqmlATOMTYPE atleft  = aleft->type.type;
00103   oqmlATOMTYPE atright = aright->type.type;
00104 
00105 //#define NEW_ADD_COLL
00106   if (OQML_IS_COLL(aleft)) {
00107     oqmlAtomList *al = new oqmlAtomList();
00108 
00109     al->append(OQML_ATOM_COLLVAL(aleft), oqml_False);
00110 #ifdef NEW_ADD_COLL
00111     if (!aright->as_nil())
00112       al->append(aright->copy());
00113 #else
00114     if (OQML_IS_COLL(aright)) {
00115       if (atleft != atright)
00116         return oqmlStatus::expected(this, &aleft->type, &aright->type);
00117       al->append(OQML_ATOM_COLLVAL(aright)->copy(), oqml_False);
00118     }
00119     else if (!aright->as_nil())
00120       al->append(aright->copy());
00121 #endif
00122 
00123     if (OQML_IS_LIST(aleft))
00124       *alist = new oqmlAtomList(new oqmlAtom_list(al));
00125     else if (OQML_IS_BAG(aleft))
00126       *alist = new oqmlAtomList(new oqmlAtom_bag(al));
00127     else if (OQML_IS_ARRAY(aleft))
00128       *alist = new oqmlAtomList(new oqmlAtom_array(al));
00129     else if (OQML_IS_SET(aleft))
00130       *alist = new oqmlAtomList(new oqmlAtom_set(al));
00131 
00132 #ifdef SYNC_GARB
00133     // NO !!!
00134     /*
00135     delete al_left;
00136     delete al_right;
00137     */
00138 #endif
00139     return oqmlSuccess;
00140   }
00141 
00142   if (OQML_IS_COLL(aright)) {
00143     oqmlAtomList *al = new oqmlAtomList();
00144 
00145     if (OQML_IS_COLL(aleft)) {
00146 #ifdef NEW_ADD_COLL
00147       assert(0);
00148 #endif
00149       if (atleft != atright)
00150         return oqmlStatus::expected(this, &aright->type, &aleft->type);
00151       al->append(OQML_ATOM_COLLVAL(aleft), oqml_False);
00152     }
00153     else if (!aleft->as_nil())
00154       al->append(aleft);
00155 
00156     al->append(OQML_ATOM_COLLVAL(aright), oqml_False);
00157 
00158     if (OQML_IS_LIST(aright))
00159       *alist = new oqmlAtomList(new oqmlAtom_list(al));
00160     else if (OQML_IS_BAG(aright))
00161       *alist = new oqmlAtomList(new oqmlAtom_bag(al));
00162     else if (OQML_IS_ARRAY(aright))
00163       *alist = new oqmlAtomList(new oqmlAtom_array(al));
00164     else if (OQML_IS_SET(aright))
00165       *alist = new oqmlAtomList(new oqmlAtom_set(al));
00166     
00167 #ifdef SYNC_GARB
00168     // NO !!!
00169     /*
00170     delete al_left;
00171     delete al_right;
00172     */
00173 #endif
00174     return oqmlSuccess;
00175   }
00176 
00177   if (atleft == oqmlATOM_INT)
00178     *alist = new oqmlAtomList
00179       (new oqmlAtom_int(OQML_ATOM_INTVAL(aleft) + OQML_ATOM_INTVAL(aright)));
00180 
00181   else if (atleft == oqmlATOM_CHAR)
00182     *alist = new oqmlAtomList
00183       (new oqmlAtom_int(OQML_ATOM_CHARVAL(aleft) + OQML_ATOM_CHARVAL(aright)));
00184 
00185   else if (atleft == oqmlATOM_DOUBLE)
00186     *alist = new oqmlAtomList
00187       (new oqmlAtom_double(OQML_ATOM_DBLVAL(aleft) + OQML_ATOM_DBLVAL(aright)));
00188 
00189   else if (atleft == oqmlATOM_STRING) {
00190     char *s = new char[OQML_ATOM_STRLEN(aleft) + 
00191                       OQML_ATOM_STRLEN(aright)+1];
00192     s[0] = 0;
00193     strcat(s, OQML_ATOM_STRVAL(aleft));
00194     strcat(s, OQML_ATOM_STRVAL(aright));
00195     
00196     *alist = new oqmlAtomList(new oqmlAtom_string(s));
00197     delete [] s;
00198   }
00199   else
00200     return new oqmlStatus(this, "unexpected type %s", aleft->type.getString());
00201 
00202 #ifdef SYNC_GARB
00203   OQL_DELETE(al_left);
00204   OQL_DELETE(al_right);
00205 #endif
00206   return oqmlSuccess;
00207 }
00208 
00209 void oqmlAdd::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00210 {
00211   *at = eval_type;
00212 }
00213 
00214 oqmlBool oqmlAdd::isConstant() const
00215 {
00216   return OQMLBOOL(qleft->isConstant() && qright->isConstant());
00217 }
00218 
00219 std::string
00220 oqmlAdd::toString(void) const
00221 {
00222   if (unary)
00223     return oqml_unop_string(qright, "+", is_statement);
00224   return oqml_binop_string(qleft, qright, "+", is_statement);
00225 }
00226 
00227 oqmlSub::oqmlSub(oqmlNode * _qleft, oqmlNode * _qright, oqmlBool _unary) :
00228   oqmlNode(oqmlSUB)
00229 {
00230   qleft = _qleft;
00231   qright = _qright;
00232   unary = _unary;
00233 }
00234 
00235 oqmlSub::oqmlSub(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlSUB)
00236 {
00237   qleft = _qleft;
00238   qright = _qright;
00239   unary = oqml_False;
00240 }
00241 
00242 oqmlSub::~oqmlSub()
00243 {
00244 }
00245 
00246 oqmlStatus *oqmlSub::compile(Database *db, oqmlContext *ctx)
00247 {
00248   oqmlBool iscts;
00249   oqmlStatus *s;
00250   s = binopCompile(db, ctx, "-", qleft, qright, eval_type, oqmlDoubleOK, iscts);
00251 
00252   if (s)
00253     return s;
00254 
00255   if (isConstant() && !cst_list)
00256    {
00257       oqmlAtomList *al;
00258       s = eval(db, ctx, &al);
00259       if (s) return s;
00260       cst_list = al->copy();
00261       if (isLocked())
00262          oqmlLock(cst_list, oqml_True);
00263    }
00264 
00265   return oqmlSuccess;
00266 }
00267 
00268 oqmlStatus *oqmlSub::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00269 {
00270   if (cst_list)
00271     {
00272       *alist = new oqmlAtomList(cst_list);
00273       return oqmlSuccess;
00274     }
00275 
00276   oqmlAtomList *al_left, *al_right;
00277   oqmlStatus *s = binopEval(db, ctx, "-", eval_type, qleft, qright, oqmlDoubleOK, &al_left, &al_right);
00278 
00279   if (s)
00280     return s;
00281 
00282   oqmlAtom *aleft = al_left->first, *aright = al_right->first;
00283 
00284   oqmlATOMTYPE at = aleft->type.type;
00285 
00286   if (at == oqmlATOM_INT)
00287     *alist = new oqmlAtomList
00288       (new oqmlAtom_int(OQML_ATOM_INTVAL(aleft) - OQML_ATOM_INTVAL(aright)));
00289   else if (at == oqmlATOM_CHAR)
00290     *alist = new oqmlAtomList
00291       (new oqmlAtom_int(OQML_ATOM_CHARVAL(aleft) - OQML_ATOM_CHARVAL(aright)));
00292   else if (at == oqmlATOM_DOUBLE)
00293     *alist = new oqmlAtomList
00294       (new oqmlAtom_double(OQML_ATOM_DBLVAL(aleft) - OQML_ATOM_DBLVAL(aright)));
00295   else
00296     return oqmlStatus::expected(this, "integer, character or double", aleft->type.getString());
00297 
00298 #ifdef SYNC_GARB
00299   OQL_DELETE(al_left);
00300   OQL_DELETE(al_right);
00301 #endif
00302   return oqmlSuccess;
00303 }
00304 
00305 void oqmlSub::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00306 {
00307   *at = eval_type;
00308 }
00309 
00310 oqmlBool oqmlSub::isConstant() const
00311 {
00312   return OQMLBOOL(qleft->isConstant() && qright->isConstant());
00313 }
00314 std::string oqmlSub::toString(void) const
00315 {
00316   if (unary)
00317     return oqml_unop_string(qright, "-", is_statement);
00318   return oqml_binop_string(qleft, qright, "-", is_statement);
00319 }
00320 
00321 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00322 //
00323 // standard binop operator methods
00324 //
00325 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00326 
00327 #define OQML_STD_BINOP(X, PARENT, XX, OPSTR) \
00328 X::X(oqmlNode * _qleft, oqmlNode * _qright) : \
00329   PARENT(XX, _qleft, _qright, OPSTR) { } \
00330  \
00331 X::~X() { } 
00332 
00333 OQML_STD_BINOP(oqmlEqual, oqmlComp, oqmlEQUAL, "==")
00334 OQML_STD_BINOP(oqmlDiff, oqmlComp, oqmlDIFF, "!=")
00335 OQML_STD_BINOP(oqmlInf, oqmlComp, oqmlINF, "<")
00336 OQML_STD_BINOP(oqmlInfEq, oqmlComp, oqmlINFEQ, "<=")
00337 OQML_STD_BINOP(oqmlSup, oqmlComp, oqmlSUP, ">")
00338 OQML_STD_BINOP(oqmlSupEq, oqmlComp, oqmlSUPEQ, ">=")
00339 OQML_STD_BINOP(oqmlBetween, oqmlComp, oqmlBETWEEN, " between ")
00340 OQML_STD_BINOP(oqmlNotBetween, oqmlComp, oqmlNOTBETWEEN, " not between ")
00341 
00342 oqmlNode *oqmlBetween::requalifyNot()
00343 {
00344   oqmlNode *node = new oqmlNotBetween(qleft, qright);
00345   qleft = qright = 0;
00346   return node;
00347 }
00348 
00349 OQML_STD_BINOP(oqmlRegCmp, oqmlRegex, oqmlREGCMP, "~")
00350 OQML_STD_BINOP(oqmlRegICmp, oqmlRegex, oqmlREGICMP, "~~")
00351 OQML_STD_BINOP(oqmlRegDiff, oqmlRegex, oqmlREGDIFF, "!~")
00352 OQML_STD_BINOP(oqmlRegIDiff, oqmlRegex, oqmlREGIDIFF, "!~~")
00353 
00354 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00355 //
00356 // logical operator methods
00357 //
00358 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00359 
00360 static oqmlStatus *
00361 oqml_logical_error(oqmlNode *node, oqmlAtomType *at, bool strict)
00362 {
00363   std::string msg = (strict ? "bool": "bool, int, char or double");
00364   if (at)
00365     return oqmlStatus::expected(node, msg.c_str(), at->getString());
00366 
00367   return new oqmlStatus(node, (msg + " expected").c_str());
00368 }
00369 
00370 static oqmlStatus *
00371 oqml_check_type(oqmlNode *node, Database *db, oqmlContext *ctx,
00372                 oqmlNode *ql, const char *name, bool strict = false)
00373 {
00374   if (ql->getType() == oqmlASSIGN)
00375     return oqmlSuccess;
00376 
00377   oqmlAtomType at;
00378   ql->evalType(db, ctx, &at);
00379 
00380   /*
00381   if (at.type != oqmlATOM_IDENT && at.type != oqmlATOM_INT &&
00382       at.type != oqmlATOM_DOUBLE && at.type != oqmlATOM_CHAR &&
00383       at.type != oqmlATOM_BOOL && at.type != oqmlATOM_UNKNOWN_TYPE)
00384     return oqml_logical_error(node, name, &at);
00385     */
00386 
00387   if (at.type == oqmlATOM_UNKNOWN_TYPE)
00388     return oqmlSuccess;
00389 
00390   if (strict) {
00391     if (at.type != oqmlATOM_BOOL)
00392       return oqml_logical_error(node, &at, strict);
00393   }
00394 
00395   if (at.type != oqmlATOM_INT &&
00396       at.type != oqmlATOM_CHAR &&
00397       at.type != oqmlATOM_DOUBLE &&
00398       at.type != oqmlATOM_BOOL)
00399     return oqml_logical_error(node, &at, strict);
00400 
00401   return oqmlSuccess;
00402 }
00403 
00404 oqmlStatus *
00405 oqml_check_logical(oqmlNode *node, oqmlAtomList *al, oqmlBool &b,
00406                    bool strict)
00407 {
00408   if (al->cnt != 1)
00409     return oqml_logical_error(node, 0, strict);
00410 
00411   oqmlAtom *a = al->first;
00412   if (a->type.type == oqmlATOM_BOOL) {
00413     b = (((oqmlAtom_bool *)a)->b) ? oqml_True : oqml_False;
00414     return oqmlSuccess;
00415   }
00416   
00417   if (!strict) {
00418     if (a->type.type == oqmlATOM_INT) {
00419       b = (((oqmlAtom_int *)a)->i) ? oqml_True : oqml_False;
00420       return oqmlSuccess;
00421     }
00422 
00423     if (a->type.type == oqmlATOM_CHAR) {
00424       b = (((oqmlAtom_char *)a)->c) ? oqml_True : oqml_False;
00425       return oqmlSuccess;
00426     }
00427 
00428     if (a->type.type == oqmlATOM_DOUBLE) {
00429       b = (((oqmlAtom_double *)a)->d) ? oqml_True : oqml_False;
00430       return oqmlSuccess;
00431     }
00432   }
00433 
00434   return oqml_logical_error(node, &a->type, strict);
00435 }
00436 
00437 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00438 //
00439 // logical OR operator methods
00440 //
00441 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00442 
00443 oqmlLOr::oqmlLOr(oqmlNode * _qleft, oqmlNode * _qright,
00444                  oqmlBool _isLiteral) : oqmlNode(oqmlLOR)
00445 {
00446   qleft = _qleft;
00447   qright = _qright;
00448   eval_type.type = oqmlATOM_BOOL;
00449   isLiteral = _isLiteral;
00450   node = 0;
00451 }
00452 
00453 oqmlLOr::~oqmlLOr()
00454 {
00455 }
00456 
00457 #define STRICT_SELECT
00458 
00459 oqmlStatus *oqmlLOr::compile(Database *db, oqmlContext *ctx)
00460 {
00461   node = 0;
00462 
00463   if (ctx->isSelectContext())
00464     {
00465 #ifdef STRICT_SELECT
00466       return new oqmlStatus(this, "this type of query constructs is no more supported: use select/from/where clause");
00467 #else
00468       node = new oqmlOr(qleft, qright);
00469       if (isLocked())
00470         node->lock();
00471       return node->compile(db, ctx);
00472 #endif
00473     }
00474 
00475   oqmlStatus *s;
00476 
00477   s = qleft->compile(db, ctx);
00478   if (s)
00479     return s;
00480 
00481   s = oqml_check_type(this, db, ctx, qleft, "||");
00482   if (s)
00483     return s;
00484 
00485   s = qright->compile(db, ctx);
00486   if (s)
00487     return s;
00488 
00489   s = oqml_check_type(this, db, ctx, qright, "||");
00490   if (s)
00491     return s;
00492   return oqmlSuccess;
00493 }
00494 
00495 oqmlStatus *oqmlLOr::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00496 {
00497   if (node)
00498     return node->eval(db, ctx, alist);
00499 
00500   oqmlStatus *s;
00501   oqmlAtomList *al_left, *al_right;
00502 
00503   *alist = new oqmlAtomList;
00504 
00505   s = qleft->eval(db, ctx, &al_left);
00506   if (s)
00507     return s;
00508 
00509   oqmlBool b;
00510 
00511   s = oqml_check_logical(this, al_left, b);
00512   if (s)
00513     return s;
00514 
00515   if (b)
00516     {
00517       (*alist)->append(new oqmlAtom_bool(oqml_True));
00518       return oqmlSuccess;
00519     }
00520 
00521   s = qright->eval(db, ctx, &al_right);
00522   if (s)
00523     return s;
00524 
00525   s = oqml_check_logical(this, al_right, b);
00526   if (s)
00527     return s;
00528 
00529   if (b)
00530     (*alist)->append(new oqmlAtom_bool(oqml_True));
00531   else
00532     (*alist)->append(new oqmlAtom_bool(oqml_False));
00533 
00534   return oqmlSuccess;
00535 }
00536 
00537 void oqmlLOr::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00538 {
00539   *at = eval_type;
00540 }
00541 
00542 oqmlStatus *
00543 oqmlLOr::preEvalSelect(Database *db, oqmlContext *ctx,
00544                        const char *ident, oqmlBool &done,
00545                        unsigned int &cnt, oqmlBool firstPass)
00546 {
00547   if (node)
00548     return node->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00549 
00550   oqmlStatus *s;
00551 
00552   ctx->incrOrContext();
00553   s = qleft->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00554 
00555   if (!s)
00556     {
00557       unsigned int cnt_r;
00558       s = qright->preEvalSelect(db, ctx, ident, done, cnt_r, firstPass);
00559       if (!s) cnt += cnt_r;
00560     }
00561 
00562   ctx->decrOrContext();
00563   return s;
00564 }
00565 
00566 oqmlBool oqmlLOr::isConstant() const
00567 {
00568   return oqml_False;
00569 }
00570 
00571 void
00572 oqmlLOr::lock()
00573 {
00574   oqmlNode::lock();
00575   qleft->lock();
00576   qright->lock();
00577   if (node) node->lock();
00578 }
00579 
00580 void
00581 oqmlLOr::unlock()
00582 {
00583   oqmlNode::unlock();
00584   qleft->unlock();
00585   qright->unlock();
00586   if (node) node->unlock();
00587 }
00588 
00589 std::string
00590 oqmlLOr::toString(void) const
00591 {
00592   return (node ? node->toString() :
00593           oqml_binop_string(qleft, qright, (isLiteral ? " or " : "||"),
00594                             is_statement));
00595 }
00596 
00597 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00598 //
00599 // logical AND operator methods
00600 //
00601 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00602 
00603 oqmlLAnd::oqmlLAnd(oqmlNode * _qleft, oqmlNode * _qright,
00604                    oqmlBool _isLiteral, oqmlNode *_intersect_pred) :
00605   oqmlNode(oqmlLAND)
00606 {
00607   qleft = _qleft;
00608   qright = _qright;
00609   isLiteral = _isLiteral;
00610   eval_type.type = oqmlATOM_BOOL;
00611   node = 0;
00612   intersect_pred = _intersect_pred;
00613   must_intersect = oqml_False;
00614   estimated = oqml_False;
00615   r_first =  r_second = 0;
00616 }
00617 
00618 oqmlLAnd::~oqmlLAnd()
00619 {
00620 }
00621 
00622 oqmlStatus *oqmlLAnd::compile(Database *db, oqmlContext *ctx)
00623 {
00624   node = 0;
00625   requalified = oqml_False;
00626 
00627   if (ctx->isSelectContext())
00628     {
00629 #ifdef STRICT_SELECT
00630       return new oqmlStatus(this, "this type of query constructs is no more supported: use select/from/where clause");
00631 #else
00632       node = new oqmlAnd(qleft, qright);
00633       if (isLocked())
00634         node->lock();
00635       return node->compile(db, ctx);
00636 #endif
00637     }
00638 
00639   oqmlStatus *s;
00640 
00641   s = qleft->compile(db, ctx);
00642   if (s)
00643     return s;
00644 
00645   s = oqml_check_type(this, db, ctx, qleft, "&&");
00646   if (s)
00647     return s;
00648 
00649   s = qright->compile(db, ctx);
00650   if (s)
00651     return s;
00652 
00653   s = oqml_check_type(this, db, ctx, qright, "&&");
00654   if (s)
00655     return s;
00656 
00657   return oqmlSuccess;
00658 }
00659 
00660 oqmlStatus *oqmlLAnd::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00661 {
00662   if (node)
00663     return node->eval(db, ctx, alist);
00664 
00665   oqmlStatus *s;
00666   oqmlAtomList *al_left, *al_right;
00667 
00668   *alist = new oqmlAtomList;
00669 
00670   s = qleft->eval(db, ctx, &al_left);
00671   if (s)
00672     return s;
00673 
00674   oqmlBool b;
00675 
00676   s = oqml_check_logical(this, al_left, b);
00677   if (s)
00678     return s;
00679 
00680   if (!b)
00681     {
00682       (*alist)->append(new oqmlAtom_bool(oqml_False));
00683       return oqmlSuccess;
00684     }
00685 
00686   s = qright->eval(db, ctx, &al_right);
00687   if (s)
00688     return s;
00689 
00690   s = oqml_check_logical(this, al_right, b);
00691   if (s)
00692     return s;
00693 
00694   if (b)
00695     (*alist)->append(new oqmlAtom_bool(oqml_True));
00696   else
00697     (*alist)->append(new oqmlAtom_bool(oqml_False));
00698 
00699   return oqmlSuccess;
00700 }
00701 
00702 void oqmlLAnd::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00703 {
00704   *at = eval_type;
00705 }
00706 
00707 class OptimContext {
00708 
00709   LinkedList varlist;
00710   oqmlNode *node;
00711   Database *db;
00712   oqmlContext *ctx;
00713 
00714   oqmlStatus *push(const char *ident, oqmlAtom *x) {
00715     oqmlStatus *s = ctx->pushSymbol(ident, &x->type, x, oqml_True, oqml_True);
00716     if (s) return s;
00717     varlist.insertObject((void *)ident);
00718     return s;
00719   }
00720 
00721 public:
00722   OptimContext(oqmlNode *_node, Database *_db, oqmlContext *_ctx) :
00723     node(_node), db(_db), ctx(_ctx) { }
00724 
00725   oqmlStatus *realize(oqmlNode *intersect_pred, oqmlBool done,
00726                       unsigned int r_first, unsigned int r_second,
00727                       unsigned int cnt, oqmlBool &make_intersect)
00728     {
00729       if (!intersect_pred)
00730         {
00731           make_intersect = oqml_False;
00732           return oqmlSuccess;
00733         }
00734 
00735       oqmlStatus *s = push("oql$done_1", new oqmlAtom_bool(done));
00736       if (s) return s;
00737 
00738       s = push("oql$estim_1", new oqmlAtom_int(r_first));
00739       if (s) return s;
00740 
00741       s = push("oql$estim_2", new oqmlAtom_int(r_second));
00742       if (s) return s;
00743 
00744       s = push("oql$count_1", new oqmlAtom_int(cnt));
00745       if (s) return s;
00746 
00747       int select_ctx_cnt = ctx->getSelectContextCount();
00748 
00749       s = intersect_pred->compile(db, ctx);
00750       oqmlAtomList *al = 0;
00751       if (!s)
00752         s = intersect_pred->eval(db, ctx, &al);
00753 
00754       ctx->setSelectContextCount(select_ctx_cnt);
00755 
00756       if (s) return s;
00757 
00758       if (al->cnt != 1 || !OQML_IS_BOOL(al->first))
00759         return new oqmlStatus(node, "and hint: bool expected, got %s",
00760                               al->first ? al->first->type.getString() :
00761                               "nothing");
00762 
00763       make_intersect = OQML_ATOM_BOOLVAL(al->first);
00764       return oqmlSuccess;
00765     }
00766 
00767   ~OptimContext() {
00768     LinkedListCursor c(varlist);
00769     const char *ident;
00770     while (c.getNext((void *&)ident))
00771       ctx->popSymbol(ident, oqml_True);
00772   }
00773 
00774 };
00775 
00776 const char *
00777 oqmlLAnd::getDefaultRule()
00778 {
00779   // WARNING: this must match the test in oqmlLAnd::preEvalSelect_optim
00780   return "!oql$done_1 || (oql$estim_2 != oql$ESTIM_MAX && oql$estim_2 <= oql$estim_1 && oql$count_1 > 100)";
00781 }
00782 
00783 oqmlStatus *
00784 oqmlLAnd::estimateLAnd(Database *db, oqmlContext *ctx)
00785 {
00786   if (estimated)
00787     return oqmlSuccess;
00788 
00789   unsigned int r_left, r_right;
00790   oqmlStatus *s;
00791 
00792   s = qleft->estimate(db, ctx, r_left);
00793   if (s) return s;
00794 
00795   ctx->incrAndContext();
00796   s = qright->estimate(db, ctx, r_right);
00797   ctx->decrAndContext();
00798   if (s) return s;
00799 
00800   estimated = oqml_True;
00801 
00802   if (r_left <= r_right)
00803     {
00804       r_first = r_left;
00805       r_second = r_right;
00806       return oqmlSuccess;
00807     }
00808 
00809   oqmlNode *ql = qleft;
00810   qleft = qright;
00811   qright = ql;
00812   r_first = r_right;
00813   r_second = r_left;
00814   return oqmlSuccess;
00815 }
00816 
00817 oqmlStatus *
00818 oqmlLAnd::preEvalSelect_optim(Database *db, oqmlContext *ctx,
00819                               const char *ident, oqmlBool &done,
00820                               unsigned int &cnt, oqmlBool firstPass)
00821 {
00822   if (node)
00823     return node->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00824 
00825   oqmlStatus *s;
00826   s = estimateLAnd(db, ctx);
00827   if (s) return s;
00828 
00829   s = qleft->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00830   if (s) return s;
00831 
00832   OptimContext optim_ctx(this, db, ctx);
00833   oqmlBool make_intersect;
00834   s = optim_ctx.realize(intersect_pred, done, r_first, r_second, cnt,
00835                         make_intersect);
00836   if (s) return s;
00837 
00838   /*
00839     default rule:
00840     !oql$done_1 || (oql$estim_2 != oql$ESTIM_MAX && oql$estim_2 < oql$estim_1 && oql$count_1 > 100)
00841     */
00842 
00843   if (!must_intersect && intersect_pred && !make_intersect)
00844     return oqmlSuccess;
00845 
00846   if (firstPass &&
00847       (must_intersect || make_intersect ||
00848        // WARNING: the following code must match default rule
00849        !done || (r_second != oqml_ESTIM_MAX && r_second <= r_first && cnt > 100)))
00850     {
00851       unsigned int cnt_r;
00852       oqmlBool odone = done;
00853       if (odone) ctx->incrAndContext();
00854       s = qright->preEvalSelect(db, ctx, ident, done, cnt_r, firstPass);
00855       if (odone) ctx->decrAndContext();
00856       return s;
00857     }
00858 
00859   return oqmlSuccess;
00860 }
00861 
00862 oqmlStatus *
00863 oqmlLAnd::preEvalSelect_nooptim(Database *db, oqmlContext *ctx,
00864                                 const char *ident, oqmlBool &done,
00865                                 unsigned int &cnt, oqmlBool firstPass)
00866 {
00867   if (node)
00868     return node->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00869 
00870   oqmlStatus *s;
00871 
00872   // 29/08/02 : en mode non optimisé, on doit prendre l'ordre du ``and''
00873   // as is !
00874 #if 1
00875   s = qleft->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00876   if (s || done) return s;
00877   return qright->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00878 #else
00879   unsigned int r_left, r_right;
00880 
00881   s = qleft->estimate(db, ctx, r_left);
00882   if (s) return s;
00883 
00884   if (r_left != oqml_ESTIM_MIN)
00885     {
00886       s = qright->estimate(db, ctx, r_right);
00887       if (s) return s;
00888     }
00889   else
00890     r_right = oqml_ESTIM_MAX;
00891 
00892   if (r_left <= r_right)
00893     {
00894       s = qleft->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00895       if (s || done) return s;
00896       return qright->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00897     }
00898 
00899   s = qright->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00900   if (s || done) return s;
00901   return qleft->preEvalSelect(db, ctx, ident, done, cnt, firstPass);
00902 #endif
00903 }
00904 
00905 #define REQUALIFY_AND(OPL, OPLEQ, OPR, OPREQ, \
00906                       getL1, getR1, getL2, getR2) \
00907   if ((left_type == OPL || left_type == OPLEQ) && \
00908       (right_type == OPR || right_type == OPREQ))\
00909     { \
00910       oqmlComp *cleft = ((oqmlComp *)qleft); \
00911       oqmlComp *cright = ((oqmlComp *)qright); \
00912  \
00913       if (cleft->getL1()->toString() == cright->getR1()->toString()) \
00914         return new oqmlBetween \
00915           (cleft->getL1(), \
00916            new oqmlRange(cleft->getL2(), \
00917                          (left_type == OPL ? oqml_False : oqml_True), \
00918                          cright->getR2(), \
00919                          (right_type == OPR ? oqml_False : oqml_True))); \
00920     }
00921 
00922 oqmlNode *
00923 oqmlLAnd::requalifyRange()
00924 {
00925   oqmlTYPE left_type = qleft->getType();
00926   oqmlTYPE right_type = qright->getType();
00927 
00928   REQUALIFY_AND(oqmlSUP, oqmlSUPEQ, oqmlINF, oqmlINFEQ,
00929                 getLeft, getLeft, getRight, getRight);
00930 
00931   REQUALIFY_AND(oqmlINF, oqmlINFEQ, oqmlSUP, oqmlSUPEQ,
00932                 getRight, getRight, getLeft, getLeft);
00933   REQUALIFY_AND(oqmlINF, oqmlINFEQ, oqmlINF, oqmlINFEQ,
00934                 getRight, getLeft, getLeft, getRight);
00935   REQUALIFY_AND(oqmlSUP, oqmlSUPEQ, oqmlSUP, oqmlSUPEQ,
00936                 getLeft, getRight, getRight, getLeft);
00937 
00938   return (oqmlNode *)0;
00939 }
00940 
00941 oqmlStatus *
00942 oqmlLAnd::requalify(Database *db, oqmlContext *ctx,
00943                     const char *_ident, oqmlNode *_node, oqmlBool& done)
00944 {
00945   if (requalified)
00946     return oqmlSuccess;
00947 
00948   //printf("BEFORE #1 REQUALIFICATION %s\n", (const char *)toString());
00949   oqmlBool done_left = oqml_False, done_right = oqml_False;
00950   oqmlStatus *s = requalify_node(db, ctx, qleft, _ident, _node, done_left);
00951   if (s) return s;
00952   s = requalify_node(db, ctx, qright, _ident, _node, done_right);
00953   if (s) return s;
00954 
00955   //printf("AFTER #1 REQUALIFICATION %s\n", (const char *)toString());
00956   oqmlBool and_optim = isAndOptim(ctx);
00957 
00958   if (and_optim) {
00959     s = estimateLAnd(db, ctx);
00960     if (s) return s;
00961   }
00962 
00963   // must requalify back only if done_left and done_right
00964   //printf("DONES %d %d\n", done_left, done_right);
00965   if (done_left && done_right)
00966     {
00967       s = requalify_back(db, ctx);
00968       if (s) return s;
00969     }
00970 
00971   if (and_optim) {
00972     must_intersect = OQMLBOOL((done_left && !done_right) ||
00973                               (!done_left && done_right));
00974 
00975   }
00976 
00977   /*
00978   printf("AFTER #2 REQUALIFICATION %s %d\n", (const char *)toString(),
00979          must_intersect);
00980          */
00981 
00982   if (OQMLBOOL(done_left || done_right))
00983     done = oqml_True;
00984 
00985   requalified = oqml_True;
00986   return oqmlSuccess;
00987 }
00988 
00989 oqmlStatus *
00990 oqmlLAnd::requalify_back(Database *db, oqmlContext *ctx)
00991 {
00992   return requalify_node_back(db, ctx, qright);
00993 }
00994 
00995 oqmlBool
00996 oqmlLAnd::isAndOptim(oqmlContext *ctx)
00997 {
00998   static const char oql_no_and_optim[] = "oql$no_and_optim";
00999   return oqml_is_symbol(ctx, oql_no_and_optim) ? oqml_False : oqml_True;
01000 }
01001 
01002 oqmlStatus *
01003 oqmlLAnd::preEvalSelect(Database *db, oqmlContext *ctx,
01004                         const char *ident, oqmlBool &done,
01005                         unsigned int &cnt, oqmlBool firstPass)
01006 {
01007   if (isAndOptim(ctx))
01008     return preEvalSelect_optim(db, ctx, ident, done, cnt, firstPass);
01009   return preEvalSelect_nooptim(db, ctx, ident, done, cnt, firstPass);
01010 }
01011 
01012 oqmlBool oqmlLAnd::isConstant() const
01013 {
01014   return oqml_False;
01015 }
01016 
01017 void
01018 oqmlLAnd::lock()
01019 {
01020   oqmlNode::lock();
01021   qleft->lock();
01022   qright->lock();
01023   if (node) node->lock();
01024   if (intersect_pred) intersect_pred->lock();
01025 }
01026 
01027 void
01028 oqmlLAnd::unlock()
01029 {
01030   oqmlNode::unlock();
01031   qleft->unlock();
01032   qright->unlock();
01033   if (node) node->unlock();
01034   if (intersect_pred) intersect_pred->unlock();
01035 }
01036 
01037 std::string
01038 oqmlLAnd::toString(void) const
01039 {
01040   return (node ? node->toString() :
01041           oqml_binop_string(qleft, qright, (isLiteral ? " and " : "&&"),
01042                             is_statement));
01043 }
01044 
01045 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01046 //
01047 // logical NOT operator methods
01048 //
01049 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01050 
01051 oqmlLNot::oqmlLNot(oqmlNode * _ql) : oqmlNode(oqmlLNOT)
01052 {
01053   ql = _ql;
01054   eval_type.type = oqmlATOM_BOOL;
01055 }
01056 
01057 oqmlLNot::~oqmlLNot()
01058 {
01059 }
01060 
01061 oqmlStatus *oqmlLNot::compile(Database *db, oqmlContext *ctx)
01062 {
01063   oqmlStatus *s;
01064 
01065   s = ql->compile(db, ctx);
01066   if (s)
01067     return s;
01068 
01069   return oqml_check_type(this, db, ctx, ql, "!");
01070 }
01071 
01072 oqmlStatus *oqmlLNot::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01073 {
01074   oqmlStatus *s;
01075   oqmlAtomList *al;
01076 
01077   *alist = new oqmlAtomList;
01078 
01079   s = ql->eval(db, ctx, &al);
01080   if (s)
01081     return s;
01082 
01083   oqmlBool b;
01084 
01085   s = oqml_check_logical(this, al, b);
01086   if (s)
01087     return s;
01088 
01089   if (b)
01090     (*alist)->append(new oqmlAtom_bool(oqml_False));
01091   else
01092     (*alist)->append(new oqmlAtom_bool(oqml_True));
01093 
01094   return oqmlSuccess;
01095 }
01096 
01097 void oqmlLNot::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01098 {
01099   *at = eval_type;
01100 }
01101 
01102 oqmlBool oqmlLNot::isConstant() const
01103 {
01104   return ql->isConstant();
01105 }
01106 
01107 std::string
01108 oqmlLNot::toString(void) const
01109 {
01110   return oqml_unop_string(ql, "!", is_statement);
01111 }
01112 
01113 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01114 //
01115 // comma binary operator methods
01116 //
01117 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01118 
01119 oqmlComma::oqmlComma(oqmlNode * _qleft, oqmlNode * _qright, oqmlBool _is_statement) :
01120   oqmlNode(oqmlCOMMA)
01121 {
01122   qleft = _qleft;
01123   qright = _qright;
01124   is_statement = _is_statement;
01125 }
01126 
01127 oqmlComma::~oqmlComma()
01128 {
01129 }
01130 
01131 oqmlStatus *oqmlComma::compile(Database *db, oqmlContext *ctx)
01132 {
01133   oqmlStatus *s;
01134 
01135   s = qleft->compile(db, ctx);
01136   if (s)
01137     return s;
01138 
01139   s = qright->compile(db, ctx);
01140   if (s)
01141     return s;
01142 
01143   return oqmlSuccess;
01144 }
01145 
01146 oqmlStatus *oqmlComma::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01147 {
01148   oqmlStatus *s;
01149   oqmlAtomList *al_left, *al_right;
01150 
01151   *alist = new oqmlAtomList();
01152 
01153   s = qleft->eval(db, ctx, &al_left);
01154   if (s)
01155     return s;
01156 
01157 #ifdef SYNC_GARB
01158   OQL_DELETE(al_left);
01159 #endif
01160   s = qright->eval(db, ctx, &al_right);
01161   if (s)
01162     return s;
01163 
01164   (*alist)->append(al_right);
01165   /*
01166 #ifdef SYNC_GARB
01167   al_right->first = 0;
01168   OQL_DELETE(al_right);
01169 #endif
01170   */
01171 
01172   return oqmlSuccess;
01173 }
01174 
01175 void oqmlComma::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01176 {
01177   oqmlAtomType at_left, at_right;
01178   oqmlStatus *s;
01179 
01180   qright->evalType(db, ctx, &at_right);
01181 
01182   *at = at_right;
01183 }
01184 
01185 oqmlBool oqmlComma::isConstant() const
01186 {
01187   return oqml_False;
01188 }
01189 
01190 std::string
01191 oqmlComma::toString(void) const
01192 {
01193   if (!is_statement)
01194     return oqml_binop_string(qleft, qright, ",", is_statement);
01195 
01196   return qleft->toString() + qright->toString();
01197 }
01198 
01199 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01200 //
01201 // assignement binary operator methods
01202 //
01203 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01204 
01205 oqmlAssign::oqmlAssign(oqmlNode * _qleft, oqmlNode * _qright)
01206   : oqmlNode(oqmlASSIGN)
01207 {
01208   qleft = _qleft;
01209   qright = _qright;
01210   ident = 0;
01211 }
01212 
01213 oqmlAssign::~oqmlAssign()
01214 {
01215   free(ident);
01216 }
01217 
01218 oqmlStatus *oqmlAssign::compile(Database *db, oqmlContext *ctx)
01219 {
01220   oqmlStatus *s;
01221 
01222   free(ident); ident = 0;
01223 
01224   s = qleft->compile(db, ctx);
01225   if (s) return s;
01226 
01227   s = qright->compile(db, ctx);
01228   if (s) return s;
01229 
01230   if (qleft->getType() == oqmlIDENT)
01231     {
01232       ident = strdup(((oqmlIdent *)qleft)->getName());
01233       return oqmlSuccess;
01234     }
01235 
01236   if (qleft->asDot())
01237     {
01238       oqmlAtomType at_left, at_right;
01239 
01240       qleft->evalType(db, ctx, &at_left);
01241       qright->evalType(db, ctx, &at_right);
01242           
01243       if (at_left.type != oqmlATOM_UNKNOWN_TYPE &&
01244           at_right.type != oqmlATOM_UNKNOWN_TYPE &&
01245           !at_left.cmp(at_right))
01246         {
01247           if (at_left.type == oqmlATOM_OID && at_right.type != oqmlATOM_NULL)
01248             return new oqmlStatus(this, "incompatible types for assignation: "
01249                                  "%s expected, got %s.",
01250                                  at_left.getString(), at_right.getString());
01251         }
01252 
01253       return oqmlSuccess;
01254     }
01255 
01256   return oqmlSuccess;
01257 }
01258 
01259 oqmlStatus *oqmlAssign::eval(Database *db, oqmlContext *ctx,
01260                              oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01261 {
01262   oqmlAtomList *al_right = 0;
01263   oqmlStatus *s;
01264   oqmlAtom *leftValue = 0;
01265   oqmlSymbolEntry *entry = 0;
01266   int idx = -1;
01267 
01268   s = qright->eval(db, ctx, &al_right);
01269   if (s) return s;
01270 
01271   if (!ident && qleft->getType() != oqmlDOT)
01272     {
01273       s = qleft->evalLeft(db, ctx, &leftValue, idx);
01274       if (s) return s;
01275 
01276       if (!leftValue)
01277         return new oqmlStatus(this, "not a left value");
01278 
01279       if (leftValue->as_ident())
01280         {
01281           ident = strdup(OQML_ATOM_IDENTVAL(leftValue));
01282           entry = leftValue->as_ident()->entry;
01283         }
01284     }
01285 
01286   if (ident)
01287     {
01288       oqmlAtom *a;
01289       if (al_right->cnt == 1) {
01290         a = al_right->first;
01291 #ifdef SYNC_GARB
01292         if (al_right && !al_right->refcnt) {
01293           al_right->first = 0;
01294           OQL_DELETE(al_right);
01295         }
01296 #endif
01297       }
01298       else if (al_right->cnt)
01299         a = new oqmlAtom_list(al_right);
01300       else
01301         a = NULL;
01302 
01303       oqmlBool global;
01304 
01305       if (entry)
01306         {
01307           // added the 3/01/00 to set both entries (:: prefixed, and not
01308           // prefixed) in the symbol table.
01309           if (entry->global)
01310             {
01311               s = ctx->setSymbol(entry->ident, (a ? &a->type : 0), a, oqml_True);
01312               if (s) return s;
01313             }
01314           // ...
01315           else
01316             entry->set((a ? &a->type : 0), a);
01317         }
01318       else
01319         {
01320           if (!ctx->getSymbol(ident, 0, 0, &global) || global ||
01321               !strncmp(ident, oqml_global_scope, oqml_global_scope_len))
01322             s = ctx->setSymbol(ident, (a ? &a->type : 0), a, oqml_True);
01323           else
01324             s = ctx->setSymbol(ident, (a ? &a->type : 0), a, oqml_False);
01325 
01326           if (s) return s;
01327         }
01328 
01329       *alist = new oqmlAtomList(a);
01330       free(ident); ident = 0;
01331       return oqmlSuccess;
01332     }
01333 
01334   if (leftValue)
01335     {
01336       if (idx < 0)
01337         return new oqmlStatus(this, "not a left value");
01338 
01339       oqmlAtom *a = 0;
01340 
01341       if (al_right->cnt == 1) {
01342         a = al_right->first;
01343 #ifdef SYNC_GARB
01344         if (al_right && !al_right->refcnt) {
01345           al_right->first = 0;
01346           OQL_DELETE(al_right);
01347         }
01348 #endif
01349       }
01350 
01351       if (leftValue->as_string()) {
01352         s = leftValue->as_string()->setAtom(a, idx, this);
01353         if (s) return s;
01354       }
01355       else if (leftValue->as_list()) {
01356         s = leftValue->as_list()->setAtom(a, idx, this);
01357         if (s) return s;
01358       }
01359       else if (leftValue->as_array()) {
01360         s = leftValue->as_array()->setAtom(a, idx, this);
01361         if (s) return s;
01362       }
01363       else if (leftValue->as_struct()) {
01364         s = leftValue->as_struct()->setAtom(a, idx, this);
01365         if (s) return s;
01366       }
01367       else if (OQML_IS_OBJECT(leftValue)) {
01368         Object *o = 0;
01369         s = oqmlObjectManager::getObject(this, db, leftValue, o, oqml_False,
01370                                          oqml_True);
01371         if (s) return s;
01372         
01373         if (!o->asCollArray()) {
01374           oqmlObjectManager::releaseObject(o, oqml_False);
01375           return new oqmlStatus(this, "not a left value");
01376         }
01377 
01378         Status is;
01379 
01380         if (a->as_null() || (a->as_oid() && !OQML_ATOM_OIDVAL(a).isValid())
01381             || (a->as_obj() && !OQML_ATOM_OBJVAL(a)))
01382           is = o->asCollArray()->suppressAt(idx);
01383         else if (a->as_oid())
01384           is = o->asCollArray()->insertAt(idx, OQML_ATOM_OIDVAL(a));
01385         else if (a->as_obj()) {
01386           OQL_CHECK_OBJ(a);
01387           is = o->asCollArray()->insertAt(idx, OQML_ATOM_OBJVAL(a));
01388         }
01389         else {
01390           oqmlObjectManager::releaseObject(o, oqml_False);
01391           return new oqmlStatus(this, "left value: only support collection array of objects");
01392         }
01393 
01394         if (!is)
01395           is = o->store();
01396         oqmlObjectManager::releaseObject(o, oqml_False);
01397         if (is) return new oqmlStatus(this, is);
01398       }
01399       else
01400         return new oqmlStatus(this, "not a left value");
01401       
01402       *alist = new oqmlAtomList(a);
01403       return oqmlSuccess;
01404     }
01405 
01406   if (qleft->asDot()) {
01407     if (al_right->cnt != 1)
01408       return new oqmlStatus(this, "invalid right part for dot");
01409     
01410     return qleft->asDot()->set(db, ctx, al_right->first, alist);
01411   }
01412 
01413   return new oqmlStatus(this, "not a left value");
01414 }
01415 
01416 void oqmlAssign::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01417 {
01418   *at = eval_type;
01419 }
01420 
01421 oqmlBool oqmlAssign::isConstant() const
01422 {
01423   return oqml_False;
01424 }
01425 
01426 std::string
01427 oqmlAssign::toString(void) const
01428 {
01429   return oqml_binop_string(qleft, qright, ":=", is_statement);
01430 }
01431 
01432 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01433 //
01434 // oqmlCompoundStatement operator methods
01435 //
01436 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01437 
01438 oqmlCompoundStatement::oqmlCompoundStatement(oqmlNode * _node) : oqmlNode(oqmlCOMPOUND_STATEMENT)
01439 {
01440   node = _node;
01441 }
01442 
01443 oqmlCompoundStatement::~oqmlCompoundStatement()
01444 {
01445 }
01446 
01447 oqmlStatus *oqmlCompoundStatement::compile(Database *db, oqmlContext *ctx)
01448 {
01449   if (!node)
01450     return oqmlSuccess;
01451 
01452   return node->compile(db, ctx);
01453 }
01454 
01455 oqmlStatus *oqmlCompoundStatement::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01456 {
01457   if (!node)
01458     return oqmlSuccess;
01459 
01460   *alist = new oqmlAtomList();
01461   oqmlAtomList *dlist = 0;
01462   oqmlStatus *s = node->eval(db, ctx, &dlist);
01463 #ifdef SYNC_GARB
01464   OQL_DELETE(dlist);
01465 #endif
01466   return s;
01467 }
01468 
01469 void oqmlCompoundStatement::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01470 {
01471   *at = eval_type;
01472 }
01473 
01474 oqmlBool oqmlCompoundStatement::isConstant() const
01475 {
01476   return oqml_False;
01477 }
01478 
01479 std::string
01480 oqmlCompoundStatement::toString(void) const
01481 {
01482   return std::string("{ ") + (node ? node->toString() : std::string("")) +
01483     "}";
01484 }
01485 
01486 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01487 //
01488 // unary typeof operator methods
01489 //
01490 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01491 
01492 oqmlTypeOf::oqmlTypeOf(oqmlNode * _ql) : oqmlNode(oqmlTYPEOF)
01493 {
01494   ql = _ql;
01495   eval_type.type = oqmlATOM_STRING;
01496   eval_type.comp = oqml_True;
01497 }
01498 
01499 oqmlTypeOf::~oqmlTypeOf()
01500 {
01501 }
01502 
01503 oqmlStatus *oqmlTypeOf::compile(Database *db, oqmlContext *ctx)
01504 {
01505   return ql->compile(db, ctx);
01506 }
01507 
01508 oqmlStatus *oqmlTypeOf::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01509 {
01510   oqmlStatus *s;
01511 
01512   oqmlAtomList *al;
01513   s = ql->eval(db, ctx, &al);
01514   if (s)
01515     return s;
01516 
01517   if (!al->cnt)
01518     *alist = new oqmlAtomList(new oqmlAtom_string("nil"));
01519   else
01520     *alist = new oqmlAtomList(new oqmlAtom_string(al->first->type.getString()));
01521   return oqmlSuccess;
01522 }
01523 
01524 void oqmlTypeOf::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01525 {
01526   *at = eval_type;
01527 }
01528 
01529 oqmlBool oqmlTypeOf::isConstant() const
01530 {
01531   return OQMLBOOL(ql->isConstant());
01532 }
01533 
01534 std::string
01535 oqmlTypeOf::toString(void) const
01536 {
01537   return oqml_unop_string(ql, "typeof ", is_statement);
01538 }
01539 
01540 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01541 //
01542 // unary unval operator methods
01543 //
01544 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01545 
01546 oqmlUnval::oqmlUnval(oqmlNode * _ql) : oqmlNode(oqmlUNVAL)
01547 {
01548   ql = _ql;
01549   eval_type.type = oqmlATOM_STRING;
01550   eval_type.comp = oqml_True;
01551 }
01552 
01553 oqmlUnval::~oqmlUnval()
01554 {
01555 }
01556 
01557 oqmlStatus *oqmlUnval::compile(Database *db, oqmlContext *ctx)
01558 {
01559   return oqmlSuccess;
01560 }
01561 
01562 oqmlStatus *oqmlUnval::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01563 {
01564   *alist = new oqmlAtomList(new oqmlAtom_string
01565                             ((ql->toString() +
01566                               (ql->is_statement ? "; " : "")).c_str()));
01567   return oqmlSuccess;
01568 }
01569 
01570 void oqmlUnval::evalType(Database *db, oqmlContext *ctx,
01571                             oqmlAtomType *at)
01572 {
01573   *at = eval_type;
01574 }
01575 
01576 oqmlBool oqmlUnval::isConstant() const
01577 {
01578   return oqml_True;
01579 }
01580 
01581 std::string
01582 oqmlUnval::toString(void) const
01583 {
01584   return std::string("unval(") + ql->toString() + std::string(")");
01585 }
01586 
01587 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01588 //
01589 // unary eval operator methods
01590 //
01591 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01592 
01593 oqmlEval::oqmlEval(oqmlNode * _ql) : oqmlNode(oqmlEVAL)
01594 {
01595   ql = _ql;
01596 }
01597 
01598 oqmlEval::~oqmlEval()
01599 {
01600 }
01601 
01602 oqmlStatus *oqmlEval::compile(Database *db, oqmlContext *ctx)
01603 {
01604   oqmlStatus *s;
01605 
01606   s = ql->compile(db, ctx);
01607   if (s)
01608     return s;
01609 
01610   return oqmlSuccess;
01611 }
01612 
01613 oqmlStatus *oqmlEval::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01614 {
01615   oqmlStatus *s;
01616 
01617   oqmlAtomList *al;
01618   s = ql->eval(db, ctx, &al);
01619   if (s)
01620     return s;
01621 
01622   if (al->cnt == 1 && al->first->as_string())
01623     {
01624       char *str = strdup((std::string(OQML_ATOM_STRVAL(al->first)) + ";").c_str());
01625       s = oqml_realize(db, str, alist);
01626       free(str);
01627       return s;
01628     }
01629 
01630   return new oqmlStatus(this, "string expected");
01631 }
01632 
01633 void oqmlEval::evalType(Database *db, oqmlContext *ctx,
01634                         oqmlAtomType *at)
01635 {
01636   *at = eval_type;
01637 }
01638 
01639 oqmlBool oqmlEval::isConstant() const
01640 {
01641   return OQMLBOOL(ql->isConstant());
01642 }
01643 
01644 std::string
01645 oqmlEval::toString(void) const
01646 {
01647   return oqml_unop_string(ql, "eval ", is_statement);
01648 }
01649 
01650 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01651 //
01652 // unary prin operator methods
01653 //
01654 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01655 
01656 oqmlPrint::oqmlPrint(oqmlNode * _ql) : oqmlNode(oqmlPRINT)
01657 {
01658   ql = _ql;
01659 }
01660 
01661 oqmlPrint::~oqmlPrint()
01662 {
01663 }
01664 
01665 oqmlStatus *oqmlPrint::compile(Database *db, oqmlContext *ctx)
01666 {
01667   oqmlStatus *s;
01668 
01669   s = ql->compile(db, ctx);
01670   if (s)
01671     return s;
01672 
01673   return oqmlSuccess;
01674 }
01675 
01676 oqmlStatus *oqmlPrint::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01677 {
01678   oqmlStatus *s;
01679 
01680   oqmlAtomList *al;
01681   s = ql->eval(db, ctx, &al);
01682   if (s)
01683     return s;
01684 
01685   if (al->cnt == 1 && al->first->as_string())
01686     {
01687       /*
01688       fprintf(stdout, OQML_ATOM_STRVAL(al->first));
01689       fflush(stdout);
01690       */
01691       Connection::setServerMessage(OQML_ATOM_STRVAL(al->first));
01692       *alist = new oqmlAtomList();
01693       return oqmlSuccess;
01694     }
01695 
01696   return new oqmlStatus(this, "string expected");
01697 }
01698 
01699 void oqmlPrint::evalType(Database *db, oqmlContext *ctx,
01700                         oqmlAtomType *at)
01701 {
01702   *at = eval_type;
01703 }
01704 
01705 oqmlBool oqmlPrint::isConstant() const
01706 {
01707   return OQMLBOOL(ql->isConstant());
01708 }
01709 
01710 std::string
01711 oqmlPrint::toString(void) const
01712 {
01713   return oqml_unop_string(ql, "print ", is_statement);
01714 }
01715 
01716 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01717 //
01718 // unary import operator methods
01719 //
01720 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01721 
01722 oqmlImport::oqmlImport(oqmlNode * _ql) : oqmlNode(oqmlIMPORT)
01723 {
01724   ql = _ql;
01725 }
01726 
01727 oqmlImport::~oqmlImport()
01728 {
01729 }
01730 
01731 oqmlStatus *oqmlImport::compile(Database *db, oqmlContext *ctx)
01732 {
01733   oqmlStatus *s;
01734 
01735   s = ql->compile(db, ctx);
01736   if (s)
01737     return s;
01738 
01739   return oqmlSuccess;
01740 }
01741 
01742 oqmlStatus *oqmlImport::eval(Database *db, oqmlContext *ctx,
01743                              oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01744 {
01745   oqmlStatus *s;
01746 
01747   oqmlAtomList *al;
01748   s = ql->eval(db, ctx, &al);
01749   if (s)
01750     return s;
01751 
01752   if (al->cnt == 1 && al->first->as_string())
01753     {
01754       char *file = OQML_ATOM_STRVAL(al->first);
01755       const char *oqmlpath = eyedb::ServerConfig::getSValue("oqlpath");
01756 
01757       oqmlBool check;
01758       if (!oqmlpath || file[0] == '/')
01759         {
01760           check = oqml_False;
01761           return import_realize(db, alist, file, 0, check);
01762         }
01763 
01764       const char *x;
01765       int idx = 0;
01766       while (*(x = get_next_path(oqmlpath, idx)))
01767         {
01768           check = oqml_True;
01769           s = import_realize(db, alist, file, x, check);
01770           if (check || s)
01771             return s;
01772         }
01773 
01774       return new oqmlStatus(this, "cannot find file '%s'", file);
01775     }
01776 
01777   return new oqmlStatus(this, "string expected");
01778 }
01779 
01780 void oqmlImport::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01781 {
01782   *at = eval_type;
01783 }
01784 
01785 oqmlBool oqmlImport::isConstant() const
01786 {
01787   return oqml_False;
01788 }
01789 
01790 std::string
01791 oqmlImport::toString(void) const
01792 {
01793   return oqml_unop_string(ql, "import ", is_statement);
01794 }
01795 
01796 oqmlStatus *
01797 oqmlImport::import_realize(Database *db,
01798                            oqmlAtomList **alist,
01799                            const char *file, const char *dir, oqmlBool &check)
01800 {
01801   static const char suffix[] = ".oql";
01802   static const unsigned int suffix_len = strlen(suffix);
01803   std::string sfile;
01804 
01805   sfile = (dir ? std::string(dir) + "/" + file : std::string(file));
01806   int len = strlen(file);
01807   if (len <= suffix_len || strcmp(&file[len-suffix_len], suffix))
01808     sfile += suffix;
01809       
01810   int fd = open(sfile.c_str(), O_RDONLY);
01811 
01812   *alist = new oqmlAtomList();
01813   (*alist)->append(new oqmlAtom_string(sfile.c_str()));
01814 
01815   if (fd >= 0)
01816     {
01817       extern char *oqml_file;
01818       oqmlAtomList *xal;
01819       char *str;
01820       oqmlStatus *s = file_to_buf(sfile.c_str(), fd, str);
01821       if (s) return s;
01822       char *lastfile = oqml_file;
01823       oqml_file = strdup(sfile.c_str());
01824       s = oqml_realize(db, str, &xal);
01825       close(fd);
01826       free(str);
01827       if (!s) check = oqml_True;
01828       free(oqml_file);
01829       oqml_file = lastfile;
01830       return s;
01831     }
01832 
01833   if (check)
01834     {
01835       check = oqml_False;
01836       return oqmlSuccess;
01837     }
01838 
01839   return new oqmlStatus("cannot find file '%s'", sfile.c_str());
01840 }
01841 
01842 const char *
01843 oqmlImport::get_next_path(const char *oqmlpath, int &idx)
01844 {
01845   static char path[512];
01846 
01847   const char *s = strchr(oqmlpath+idx, ':');
01848   if (!s)
01849     {
01850       s = oqmlpath+idx;
01851       idx += strlen(oqmlpath+idx)+1;
01852       return s;
01853     }
01854 
01855   int len = s-oqmlpath-idx;
01856   strncpy(path, oqmlpath+idx, len);
01857   path[len] = 0;
01858   idx += strlen(path)+1;
01859   return path;
01860 }
01861 
01862 oqmlStatus *
01863 oqmlImport::file_to_buf(const char *file, int fd, char *&str)
01864 {
01865   struct stat st;
01866   if (fstat(fd, &st) < 0)
01867     return new oqmlStatus(this, "stat error on file '%s'",
01868                           file);
01869 
01870   str = (char *)malloc(st.st_size+1);
01871   if (read(fd, str, st.st_size) != st.st_size)
01872     {
01873       free(str);
01874       return new oqmlStatus(this, "read error on file '%s'",
01875                             file);
01876     }
01877 
01878   str[st.st_size] = 0;
01879   return oqmlSuccess;
01880 }
01881 
01882 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01883 //
01884 // self increment operator methods
01885 //
01886 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01887 
01888 oqmlSelfIncr::oqmlSelfIncr(oqmlNode * _ql, int _incr, oqmlBool _post)
01889   : oqmlNode(oqmlASSIGN)
01890 {
01891   ql = _ql;
01892   incr = _incr;
01893   post = _post;
01894   if (incr > 0)
01895     qlassign = new oqmlAssign(ql, new oqmlAdd(ql, new oqmlInt(incr)));
01896   else
01897     qlassign = new oqmlAssign(ql, new oqmlSub(ql, new oqmlInt(-incr)));
01898 }
01899 
01900 oqmlSelfIncr::~oqmlSelfIncr()
01901 {
01902 }
01903 
01904 oqmlStatus *oqmlSelfIncr::compile(Database *db, oqmlContext *ctx)
01905 {
01906   return qlassign->compile(db, ctx);
01907 }
01908 
01909 oqmlStatus *oqmlSelfIncr::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01910 {
01911   oqmlStatus *s;
01912 
01913   oqmlAtomList *al;
01914   s = qlassign->eval(db, ctx, &al);
01915 
01916   if (s)
01917     return s;
01918   
01919   if (!post)
01920     {
01921       *alist = al;
01922       return oqmlSuccess;
01923     }
01924 
01925   *alist = new oqmlAtomList();
01926   oqmlAtom *a = al->first;
01927   while (a)
01928     {
01929       oqmlAtom *x;
01930       if (a->type.type == oqmlATOM_INT)
01931         x = new oqmlAtom_int(OQML_ATOM_INTVAL(a)-incr);
01932       else if (a->type.type == oqmlATOM_DOUBLE)
01933         x = new oqmlAtom_double(OQML_ATOM_DBLVAL(a)-incr);
01934       else if (a->type.type == oqmlATOM_CHAR)
01935         x = new oqmlAtom_int(OQML_ATOM_CHARVAL(a)-incr);
01936       else
01937         new oqmlStatus(this, "cannot performed operation on '%s'",
01938                       (incr > 0 ? "++" : "--"), a->type.getString());
01939       (*alist)->append(x);
01940       a = a->next;
01941     }
01942 
01943   return oqmlSuccess;
01944 }
01945 
01946 void oqmlSelfIncr::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01947 {
01948   qlassign->evalType(db, ctx, at);
01949 }
01950 
01951 oqmlBool oqmlSelfIncr::isConstant() const
01952 {
01953   return qlassign->isConstant();
01954 }
01955 
01956 std::string
01957 oqmlSelfIncr::toString(void) const
01958 {
01959   const char *opstr = (incr > 0 ? "++" : "--");
01960   if (post)
01961     {
01962       if (is_statement)
01963         return ql->toString() + opstr + "; ";
01964       return std::string("(") + ql->toString() + opstr + std::string(")");
01965     }
01966 
01967   return oqml_unop_string(ql, opstr, is_statement);
01968 }
01969 
01970 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01971 //
01972 // unary tilde operator methods
01973 //
01974 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
01975 
01976 oqmlTilde::oqmlTilde(oqmlNode * _ql) : oqmlNode(oqmlTILDE)
01977 {
01978   ql = _ql;
01979 }
01980 
01981 oqmlTilde::~oqmlTilde()
01982 {
01983 }
01984 
01985 oqmlStatus *oqmlTilde::compile(Database *db, oqmlContext *ctx)
01986 {
01987   oqmlStatus *s;
01988 
01989   s = ql->compile(db, ctx);
01990   if (s)
01991     return s;
01992 
01993   return oqmlSuccess;
01994 }
01995 
01996 oqmlStatus *oqmlTilde::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01997 {
01998   oqmlStatus *s;
01999 
02000   oqmlAtomList *al;
02001   s = ql->eval(db, ctx, &al);
02002   if (s)
02003     return s;
02004 
02005   if (al->cnt > 1)
02006     return new oqmlStatus(this, "cannot perform operation on"
02007                          " a non atomic operand");
02008   if (al->cnt == 0)
02009     return new oqmlStatus(this, "cannot perform operation on"
02010                          " a nil operand");
02011 
02012   oqmlAtom *a = al->first;
02013   if (a->type.type == oqmlATOM_INT)
02014     *alist = new oqmlAtomList(new oqmlAtom_int(~((oqmlAtom_int *)a)->i));
02015   else if (a->type.type == oqmlATOM_CHAR)
02016     *alist = new oqmlAtomList(new oqmlAtom_int(~(int)((oqmlAtom_char *)a)->c));
02017   else
02018     return new oqmlStatus(this, "operation '~%s' is not valid",
02019                          a->type.getString());
02020   return oqmlSuccess;
02021 }
02022 
02023 void oqmlTilde::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
02024 {
02025   *at = eval_type;
02026 }
02027 
02028 oqmlBool oqmlTilde::isConstant() const
02029 {
02030   return OQMLBOOL(ql->isConstant());
02031 }
02032 
02033 std::string
02034 oqmlTilde::toString(void) const
02035 {
02036   return oqml_unop_string(ql, "~", is_statement);
02037 }
02038 
02039 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
02040 //
02041 // standard binary operator methods
02042 //
02043 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
02044 
02045 typedef oqmlStatus * (*oqml_check_fun)(oqmlNode *node, oqmlAtom *, oqmlAtom *a);
02046 
02047 static oqmlStatus *
02048 check_right_nonzero(oqmlNode *node, oqmlAtom *, oqmlAtom *a)
02049 {
02050   oqmlATOMTYPE at = a->type.type;
02051 
02052   if (at == oqmlATOM_INT)
02053     {
02054       if (!OQML_ATOM_INTVAL(a))
02055         return new oqmlStatus(node,
02056                               "right operand: invalid null integer value");
02057       return oqmlSuccess;
02058     }
02059 
02060   if (at == oqmlATOM_DOUBLE)
02061     {
02062       if (!OQML_ATOM_DBLVAL(a))
02063         return new oqmlStatus(node,
02064                               "right operand: invalid null float value");
02065       return oqmlSuccess;
02066     }
02067 
02068   if (at == oqmlATOM_CHAR)
02069     {
02070       if (!OQML_ATOM_CHARVAL(a))
02071         return new oqmlStatus(node,
02072                               "right operand: invalid null character value");
02073       return oqmlSuccess;
02074     }
02075 
02076   return oqmlSuccess;
02077 }
02078 
02079 std::string
02080 oqml_binop_string(oqmlNode *qleft, oqmlNode *qright, const char *opstr,
02081                   oqmlBool is_statement)
02082 {
02083   if (is_statement)
02084     return qleft->toString() + opstr + qright->toString() + "; ";
02085 
02086   return std::string("(") + qleft->toString() + opstr + 
02087     qright->toString() + std::string(")");
02088 }
02089 
02090 std::string
02091 oqml_unop_string(oqmlNode *ql, const char *opstr, oqmlBool is_statement)
02092 {
02093   if (is_statement)
02094     return std::string(opstr) + ql->toString() + "; ";
02095   return std::string("(") + opstr + ql->toString() + std::string(")");
02096 }
02097 
02098 #define OQML_INT_BINOP(oqml_x, oqml_XX, OP, OPSTR, CHECK_FUN) \
02099 oqml_x::oqml_x(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqml_XX) \
02100 { \
02101   qleft = _qleft; \
02102   qright = _qright; \
02103 } \
02104  \
02105 oqml_x::~oqml_x() \
02106 { \
02107 } \
02108  \
02109 oqmlStatus *oqml_x::compile(Database *db, oqmlContext *ctx) \
02110 { \
02111   oqmlBool iscts; \
02112   oqmlStatus *s; \
02113   s = binopCompile(db, ctx, OPSTR, qleft, qright, eval_type, oqmlIntOK, iscts); \
02114  \
02115   if (s) \
02116     return s; \
02117  \
02118   if (isConstant() && !cst_list) \
02119    { \
02120       oqmlAtomList *al; \
02121       s = eval(db, ctx, &al); \
02122       if (s) return s; \
02123       cst_list = al->copy(); \
02124       if (isLocked()) \
02125         oqmlLock(cst_list, oqml_True); \
02126    } \
02127  \
02128   return oqmlSuccess; \
02129 } \
02130  \
02131 oqmlStatus *oqml_x::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *) \
02132 { \
02133   if (cst_list) \
02134     { \
02135       *alist = new oqmlAtomList(cst_list); \
02136       return oqmlSuccess; \
02137     } \
02138  \
02139   oqmlAtomList *al_left, *al_right; \
02140   oqmlStatus *s = binopEval(db, ctx, OPSTR, eval_type, qleft, qright, oqmlIntOK, &al_left, &al_right); \
02141  \
02142   if (s) \
02143     return s; \
02144  \
02145   oqmlAtom *aleft = al_left->first, *aright = al_right->first; \
02146  \
02147   if (CHECK_FUN) \
02148     { \
02149       s = ((oqml_check_fun)CHECK_FUN)(this, aleft, aright); \
02150       if (s) return s; \
02151     } \
02152  \
02153   oqmlATOMTYPE at = aleft->type.type; \
02154  \
02155   if (at == oqmlATOM_INT) \
02156     *alist = new oqmlAtomList\
02157       (new oqmlAtom_int(OQML_ATOM_INTVAL(aleft) OP OQML_ATOM_INTVAL(aright))); \
02158  \
02159   else if (at == oqmlATOM_CHAR) \
02160     *alist = new oqmlAtomList\
02161       (new oqmlAtom_int(OQML_ATOM_CHARVAL(aleft) OP OQML_ATOM_CHARVAL(aright))); \
02162   else \
02163     return oqmlStatus::expected(this, "integer or character", aleft->type.getString()); \
02164 \
02165   OQL_DELETE(al_left); \
02166   OQL_DELETE(al_right); \
02167 \
02168   return oqmlSuccess; \
02169 } \
02170  \
02171 void oqml_x::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at) \
02172 { \
02173   *at = eval_type; \
02174 } \
02175  \
02176 oqmlBool oqml_x::isConstant() const \
02177 { \
02178   return OQMLBOOL(qleft->isConstant() && qright->isConstant()); \
02179 } \
02180  \
02181 std::string oqml_x::toString(void) const \
02182 { \
02183   return oqml_binop_string(qleft, qright, OPSTR, is_statement); \
02184 }
02185 
02186 #define OQML_BINOP(oqml_x, oqml_XX, OP, OPSTR, CHECK_FUN) \
02187 oqml_x::oqml_x(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqml_XX) \
02188 { \
02189   qleft = _qleft; \
02190   qright = _qright; \
02191 } \
02192  \
02193 oqml_x::~oqml_x() \
02194 { \
02195 } \
02196  \
02197 oqmlStatus *oqml_x::compile(Database *db, oqmlContext *ctx) \
02198 { \
02199   oqmlBool iscts; \
02200   oqmlStatus *s; \
02201   s = binopCompile(db, ctx, OPSTR, qleft, qright, eval_type, oqmlDoubleOK, iscts); \
02202  \
02203   if (s) \
02204     return s; \
02205  \
02206   if (isConstant() && !cst_list) \
02207    { \
02208       oqmlAtomList *al; \
02209       s = eval(db, ctx, &al); \
02210       if (s) return s; \
02211       cst_list = al->copy(); \
02212       if (isLocked()) \
02213          oqmlLock(cst_list, oqml_True); \
02214    } \
02215  \
02216   return oqmlSuccess; \
02217 } \
02218  \
02219 oqmlStatus *oqml_x::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *) \
02220 { \
02221   if (cst_list) \
02222     { \
02223       *alist = new oqmlAtomList(cst_list); \
02224       return oqmlSuccess; \
02225     } \
02226  \
02227   oqmlAtomList *al_left, *al_right; \
02228   oqmlStatus *s = binopEval(db, ctx, OPSTR, eval_type, qleft, qright, oqmlDoubleOK, &al_left, &al_right); \
02229  \
02230   if (s) \
02231     return s; \
02232  \
02233   oqmlAtom *aleft = al_left->first, *aright = al_right->first; \
02234  \
02235   if (CHECK_FUN) \
02236     { \
02237       s = ((oqml_check_fun)CHECK_FUN)(this, aleft, aright); \
02238       if (s) return s; \
02239     } \
02240  \
02241   oqmlATOMTYPE at = aleft->type.type; \
02242  \
02243   if (at == oqmlATOM_INT) \
02244     *alist = new oqmlAtomList \
02245       (new oqmlAtom_int(OQML_ATOM_INTVAL(aleft) OP OQML_ATOM_INTVAL(aright))); \
02246  \
02247   else if (at == oqmlATOM_CHAR) \
02248     *alist = new oqmlAtomList \
02249       (new oqmlAtom_int(OQML_ATOM_CHARVAL(aleft) OP OQML_ATOM_CHARVAL(aright))); \
02250   else if (at == oqmlATOM_DOUBLE) \
02251     *alist = new oqmlAtomList \
02252       (new oqmlAtom_double(OQML_ATOM_DBLVAL(aleft) OP OQML_ATOM_DBLVAL(aright))); \
02253   else \
02254     return oqmlStatus::expected(this, "integer, character or double", aleft->type.getString()); \
02255 \
02256   OQL_DELETE(al_left); \
02257   OQL_DELETE(al_right); \
02258 \
02259   return oqmlSuccess; \
02260 } \
02261  \
02262 void oqml_x::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at) \
02263 { \
02264   *at = eval_type; \
02265 } \
02266  \
02267 oqmlBool oqml_x::isConstant() const \
02268 { \
02269   return OQMLBOOL(qleft->isConstant() && qright->isConstant()); \
02270 } \
02271 std::string oqml_x::toString(void) const \
02272 { \
02273   if (qleft->getType() == oqmlINT)\
02274     return oqml_unop_string(qright, OPSTR, is_statement); \
02275   return oqml_binop_string(qleft, qright, OPSTR, is_statement); \
02276 }
02277 
02278 OQML_BINOP(oqmlMul, oqmlMUL, *, "*", 0)
02279 OQML_BINOP(oqmlDiv, oqmlDIV, /, "/", check_right_nonzero)
02280 
02281 OQML_INT_BINOP(oqmlMod, oqmlMOD, %, "%", check_right_nonzero)
02282 OQML_INT_BINOP(oqmlAAnd, oqmlAAND, &, "&", 0)
02283 OQML_INT_BINOP(oqmlAOr, oqmlAOR, |, "|", 0)
02284 OQML_INT_BINOP(oqmlXor, oqmlXOR, ^, "^", 0)
02285 OQML_INT_BINOP(oqmlShr, oqmlSHR, >>, ">>", 0)
02286 OQML_INT_BINOP(oqmlShl, oqmlSHL, <<, "<<", 0)
02287   }

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