00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #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
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
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
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
00080
00081
00082
00083 oqmlBool oqmlMethodCall::isConstant() const
00084 {
00085 return oqml_False;
00086 }
00087
00088
00089
00090
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
00149
00150
00151
00152
00153
00154
00155
00156
00157
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
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
00239
00240
00241
00242
00243
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
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
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
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
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
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
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
00449
00450
00451
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
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
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
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
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
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
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
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
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
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
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
01008
01009
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
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
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
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
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
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
01446
01447
01448
01449
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
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
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();
01645 if (list) list->lock();
01646 }
01647
01648 void
01649 oqmlMethodCall::unlock()
01650 {
01651 oqmlNode::unlock();
01652 if (call) call->unlock();
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 }