oqlmth.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 #define protected public
00026 
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <assert.h>
00031 #include <dlfcn.h>
00032 
00033 #include "oql_p.h"
00034 
00035 //#define MTH_TRACE
00036 
00037 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00038 //
00039 // oqmlMethodCall methods
00040 //
00041 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00042 
00043 // -----------------------------------------------------------------------
00044 //
00045 // public instance method constructor
00046 //
00047 // -----------------------------------------------------------------------
00048 
00049 namespace eyedb {
00050 
00051 oqmlMethodCall::oqmlMethodCall(const char *_mthname, oqml_List *_list,
00052                                oqmlBool _noParenthesis) :
00053   oqmlNode(oqmlMTHCALL)
00054 {
00055   deleteList = oqml_False;
00056   init(0, _mthname, _list);
00057   noParenthesis = _noParenthesis;
00058   call = 0;
00059 }
00060 
00061 // -----------------------------------------------------------------------
00062 //
00063 // public class method constructor
00064 //
00065 // -----------------------------------------------------------------------
00066 
00067 oqmlMethodCall::oqmlMethodCall(const char *_clsname, const char *_mthname,
00068                                oqml_List *_list, oqmlNode *_call) :
00069   oqmlNode(oqmlMTHCALL)
00070 {
00071   deleteList = oqml_True;
00072   init(_clsname, _mthname, _list);
00073   noParenthesis = oqml_False;
00074   call = _call;
00075 }
00076 
00077 // -----------------------------------------------------------------------
00078 //
00079 // public isConstant() method -> returns false
00080 //
00081 // -----------------------------------------------------------------------
00082 
00083 oqmlBool oqmlMethodCall::isConstant() const
00084 {
00085   return oqml_False;
00086 }
00087 
00088 // -----------------------------------------------------------------------
00089 //
00090 // public compile method
00091 //
00092 // -----------------------------------------------------------------------
00093 
00094 oqmlStatus *oqmlMethodCall::compile(Database *db, oqmlContext *ctx)
00095 {
00096   oqmlStatus *s;
00097 
00098   if (clsname)
00099     cls = db->getSchema()->getClass(clsname);
00100 
00101   last.cls = 0;
00102   last.xmth = 0;
00103 
00104 #ifdef MTH_TRACE
00105   printf("compiling methodCall(%s, %d arguments)\n", mthname, list->cnt);
00106 #endif
00107 
00108   oqml_Link *l = list->first;
00109 
00110   while (l)
00111     {
00112       if (l->ql->getType() != oqmlIDENT)
00113         {
00114           s = l->ql->compile(db, ctx);
00115           if (s)
00116             return s;
00117         }
00118 
00119       l = l->next;
00120     }
00121 
00122   return oqmlSuccess;
00123 }
00124 
00125 #define TRS_PROLOGUE(X) \
00126   Bool isInTrs = True; \
00127   if (X) \
00128     { \
00129       if (!db) db = (Database *)(X)->getDatabase(); \
00130       if (!db->isInTransaction()) \
00131         { \
00132           Status xs = db->transactionBegin(); \
00133           if (xs) return new oqmlStatus(this, xs); \
00134           isInTrs = False; \
00135         } \
00136     }
00137 
00138 #define TRS_EPILOGUE(S) \
00139   if (!isInTrs) \
00140     { \
00141       if (S) {db->transactionAbort(); return (S);}\
00142       Status _s = db->transactionCommit(); \
00143       if (_s) return new oqmlStatus(this, _s); \
00144     }
00145 
00146 // -----------------------------------------------------------------------
00147 //
00148 // public eval method
00149 //
00150 // Algorithm:
00151 //  - eval the list and keep results in tmp_atom array
00152 //  - if the method has been resolved at compile time, check arguments
00153 //  - if the method has not been resolved at compile time, find method
00154 //    according to argument type
00155 //  - atomsToArgs
00156 //  - apply method
00157 //  - argsToAtom
00158 //
00159 // -----------------------------------------------------------------------
00160 
00161 oqmlStatus *oqmlMethodCall::eval(Database *db, oqmlContext *ctx,
00162                                  oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00163 {
00164   oqmlStatus *s;
00165 
00166 #ifdef MTH_TRACE
00167   printf("evaluate static method %s::%s\n", clsname, mthname);
00168 #endif
00169 
00170   *alist = new oqmlAtomList();
00171 
00172   s = evalList(db, ctx);
00173   if (s)
00174     return s;
00175 
00176   Method *xmth = 0;
00177 
00178   TRS_PROLOGUE(cls);
00179 
00180   if (mth)
00181     {
00182       s = checkArguments(db, ctx, mth);
00183       if (s) return s;
00184       xmth = mth;
00185     }
00186   else
00187     {
00188       s = resolveMethod(db, ctx, True, (Object *)0, xmth);
00189       if (s) return s;
00190     }
00191 
00192   TRS_EPILOGUE(s);
00193 
00194   if (xmth->getEx()->getLang() & C_LANG)
00195     s = applyC(db, ctx, xmth, alist);
00196   else 
00197     s = applyOQL(db, ctx, xmth, alist);
00198 
00199   return s;
00200 }
00201 
00202 // -----------------------------------------------------------------------
00203 //
00204 // public evalType() method
00205 //
00206 // -----------------------------------------------------------------------
00207 
00208 void oqmlMethodCall::evalType(Database *db, oqmlContext *ctx,
00209                               oqmlAtomType *at)
00210 {
00211   *at = eval_type;
00212 
00213   if (!mth || eval_type.type != oqmlATOM_UNKNOWN_TYPE)
00214     return;
00215 
00216   ArgType_Type odl_type = mth->getEx()->getSign()->getRettype()->getType();
00217 
00218   if (odl_type == OID_TYPE)
00219     at->type = oqmlATOM_OID;
00220   else if (odl_type == OBJ_TYPE)
00221     at->type = oqmlATOM_OBJ;
00222   else if (odl_type == INT16_TYPE ||
00223            odl_type == INT32_TYPE ||
00224            odl_type == INT64_TYPE)
00225     at->type = oqmlATOM_INT;
00226   else if ( odl_type == STRING_TYPE)
00227     at->type = oqmlATOM_STRING;
00228   else if (odl_type == CHAR_TYPE)
00229     at->type = oqmlATOM_CHAR;
00230   else if (odl_type == FLOAT_TYPE)
00231     at->type = oqmlATOM_DOUBLE;
00232 
00233   eval_type = *at;
00234 }
00235 
00236 // -----------------------------------------------------------------------
00237 //
00238 // public perform method
00239 //
00240 // -----------------------------------------------------------------------
00241 
00242 // 19/05/05: disconnected
00243 //#define STATIC_POLYMORPH
00244 
00245 oqmlStatus *
00246 oqmlMethodCall::perform(Database *db, oqmlContext *ctx,
00247                         Object *o, const Oid &oid, const Class *_cls,
00248                         oqmlAtomList **alist)
00249 {
00250   if (o->isRemoved())
00251     return new oqmlStatus(this, "object %s is removed", o->getOid().toString());
00252 
00253 #ifdef MTH_TRACE
00254   printf("trying to perform method call on %s class=[%p, %s] mth=%s, "
00255          "%d count\n", oid.toString(), _cls, _cls->getName(), mthname,
00256          list->cnt);
00257 #endif
00258 
00259 #ifdef STATIC_POLYMORPH
00260   const Class *xcls;
00261   if (o->asClass()) {
00262     _cls = o->asClass();
00263     xcls = _cls;
00264   }
00265 #endif
00266 
00267   cls = _cls;
00268   if (!cls->getDatabase())
00269     cls = db->getSchema()->getClass(cls->getName());
00270 
00271   oqmlStatus *s;
00272   s = evalList(db, ctx);
00273   if (s) return s;
00274 
00275   TRS_PROLOGUE(cls);
00276 
00277   Method *xmth = 0;
00278 #ifdef STATIC_POLYMORPH
00279   s = resolveMethod(db, ctx, (o->asClass() ? True: False), o, xmth);
00280 #else
00281   s = resolveMethod(db, ctx, False, o, xmth);
00282 #endif
00283   if (s) return s;
00284 
00285   TRS_EPILOGUE(s);
00286 
00287   if (xmth->getEx()->getLang() & C_LANG)
00288     s = applyC(db, ctx, xmth, alist, o, &oid);
00289   else
00290     s = applyOQL(db, ctx, xmth, alist, o, &oid);
00291 
00292   return s;
00293 }
00294 
00295 // -----------------------------------------------------------------------
00296 //
00297 // public destructor
00298 //
00299 // -----------------------------------------------------------------------
00300 
00301 oqmlMethodCall::~oqmlMethodCall()
00302 {
00303   free(clsname);
00304   free(mthname);
00305   free(atoms);
00306   free(tmp_atoms);
00307   if (deleteList)
00308     delete list;
00309 }
00310 
00311 // -----------------------------------------------------------------------
00312 //
00313 // private init() method: common initializer
00314 //
00315 // -----------------------------------------------------------------------
00316 
00317 void
00318 oqmlMethodCall::init(const char *_clsname, const char *_mthname,
00319                     oqml_List *_list)
00320 {
00321 #ifdef MTH_TRACE
00322   printf("oqmlMethodCall(%s, %s)\n", (_clsname ? _clsname : "<>"),
00323          _mthname);
00324 #endif
00325   mthname = strdup(_mthname);
00326   clsname = (_clsname ? strdup(_clsname) : 0);
00327   list = (_list ? _list : new oqml_List());
00328   if (!_list) deleteList = oqml_True;
00329   mth = 0;
00330   cls = 0;
00331   is_compiled = oqml_False;
00332   eval_type.type = oqmlATOM_UNKNOWN_TYPE;
00333   atoms     = (oqmlAtom **)calloc(sizeof(oqmlAtom *), list->cnt);
00334   tmp_atoms = (oqmlAtom **)calloc(sizeof(oqmlAtom *), list->cnt);
00335   last.cls = 0;
00336   last.xmth = 0;
00337 }
00338 
00339 oqmlStatus *oqmlMethodCall::checkStaticMethod()
00340 {
00341   if (!(mth->getEx()->getLoc() & STATIC_EXEC))
00342     return new oqmlStatus(this, "method '%s::%s' is not a static method",
00343                          cls->getName(), mthname);
00344 
00345   if (mth->getEx()->getSign()->getNargs() != list->cnt)
00346     return new oqmlStatus(this, "method '%s::%s': %d argument(s) expected, "
00347                           "got %d",
00348                           cls->getName(), mthname,
00349                           mth->getEx()->getSign()->getNargs(),
00350                           list->cnt);
00351   return oqmlSuccess;
00352 }
00353 
00354 // -----------------------------------------------------------------------
00355 //
00356 // private noMethod()
00357 //
00358 // -----------------------------------------------------------------------
00359 
00360 oqmlStatus *
00361 oqmlMethodCall::noMethod(Bool isStatic, oqmlContext *ctx,
00362                          const Method **mths, int mth_cnt)
00363 {
00364   std::string s;
00365 
00366   if (call)
00367     {
00368       s = std::string("unknown function '") + mthname + "'";
00369       return new oqmlStatus(call, s.c_str());
00370     }
00371 
00372   if (noParenthesis)
00373     s = std::string("neither attribute ") + mthname + ", nor";
00374   else
00375     s = "no";
00376   
00377   s += std::string(" ") + (isStatic ? "class" : "instance") +
00378     " method " + mthname + "(" +  getSignature(ctx) + ") in class " +
00379     cls->getName();
00380   
00381   if (mth_cnt)
00382     {
00383       s += std::string(". Candidate") + (mth_cnt > 1 ? "s are: " : " is: ");
00384       for (int i = 0; i < mth_cnt; i++)
00385         {
00386           if (i)
00387             s += "; ";
00388           s += mths[i]->getPrototype();
00389         }
00390     }
00391 
00392   return new oqmlStatus(this, s.c_str());
00393 }
00394 
00395 #if 0
00396 // -----------------------------------------------------------------------
00397 //
00398 // private findStaticMethod()
00399 //
00400 // -----------------------------------------------------------------------
00401 
00402 oqmlStatus *oqmlMethodCall::findStaticMethod(Database *db, oqmlContext *ctx)
00403 {
00404   cls = db->getSchema()->getClass(clsname);
00405   if (!cls)
00406     return new oqmlStatus(this, "'%s' is not a class name", clsname);
00407 
00408   unsigned int cnt;
00409   Status xs = cls->getMethodCount(mthname, cnt);
00410   if (xs) return new oqmlStatus(this, xs);
00411 
00412   if (!cnt)
00413     return noMethod(True, ctx);
00414 
00415   if (cnt > 1)
00416     {
00417       // will be resolved in eval method
00418       return oqmlSuccess;
00419     }
00420 
00421   xs = cls->getMethod(mthname, (const Method *&)mth);
00422   if (xs) return new oqmlStatus(this, xs);
00423 
00424   return checkStaticMethod();
00425 }
00426 #endif
00427 
00428 
00429 // -----------------------------------------------------------------------
00430 //
00431 // private evalList method
00432 //
00433 // -----------------------------------------------------------------------
00434 
00435 oqmlStatus *
00436 oqmlMethodCall::evalList(Database *db, oqmlContext *ctx)
00437 {
00438   oqmlStatus *s;
00439   oqml_Link *l = list->first;
00440 
00441 #ifdef MTH_TRACE
00442   printf("methodCall(%s, %s)->evalList()\n", cls->getName(), mthname);
00443 #endif
00444 
00445   for (int i = 0; i < list->cnt; i++, l = l->next)
00446     {
00447       /*
00448       if (l->ql->getType() == oqmlIDENT)
00449         {
00450           tmp_atoms[i] = new oqmlAtom_ident(((oqmlIdent *)l->ql)->getName());
00451           continue;
00452         }
00453         */
00454 
00455       oqmlAtomList *al = 0;
00456       s = l->ql->eval(db, ctx, &al, 0, 0);
00457       if (s)
00458         return s;
00459 
00460       if (al->cnt > 1)
00461         return new oqmlStatus(this, "method '%s::%s': argument #%d "
00462                              "cannot be a flattened list",
00463                              cls->getName(), mthname, i+1);
00464 
00465       if (al->cnt == 0)
00466         return new oqmlStatus(this, "method '%s::%s': argument #%d is undefined",
00467                               (cls ? cls->getName() : ""), mthname, i+1);
00468       tmp_atoms[i] = al->first;
00469 #ifdef SYNC_GARB
00470       if (al && !al->refcnt) {
00471         al->first = 0;
00472         OQL_DELETE(al);
00473       }
00474 #endif
00475     }
00476 
00477   return oqmlSuccess;
00478 }
00479 
00480 // -----------------------------------------------------------------------
00481 //
00482 // private compareAtomTypes() method
00483 //
00484 // -----------------------------------------------------------------------
00485 
00486 oqmlBool oqmlMethodCall::compareAtomTypes()
00487 {
00488   for (int i = 0; i < list->cnt; i++)
00489     if (!atoms[i] || atoms[i]->type.type != tmp_atoms[i]->type.type)
00490       return oqml_False;
00491 
00492   return oqml_True;
00493 }
00494 
00495 // -----------------------------------------------------------------------
00496 //
00497 // private compareType() method
00498 //
00499 // -----------------------------------------------------------------------
00500 
00501 oqmlMethodCall::Match
00502 oqmlMethodCall::compareType(oqmlContext *ctx, int n, oqmlAtom *x,
00503                             int odl_type, Bool strict)
00504 {
00505   oqmlATOMTYPE _type = x->type.type;
00506 
00507   if (_type == oqmlATOM_IDENT)
00508     {
00509       oqmlAtomType at;
00510       if (!ctx->getSymbol(OQML_ATOM_IDENTVAL(x), &at, &x))
00511         return (strict ? no_match : match);
00512       _type = at.type;
00513     }
00514 
00515   odl_type = (ArgType_Type)(odl_type & ~INOUT_ARG_TYPE);
00516 
00517   switch(_type)
00518     {
00519     case oqmlATOM_OID:
00520     case oqmlATOM_OBJ:
00521       if (odl_type == OBJ_TYPE || odl_type == OID_TYPE)
00522         return exact_match;
00523       return no_match;
00524 
00525     case oqmlATOM_INT:
00526       if (odl_type == INT16_TYPE ||
00527           odl_type == INT32_TYPE ||
00528           odl_type == INT64_TYPE)
00529         return exact_match;
00530       return no_match;
00531 
00532     case oqmlATOM_CHAR:
00533       if (odl_type == CHAR_TYPE)
00534         return exact_match;
00535       return no_match;
00536 
00537     case oqmlATOM_DOUBLE:
00538       if (odl_type == FLOAT_TYPE)
00539         return exact_match;
00540       return no_match;
00541 
00542     case oqmlATOM_STRING:
00543       if (odl_type == STRING_TYPE)
00544         return exact_match;
00545       return no_match;
00546 
00547     case oqmlATOM_LIST:
00548     case oqmlATOM_ARRAY:
00549       if (odl_type & ARRAY_TYPE)
00550         {
00551           oqmlAtom *xx = OQML_ATOM_COLLVAL(x)->first;
00552           if (!xx)
00553             return match;
00554           Match mm = exact_match;
00555           while (xx)
00556             {
00557               Match m = compareType(ctx, n, xx, odl_type&~ARRAY_TYPE,
00558                                     strict);
00559               if (m == no_match)
00560                 return no_match;
00561               if (m == match)
00562                 mm = match;
00563               xx = xx->next;
00564             }
00565           return mm;
00566         }
00567       return no_match;
00568 
00569     case oqmlATOM_NIL:
00570     case oqmlATOM_NULL:
00571     case oqmlATOM_BOOL:
00572       return no_match;
00573 
00574     default:
00575       return no_match;
00576     }
00577   
00578   return no_match;
00579 }
00580 
00581 // -----------------------------------------------------------------------
00582 //
00583 // private typeMismatch()
00584 //
00585 // -----------------------------------------------------------------------
00586 
00587 oqmlStatus *
00588 oqmlMethodCall::typeMismatch(const Signature *sign, oqmlAtomType &at, int n)
00589 {
00590   return new oqmlStatus(this, "method '%s::%s', argument #%d: %s expected, "
00591                        "got %s", cls->getName(), mthname, n+1,
00592                        Argument::getArgTypeStr(sign->getTypes(n)),
00593                        at.getString());
00594 }
00595 
00596 oqmlStatus *
00597 oqmlMethodCall::typeMismatch(ArgType *type, Object *o, int n)
00598 {
00599   return new oqmlStatus(this, "method '%s::%s', argument #%d: %s expected, "
00600                        "got %s", cls->getName(), mthname, n+1,
00601                         type->getClname().c_str(), o->getClass()->getName());
00602 }
00603 
00604 // -----------------------------------------------------------------------
00605 //
00606 // private checkArguments(Database *)
00607 //
00608 // -----------------------------------------------------------------------
00609 
00610 oqmlStatus *
00611 oqmlMethodCall::checkArguments(Database *db, oqmlContext *ctx,
00612                                const Method *xmth, Match *m)
00613 {
00614   const Signature *sign = xmth->getEx()->getSign();
00615 
00616   int nargs = sign->getNargs();
00617   if (m) *m = exact_match;
00618   for (int i = 0; i < nargs; i++)
00619     {
00620       ArgType_Type _type = sign->getTypes(i)->getType();
00621       if (_type & OUT_ARG_TYPE)
00622         {
00623           if (tmp_atoms[i]->type.type != oqmlATOM_IDENT)
00624             {
00625               if (!m)
00626                 return new oqmlStatus(this, "method '%s::%s': "
00627                                       "out argument #%d must be set "
00628                                       "to a symbol", cls->getName(),
00629                                       mthname, i+1);
00630               *m = no_match;
00631               return oqmlSuccess;
00632             }
00633         }
00634 
00635       Match mm = compareType(ctx, i, tmp_atoms[i], _type,
00636                              IDBBOOL(_type & IN_ARG_TYPE));
00637       if (mm == no_match)
00638         {
00639           if (!m)
00640             return typeMismatch(sign, tmp_atoms[i]->type, i);
00641           *m = no_match;
00642           return oqmlSuccess;
00643         }
00644 
00645       if (m && mm == match)
00646         *m = match;
00647     }
00648   
00649   memcpy(atoms, tmp_atoms, list->cnt * sizeof(oqmlAtom *));
00650   return oqmlSuccess;
00651 }
00652 
00653 #define SET(ARG, TYPE, L) \
00654 (ARG)->set((TYPE *)calloc(sizeof(TYPE)*(L)->cnt, 1), (L)->cnt, \
00655                           Argument::AutoFullGarbage)
00656 
00657 // -----------------------------------------------------------------------
00658 //
00659 // private buildArgArray()
00660 //
00661 // -----------------------------------------------------------------------
00662 
00663 oqmlStatus *
00664 oqmlMethodCall::buildArgArray(Argument *arg, oqmlAtomList *_list,
00665                               ArgType_Type odl_type, int n)
00666 {
00667   switch(odl_type)
00668     {
00669     case INT16_TYPE:
00670       SET(arg, eyedblib::int16, _list);
00671       break;
00672 
00673     case INT32_TYPE:
00674       SET(arg, eyedblib::int32, _list);
00675       break;
00676 
00677     case INT64_TYPE:
00678       SET(arg, eyedblib::int64, _list);
00679       break;
00680 
00681     case STRING_TYPE:
00682       SET(arg, char *, _list);
00683       break;
00684 
00685     case CHAR_TYPE:
00686       SET(arg, char, _list);
00687       break;
00688 
00689     case FLOAT_TYPE:
00690       SET(arg, double, _list);
00691       break;
00692 
00693     case OID_TYPE:
00694       SET(arg, Oid, _list);
00695       break;
00696 
00697     case OBJ_TYPE:
00698       SET(arg, Object *, _list);
00699       break;
00700 
00701     case VOID_TYPE:
00702       break;
00703 
00704     default:
00705       return new oqmlStatus(this, "method '%s::%s', argument #%d: odl type '%p' "
00706                            "is not supported",
00707                            cls->getName(), mthname,
00708                            n+1, odl_type);
00709     }
00710 
00711   return oqmlSuccess;
00712 }
00713 
00714 // -----------------------------------------------------------------------
00715 //
00716 // private fillArgArray()
00717 //
00718 // -----------------------------------------------------------------------
00719 
00720 oqmlStatus *
00721 oqmlMethodCall::fillArgArray(Signature *sign,
00722                             Argument *arg, Argument tmp,
00723                             ArgType_Type odl_type, int j)
00724 {
00725   switch(odl_type)
00726     {
00727     case INT16_TYPE:
00728       arg->u.arr_i16.i[j] = *tmp.getInteger16();
00729       break;
00730 
00731     case INT32_TYPE:
00732       arg->u.arr_i32.i[j] = *tmp.getInteger32();
00733       break;
00734 
00735     case INT64_TYPE:
00736       arg->u.arr_i64.i[j] = *tmp.getInteger64();
00737       break;
00738 
00739     case STRING_TYPE:
00740       arg->u.arr_s.s[j] = strdup(tmp.getString());
00741       break;
00742 
00743     case CHAR_TYPE:
00744       arg->u.arr_c.c[j] = *tmp.getChar();
00745       break;
00746 
00747     case FLOAT_TYPE:
00748       arg->u.arr_d.d[j] = *tmp.getFloat();
00749       break;
00750 
00751     case OID_TYPE:
00752       arg->u.arr_oid.oid[j] = *tmp.getOid();
00753       break;
00754 
00755     case OBJ_TYPE:
00756       arg->u.arr_o.o[j] = tmp.getObject();
00757       break;
00758 
00759     case VOID_TYPE:
00760       break;
00761 
00762     default:
00763       return new oqmlStatus(this, "method '%s::%s', argument #%d: odl type '%s' "
00764                            "is not supported",
00765                            cls->getName(), mthname,
00766                            j+1,
00767                            Argument::getArgTypeStr(sign->getTypes(j)));
00768     }
00769 
00770   return oqmlSuccess;
00771 }
00772 
00773 // -----------------------------------------------------------------------
00774 //
00775 // private makeArg()
00776 //
00777 // -----------------------------------------------------------------------
00778 
00779 oqmlStatus *
00780 oqmlMethodCall::makeArg(Argument &tmp, ArgType_Type odl_type,
00781                         const Argument *arg, int j)
00782 {
00783   switch(odl_type)
00784     {
00785     case INT16_TYPE:
00786       tmp.set(arg->u.arr_i16.i[j]);
00787       break;
00788 
00789     case INT32_TYPE:
00790       tmp.set(arg->u.arr_i32.i[j]);
00791       break;
00792 
00793     case INT64_TYPE:
00794       tmp.set(arg->u.arr_i64.i[j]);
00795       break;
00796 
00797     case STRING_TYPE:
00798       tmp.set(arg->u.arr_s.s[j]);
00799       break;
00800 
00801     case CHAR_TYPE:
00802       tmp.set(arg->u.arr_c.c[j]);
00803       break;
00804 
00805     case FLOAT_TYPE:
00806       tmp.set(arg->u.arr_d.d[j]);
00807       break;
00808 
00809     case OID_TYPE:
00810       tmp.set(arg->u.arr_oid.oid[j]);
00811       break;
00812 
00813     case OBJ_TYPE:
00814       tmp.set(arg->u.arr_o.o[j]);
00815       break;
00816 
00817     default:
00818       assert(0);
00819       break;
00820     }
00821 
00822   return oqmlSuccess;
00823 }
00824 
00825 // -----------------------------------------------------------------------
00826 //
00827 // private getArgCount()
00828 //
00829 // -----------------------------------------------------------------------
00830 
00831 unsigned int
00832 oqmlMethodCall::getArgCount(const Argument *arg, ArgType_Type odl_type)
00833 {
00834   switch(odl_type)
00835     {
00836     case INT16_TYPE:
00837       return arg->u.arr_i16.cnt;
00838 
00839     case INT32_TYPE:
00840       return arg->u.arr_i32.cnt;
00841 
00842     case INT64_TYPE:
00843       return arg->u.arr_i64.cnt;
00844 
00845     case STRING_TYPE:
00846       return arg->u.arr_s.cnt;
00847 
00848     case CHAR_TYPE:
00849       return arg->u.arr_c.cnt;
00850 
00851     case FLOAT_TYPE:
00852       return arg->u.arr_d.cnt;
00853 
00854     case OID_TYPE:
00855       return arg->u.arr_oid.cnt;
00856 
00857     case OBJ_TYPE:
00858       return arg->u.arr_o.cnt;
00859 
00860     default:
00861       assert(0);
00862       return 0;
00863     }
00864 
00865   return 0;
00866 }
00867 
00868 // -----------------------------------------------------------------------
00869 //
00870 // private getSignature()
00871 //
00872 // -----------------------------------------------------------------------
00873 
00874 const char *
00875 oqmlMethodCall::getSignature(oqmlContext *ctx)
00876 {
00877   static char sign[256];
00878   *sign = 0;
00879 
00880   for (int i = 0; i < list->cnt; i++)
00881     {
00882       if (i)
00883         strcat(sign, ", ");
00884       if (tmp_atoms[i]->type.type == oqmlATOM_IDENT)
00885         {
00886           oqmlAtomType at;
00887           if (ctx->getSymbol(OQML_ATOM_IDENTVAL(tmp_atoms[i]), &at))
00888             strcat(sign, at.getString());
00889           else
00890             strcat(sign, "??");
00891         }
00892       else
00893         strcat(sign, tmp_atoms[i]->type.getString());
00894     }
00895 
00896   return sign;
00897 }
00898 
00899 static oqmlStatus *
00900 ambiguous(oqmlNode *node, Method *m1, Method **m2, int m2_cnt)
00901 {
00902   std::string s = std::string("cannot resolve ambiguity "
00903                           "between methods '") +  m1->getPrototype() + "'";
00904   for (int i = 0; i < m2_cnt; i++)
00905     s += std::string(" and '") + m2[i]->getPrototype() + "'";
00906 
00907   return new oqmlStatus(node, s.c_str());
00908 }
00909 
00910 static bool
00911 isParent(const Class *parent, Object *o)
00912 {
00913   if (!o || !o->asClass()) return false;
00914 
00915   const Class *cls = o->asClass()->getClass();
00916 #ifdef MTH_TRACE
00917   printf("isParent: %s %s vs. %s\n", o->asClass()->getName(), cls->getName(),
00918          parent->getName());
00919 #endif
00920   while (cls) {
00921     if (parent->compare(cls)) return true;
00922     cls = cls->getParent();
00923   }
00924 
00925   return false;
00926 }
00927 
00928 // -----------------------------------------------------------------------
00929 //
00930 // private resolveMethod()
00931 //
00932 // -----------------------------------------------------------------------
00933 
00934 oqmlStatus *oqmlMethodCall::resolveMethod(Database *db, oqmlContext *ctx,
00935                                           Bool isStatic, Object *o,
00936                                           Method *&xmth)
00937 {
00938   if (last.cls == cls && last.isStatic == isStatic && compareAtomTypes()) {
00939     xmth = last.xmth;
00940     return oqmlSuccess;
00941   }
00942 
00943   if (!cls) {
00944     if (clsname)
00945       return new oqmlStatus(this, "'%s' is not a class name", clsname);
00946     return new oqmlStatus(this, "unknown class");
00947   }
00948 
00949   Status xs = const_cast<Class *>(cls)->wholeComplete();
00950   if (xs) return new oqmlStatus(this, xs);
00951 
00952   char *rmthname = strrchr(mthname, ':');
00953   const Class *scopeClass = 0;
00954 
00955   if (rmthname) {
00956     char *scope = strdup(mthname);
00957     rmthname++;
00958     *(strrchr(scope, ':')-1) = 0;
00959     if (!(scopeClass = db->getSchema()->getClass(scope))) {
00960       oqmlStatus *s = new oqmlStatus(this, "invalid class '%s'", scope);
00961       free(scope);
00962       return s;
00963     }
00964 
00965     free(scope);
00966   }
00967   else
00968     rmthname = mthname;
00969 
00970   unsigned int cnt;
00971   xs = cls->getMethodCount(rmthname, cnt);
00972   if (xs) return new oqmlStatus(this, xs);
00973 
00974   if (!cnt)
00975     return noMethod(isStatic, ctx);
00976 
00977 #ifdef MTH_TRACE
00978   printf("resolving method '%s' [isStatic %d] [class %s]\n",
00979          rmthname, isStatic, cls->getName());
00980 #endif
00981   unsigned int mth_cnt;
00982   const Method **mths = cls->getMethods(mth_cnt);
00983   const Method **cand_mths = (const Method **)
00984     malloc(mth_cnt * sizeof(Method *));
00985   Method **xmth_1 = (Method **)malloc(sizeof(Method*)*mth_cnt);
00986 
00987   int xmth_1_cnt = 0;
00988   xmth = 0;
00989   int cand_mth_cnt = 0;
00990   oqmlStatus *s;
00991   Match xm = no_match;
00992 
00993   for (int i = 0; i < mth_cnt; i++) {
00994     const Method *mx = mths[i];
00995     const Executable *ex = mx->getEx();
00996 #ifdef MTH_TRACE
00997     printf("%s_method %s [%s]\n",
00998            (ex->isStaticExec() ? "class" : "instance"),
00999            ex->getExname(),
01000            mx->getClassOwner()->getName());
01001 #endif
01002     if (!strcmp(ex->getExname().c_str(), rmthname) &&
01003         ((ex->isStaticExec() && isStatic) ||
01004          (!ex->isStaticExec() && !isStatic) ||
01005          (isStatic && isParent(mx->getClassOwner(), o)))) {
01006       /*
01007         !(ex->getLoc() & idbSTATIC_EXEC) && isStatic &&
01008         (!strcmp(mx->getClassOwner()->getName(), "object") ||
01009         !strcmp(mx->getClassOwner()->getName(), "class"))))) {
01010       */
01011 
01012         if (scopeClass && !mx->getClassOwner()->compare(scopeClass))
01013           continue;
01014 
01015 #ifdef MTH_TRACE
01016         printf("chosen!\n");
01017 #endif
01018         cand_mths[cand_mth_cnt++] = mx;
01019         if (ex->getSign()->getNargs() != list->cnt)
01020           continue;
01021     }
01022     else
01023       continue;
01024 
01025     Match m;
01026     if (s = checkArguments(db, ctx, mx, &m))
01027       return s;
01028     if (m == no_match)
01029       continue;
01030     
01031     if (!xmth) {
01032       xmth = (Method *)mx;
01033       xm = m;
01034       continue;
01035     }
01036 
01037     if (xm == exact_match && m == exact_match) {
01038       if (xmth->getClassOwner()->compare(mx->getClassOwner())) {
01039         oqmlStatus *s = ambiguous(this, xmth, (Method **)&mx, 1);
01040         free(mths);
01041         free(cand_mths);
01042         return s;
01043       }
01044 
01045       Bool is;
01046       Status s = xmth->getClassOwner()->isSuperClassOf
01047         (mx->getClassOwner(), &is);
01048       if (s) return new oqmlStatus(this, s);
01049       if (is)
01050         xmth = (Method *)mx;
01051     }
01052     
01053     if (xm == exact_match)
01054       continue;
01055     
01056     if (m != exact_match)
01057       xmth_1[xmth_1_cnt++] = xmth;
01058 
01059     xmth = (Method *)mx;
01060     xm = m;
01061   }
01062 
01063   if (xmth)
01064     s = xmth_1_cnt ? ambiguous(this, xmth, xmth_1, xmth_1_cnt) : oqmlSuccess;
01065   else
01066     s = noMethod(isStatic, ctx, cand_mths, cand_mth_cnt);
01067 
01068   free(mths);
01069   free(cand_mths);
01070   free(xmth_1);
01071 
01072   if (!s && xmth)
01073     {
01074       last.cls = cls;
01075       last.isStatic = isStatic;
01076       last.xmth = xmth;
01077     }
01078 
01079   return s;
01080 }
01081 
01082 // -----------------------------------------------------------------------
01083 //
01084 // private atomToArg()
01085 //
01086 // -----------------------------------------------------------------------
01087 
01088 oqmlStatus *oqmlMethodCall::atomToArg(Database *db, oqmlContext *ctx,
01089                                       Signature *sign,
01090                                       oqmlAtom *a,
01091                                       ArgType *type,
01092                                       ArgType_Type odl_type,
01093                                       Argument *arg, int i)
01094 {
01095   oqmlAtomType at;
01096   oqmlStatus *s;
01097 
01098   oqmlATOMTYPE _type = a->type.type;
01099 
01100   if (_type == oqmlATOM_IDENT)
01101     {
01102       const char *ident = OQML_ATOM_IDENTVAL(a);
01103       if (!ctx->getSymbol(ident, &at, &a))
01104         return new oqmlStatus(this, "method '%s::%s', argument #%d: "
01105                               "symbol '%s' is undefined",
01106                               cls->getName(), mthname,
01107                              i+1, ident);
01108       _type = at.type;
01109     }
01110   else
01111     at.type = _type;
01112   
01113   switch(_type)
01114     {
01115     case oqmlATOM_OID:
01116       if (odl_type == OID_TYPE)
01117         arg->set(OQML_ATOM_OIDVAL(a));
01118       else if (odl_type == OBJ_TYPE)
01119         {
01120           Object *o;
01121           Oid oid_o = OQML_ATOM_OIDVAL(a);
01122           if (oid_o.isValid()) {
01123             Status is = db->loadObject(oid_o, o);
01124             if (is) return new oqmlStatus(this, is);
01125             if (strcmp(type->getClname().c_str(), o->getClass()->getName()))
01126               return typeMismatch(type, o, i);
01127           }
01128           else
01129             o = 0;
01130 
01131           arg->set(o);
01132         }
01133       else
01134         return typeMismatch(sign, at, i);
01135 
01136       break;
01137 
01138     case oqmlATOM_OBJ:
01139       if (odl_type == OBJ_TYPE)
01140         {
01141           OQL_CHECK_OBJ(a);
01142           Object *o = OQML_ATOM_OBJVAL(a);
01143           if (o) {
01144             o->incrRefCount();
01145             if (strcmp(type->getClname().c_str(), o->getClass()->getName()))
01146               return typeMismatch(type, o, i);
01147             arg->set(o);
01148           }
01149           else
01150             arg->set(Oid::nullOid);
01151         }
01152       else if (odl_type == OID_TYPE)
01153         {
01154           OQL_CHECK_OBJ(a);
01155           Object *o = OQML_ATOM_OBJVAL(a);
01156           if (o)
01157             arg->set(o->getOid());
01158           else
01159             arg->set(Oid::nullOid);
01160         }
01161       else
01162         return typeMismatch(sign, at, i);
01163       break;
01164 
01165     case oqmlATOM_INT:
01166       {
01167         eyedblib::int64 ii = ((oqmlAtom_int *)a)->i;
01168         if (odl_type == INT16_TYPE)
01169           arg->set((eyedblib::int16)ii);
01170         else if (odl_type == INT32_TYPE)
01171           arg->set((eyedblib::int32)ii);
01172         else if (odl_type == INT64_TYPE)
01173           arg->set(ii);
01174         else
01175           return typeMismatch(sign, at, i);
01176         break;
01177       }
01178 
01179     case oqmlATOM_CHAR:
01180       if (odl_type == CHAR_TYPE)
01181         arg->set(((oqmlAtom_char *)a)->c);
01182       else
01183         return typeMismatch(sign, at, i);
01184       break;
01185 
01186     case oqmlATOM_DOUBLE:
01187       if (odl_type == FLOAT_TYPE)
01188         arg->set(((oqmlAtom_double *)a)->d);
01189       else
01190         return typeMismatch(sign, at, i);
01191       break;
01192 
01193     case oqmlATOM_STRING:
01194       if (odl_type == STRING_TYPE)
01195         arg->set(OQML_ATOM_STRVAL(a));
01196       else
01197         return typeMismatch(sign, at, i);
01198 
01199       break;
01200 
01201     case oqmlATOM_LIST:
01202     case oqmlATOM_ARRAY:
01203       if (!(odl_type & ARRAY_TYPE))
01204         return typeMismatch(sign, at, i);
01205       {
01206         oqmlAtomList *_list = OQML_ATOM_COLLVAL(a);
01207         odl_type = (ArgType_Type)(odl_type & ~ARRAY_TYPE);
01208         s = buildArgArray(arg, _list, odl_type, i);
01209         if (s)
01210           return s;
01211         oqmlAtom *a = _list->first;
01212         Argument tmp;
01213         for (int j = 0; j < _list->cnt; j++, a = a->next)
01214           {
01215             s = atomToArg(db, ctx, sign, a, type, odl_type, &tmp, i);
01216             if (s)
01217               return s;
01218 
01219             s = fillArgArray(sign, arg, tmp, odl_type, j);
01220             if (s)
01221               return s;
01222           }
01223 
01224         return oqmlSuccess;
01225       }
01226 
01227     default:
01228       return typeMismatch(sign, at, i);
01229     }
01230   
01231   return oqmlSuccess;
01232 }
01233 
01234 // -----------------------------------------------------------------------
01235 //
01236 // private atomsToArgs()
01237 //
01238 // -----------------------------------------------------------------------
01239 
01240 oqmlStatus *oqmlMethodCall::atomsToArgs(Database *db, oqmlContext *ctx,
01241                                       Method *xmth, ArgArray &arr)
01242 {
01243   oqmlStatus *s;
01244   Signature *sign = xmth->getEx()->getSign();
01245   for (int i = 0; i < list->cnt; i++)
01246     {
01247       ArgType *type = sign->getTypes(i);
01248       ArgType_Type odl_type = type->getType();
01249 
01250       if (!(odl_type & IN_ARG_TYPE))
01251         continue;
01252 
01253       odl_type = (ArgType_Type)(odl_type & ~INOUT_ARG_TYPE);
01254 
01255       s = atomToArg(db, ctx, sign, tmp_atoms[i], type, odl_type, arr[i], i);
01256       if (s)
01257         return s;
01258     }
01259   
01260   return oqmlSuccess;
01261 }
01262 
01263 // -----------------------------------------------------------------------
01264 //
01265 // private argToAtom()
01266 //
01267 // -----------------------------------------------------------------------
01268 
01269 oqmlStatus *oqmlMethodCall::argToAtom(const Argument *arg, int n,
01270                                       oqmlAtomType &at, oqmlAtom *&a)
01271 {
01272   oqmlStatus *s;
01273 
01274   at.cls = 0;
01275   at.comp = oqml_False;
01276 
01277   ArgType_Type odl_type = arg->getType()->getType();
01278   if (odl_type & ARRAY_TYPE)
01279     {
01280       odl_type = (ArgType_Type)(odl_type & ~ARRAY_TYPE);
01281       at.type = oqmlATOM_LIST;
01282       int cnt = getArgCount(arg, odl_type);
01283       oqmlAtomList *_list = new oqmlAtomList();
01284       a = new oqmlAtom_list(_list);
01285       for (int j = 0; j < cnt; j++)
01286         {
01287           oqmlAtomType xat;
01288           oqmlAtom *x;
01289           Argument tmp;
01290           s = makeArg(tmp, odl_type, arg, j);
01291           if (s)
01292             return s;
01293           s = argToAtom(&tmp, j, xat, x);
01294           if (s)
01295             return s;
01296           _list->append(x);
01297         }
01298 
01299       return oqmlSuccess;
01300     }
01301 
01302   switch(odl_type)
01303     {
01304     case OID_TYPE:
01305       at.type = oqmlATOM_OID;
01306       a = new oqmlAtom_oid(*arg->getOid());
01307       break;
01308 
01309     case OBJ_TYPE:
01310       at.type = oqmlATOM_OBJ;
01311       a = oqmlObjectManager::registerObject((Object *)arg->getObject());
01312       if (arg->getObject())
01313         (const_cast <Object *>(arg->getObject()))->incrRefCount();
01314       break;
01315 
01316     case INT16_TYPE:
01317     case INT32_TYPE:
01318     case INT64_TYPE:
01319       at.type = oqmlATOM_INT;
01320       a = new oqmlAtom_int(arg->getInteger());
01321       break;
01322 
01323     case STRING_TYPE:
01324       {
01325         at.type = oqmlATOM_STRING;
01326         const char *s = arg->getString();
01327         a = new oqmlAtom_string(s ? s : "");
01328       }
01329     break;
01330 
01331     case CHAR_TYPE:
01332       at.type = oqmlATOM_CHAR;
01333       a = new oqmlAtom_char(*arg->getChar());
01334       break;
01335 
01336     case FLOAT_TYPE:
01337       at.type = oqmlATOM_DOUBLE;
01338       a = new oqmlAtom_double(*arg->getFloat());
01339       break;
01340 
01341     case VOID_TYPE:
01342       break;
01343 
01344     default:
01345       return new oqmlStatus(this, "method '%s::%s', argument #%d: "
01346                             "odl type '%s' is not supported",
01347                            cls->getName(), mthname,
01348                            n+1,
01349                            Argument::getArgTypeStr(arg->getType()));
01350     }
01351 
01352   return oqmlSuccess;
01353 }
01354   
01355 // -----------------------------------------------------------------------
01356 //
01357 // private argsToAtoms()
01358 //
01359 // -----------------------------------------------------------------------
01360 
01361 oqmlStatus *oqmlMethodCall::argsToAtoms(Database *db,  oqmlContext *ctx,
01362                                       Method *xmth,
01363                                       const ArgArray &arr,
01364                                       const Argument &retarg,
01365                                       oqmlAtom *&retatom)
01366 {
01367   oqmlStatus *s;
01368   Signature *sign = xmth->getEx()->getSign();
01369   oqmlAtomType at;
01370 
01371   for (int i = 0; i < list->cnt; i++)
01372     {
01373       const Argument *arg = arr[i];
01374       ArgType_Type odl_type = sign->getTypes(i)->getType();
01375       if (!(odl_type & OUT_ARG_TYPE))
01376         continue;
01377       oqmlAtom *a;
01378       s = argToAtom(arg, i, at, a);
01379       if (s)
01380         return s;
01381 
01382       const char *ident = OQML_ATOM_IDENTVAL(tmp_atoms[i]);
01383       oqmlBool global;
01384       if (!ctx->getSymbol(ident, 0, 0, &global) || global ||
01385           !strncmp(ident, oqml_global_scope, oqml_global_scope_len))
01386         s = ctx->setSymbol(ident, &at, a, oqml_True);
01387       else
01388         s = ctx->setSymbol(ident, &at, a, oqml_False);
01389 
01390       if (s) return s;
01391     }
01392 
01393   return argToAtom(&retarg, list->cnt, at, retatom);
01394 }
01395 
01396 // -----------------------------------------------------------------------
01397 //
01398 // private applyC()
01399 //
01400 // -----------------------------------------------------------------------
01401 
01402 oqmlStatus *
01403 oqmlMethodCall::applyC(Database *db, oqmlContext *ctx,
01404                        Method *xmth,
01405                        oqmlAtomList **alist, Object *o, const Oid *oid)
01406 {
01407   oqmlStatus *s;
01408   ArgArray arr(list->cnt, Argument::AutoFullGarbage);
01409   Argument retarg;
01410 
01411 #ifdef MTH_TRACE
01412   printf("applyC methodCall(%s, %d arguments)\n", mthname, list->cnt);
01413 #endif
01414 
01415   s = atomsToArgs(db, ctx, xmth, arr);
01416   if (s)
01417     return s;
01418 
01419   Status xs;
01420   if (oid && !o) {
01421     xs = db->loadObject(*oid, o);
01422     if (xs) return new oqmlStatus(this, xs);
01423   }
01424 
01425   void *x = db->setUserData(IDB_LOCAL_CALL);
01426 
01427   xs = xmth->applyTo(db, o, arr, retarg, False);
01428 
01429   db->setUserData(x);
01430 
01431   if (xs)
01432     return new oqmlStatus(this, xs);
01433 
01434   oqmlAtom *retatom = 0;
01435   s = argsToAtoms(db, ctx, xmth, arr, retarg, retatom);
01436 
01437   if (!s && retatom)
01438     (*alist)->append(retatom);
01439 
01440   return s;
01441 }
01442 
01443 // -----------------------------------------------------------------------
01444 //
01445 // private applyOQL()
01446 //
01447 // -----------------------------------------------------------------------
01448 
01449 // introduced the 19/06/01
01450 #define NEW_THIS
01451 
01452 oqmlStatus *
01453 oqmlMethodCall::applyOQL(Database *db, oqmlContext *ctx,
01454                          Method *xmth,
01455                          oqmlAtomList **alist, Object *o, const Oid *oid)
01456 {
01457   static const char thisvar[] = "this";
01458 #ifndef NEW_THIS
01459   static const char pthisvar[] = "pthis";
01460 #endif
01461 
01462   // added the 3/07/01
01463   int select_ctx_cnt = ctx->setSelectContextCount(0);
01464 
01465   oqmlStatus *s = oqmlSuccess;
01466   oqmlStatus *s1, *s2;
01467   BEMethod_OQL *oqlmth = xmth->asBEMethod_OQL();
01468 
01469   if (!oqlmth)
01470     return new oqmlStatus(this, "internal error #243");
01471 
01472   Status is = oqlmth->runtimeInit();
01473   if (is) return new oqmlStatus(this, is);
01474 
01475   if (!oqlmth->entry)
01476     {
01477       oqmlAtomList *al;
01478       s = oqml_realize(db, oqlmth->fullBody, &al);
01479       if (s) return s;
01480       if (!ctx->getFunction(oqlmth->funcname,
01481                             (oqmlFunctionEntry **)&oqlmth->entry))
01482         return new oqmlStatus(this, "internal error #244");
01483     }
01484 
01485 #ifdef NEW_THIS
01486   pointer_int_t idx;
01487   if (o && oqmlObjectManager::isRegistered(o, idx)) {
01488     oqmlAtom_obj * obj_x;
01489     obj_x = new oqmlAtom_obj(o, idx, o->getClass());
01490     s = ctx->pushSymbol(thisvar, &obj_x->type, obj_x);
01491   }
01492   else {
01493     if (!oid && o)
01494       oid = &o->getOid();
01495 
01496     if (!oid)
01497       return new oqmlStatus(this, "invalid null object");
01498 
01499     oqmlAtom_oid *oid_x;
01500     oid_x = new oqmlAtom_oid(*oid);
01501     s = ctx->pushSymbol(thisvar, &oid_x->type, oid_x);
01502     if (s) return s;
01503   }
01504 #else
01505 
01506   oqmlAtom_oid * oid_x;
01507   if (oid)
01508     oid_x = new oqmlAtom_oid(*oid);
01509   else
01510     oid_x = new oqmlAtom_oid(Oid::nullOid);
01511 
01512   s = ctx->pushSymbol(pthisvar, &oid_x->type, oid_x);
01513   if (s) return s;
01514 
01515   oqmlAtom_obj * obj_x;
01516   pointer_int_t idx;
01517 
01518   if (o && oqmlObjectManager::isRegistered(o, idx))
01519     obj_x = new oqmlAtom_obj(o, idx, o->getClass());
01520   else
01521     obj_x = new oqmlAtom_obj(0, 0);
01522 
01523   s = ctx->pushSymbol(thisvar, &obj_x->type, obj_x);
01524   if (s) return s;
01525 #endif
01526 
01527   int n;
01528   oqml_Link *l = list->first;
01529   for (n = 0; n < oqlmth->param_cnt; n++)
01530     {
01531       oqmlAtomList *al;
01532       s1 = l->ql->eval(db, ctx, &al);
01533       s2 = ctx->pushSymbol(oqlmth->varnames[n], &al->first->type,
01534                            al->first);
01535       if (s1) s = s1;
01536       if (s2) s = s2;
01537 
01538       l = l->next;
01539     }
01540 
01541   if (!s)
01542     {
01543       oqmlAtomList *al;
01544       s = oqmlCall::realizeCall(db, ctx, (oqmlFunctionEntry *)oqlmth->entry,
01545                                 &al);
01546       if (!s)
01547         {
01548           (*alist)->first = al->first;
01549           (*alist)->cnt = al->cnt;
01550         }
01551     }
01552 
01553   for (n = 0; n < oqlmth->param_cnt; n++)
01554     {
01555       s1 = ctx->popSymbol(oqlmth->varnames[n]);
01556       if (s1 && !s) s = s1;
01557     }
01558 
01559   s1 = ctx->popSymbol(thisvar);
01560   if (s1 && !s) s = s1;
01561 
01562 #ifndef NEW_THIS
01563   s1 = ctx->popSymbol(pthisvar);
01564   if (s1 && !s) s = s1;
01565 #endif
01566 
01567   // added the 3/07/01
01568   ctx->setSelectContextCount(select_ctx_cnt);
01569 
01570   return s;
01571 }
01572 
01573 extern int oqmlLevel;
01574 
01575 #define OQML_AUTO(P, C, D) \
01576   struct P##__ { \
01577     P##__ () {(C);} \
01578     ~P##__() {(D);} \
01579   } P##_
01580 
01581 oqmlStatus *
01582 oqmlMethodCall::applyTrigger(Database *db, Trigger *trig,
01583                              Object *o, const Oid *oid)
01584 {
01585   OQML_AUTO(, oqmlLevel++, --oqmlLevel);
01586 
01587   static const char thisvar[] = "this";
01588   static const char pthisvar[] = "pthis";
01589 
01590   oqmlStatus *s = oqmlSuccess;
01591   oqmlStatus *s1, *s2;
01592 
01593   oqmlContext ctx;
01594 
01595   if (!trig->entry)
01596     {
01597       oqmlAtomList *al;
01598       s = oqml_realize(db, trig->fullBody, &al);
01599       if (s) return s;
01600       if (!ctx.getFunction(trig->funcname,
01601                             (oqmlFunctionEntry **)&trig->entry))
01602         return new oqmlStatus("internal error #244");
01603     }
01604 
01605   oqmlAtom_oid * oid_x;
01606   if (oid)
01607     oid_x = new oqmlAtom_oid(*oid);
01608   else
01609     oid_x = new oqmlAtom_oid(Oid::nullOid);
01610 
01611   s = ctx.pushSymbol(pthisvar, &oid_x->type, oid_x);
01612   if (s) return s;
01613 
01614   oqmlAtom *obj_x = oqmlObjectManager::registerObject(o);
01615 
01616   s = ctx.pushSymbol(thisvar, &obj_x->type, obj_x);
01617   if (s) return s;
01618 
01619   oqmlAtomList *al;
01620   s = oqmlCall::realizeCall(db, &ctx, (oqmlFunctionEntry *)trig->entry,
01621                             &al);
01622   s1 = ctx.popSymbol(thisvar);
01623   if (s1 && !s) s = s1;
01624 
01625   s1 = ctx.popSymbol(pthisvar);
01626   if (s1 && !s) s = s1;
01627 
01628   s1 = oqmlObjectManager::unregisterObject(0, o);
01629   if (s1 && !s) s = s1;
01630 
01631   return s;
01632 }
01633 
01634 oqmlBool
01635 oqmlMethodCall::hasIdent(const char *_ident)
01636 {
01637   return list->hasIdent(_ident);
01638 }
01639 
01640 void
01641 oqmlMethodCall::lock()
01642 {
01643   oqmlNode::lock();
01644   if (call) call->lock(); // added the 17/05/01
01645   if (list) list->lock();
01646 }
01647 
01648 void
01649 oqmlMethodCall::unlock()
01650 {
01651   oqmlNode::unlock();
01652   if (call) call->unlock(); // added the 17/05/01
01653   if (list) list->unlock();
01654 }
01655 
01656 std::string
01657 oqmlMethodCall::toString(void) const
01658 {
01659   std::string s = (clsname ? std::string(clsname) + "::" : std::string("")) + mthname + "(";
01660   oqml_Link *l = list->first;
01661 
01662   for (int i = 0; l; i++)
01663     {
01664       if (i) s += ",";
01665       s += l->ql->toString();
01666       l = l->next;
01667     }
01668 
01669   s += std::string(")") + oqml_isstat();
01670   return s;
01671 }
01672 
01673 }

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