Executable.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 <assert.h>
00026 #include <dlfcn.h>
00027 #include <fcntl.h>
00028 #include <unistd.h>
00029 #include "eyedb_p.h"
00030 
00031 namespace eyedb {
00032 
00033   static eyedbsm::Oid nulloid;
00034 
00035   Status
00036   eyedb_CHECKObjRefType(Database *db, Argument &arg, const char *which)
00037   {
00038     if (!arg.u.o->isModify())
00039       {
00040         arg.set(arg.u.o->getOid(), db); // requalification
00041         return Success;
00042       }
00043 
00044     if (!arg.u.o->getClass()->isFlatStructure())
00045       return Exception::make(IDB_ERROR,
00046                              "argument %s : object '%s' of class '%s' "
00047                              "is not consistent with database "
00048                              ": cannot be transmitted",
00049                              which, arg.u.o->getOid().getString(),
00050                              arg.u.o->getClass()->getName());
00051     return Success;
00052   }
00053 
00054   Status
00055   eyedb_CHECKObjType(Database *db, Argument &arg, const char *which)
00056   {
00057     const ArgType *t = arg.type;
00058 
00059     if (t->getType() == ARRAY_TYPE)
00060       return eyedb_CHECKObjArrayType(db, arg, which);
00061 
00062     if (t->getType() != OBJ_TYPE)
00063       return Success;
00064 
00065     if (!arg.u.o)
00066       return Success;
00067 
00068     if (arg.u.o->getOid().isValid())
00069       return eyedb_CHECKObjRefType(db, arg, which);
00070 
00071     if (!arg.u.o->getClass()->isFlatStructure() &&
00072         !(db->getOpenFlag() & _DBOpenLocal) &&
00073         !db->isBackEnd()) // the two && conditions added the 12/06/01
00074       return Exception::make(IDB_ERROR,
00075                              "argument %s : non persistent object of "
00076                              "class '%s' is not a flat structure : "
00077                              "cannot be transmitted",
00078                              which, arg.u.o->getClass()->getName());
00079     return Success;
00080   }
00081 
00082   Status
00083   eyedb_CHECKObjArrayType(Database *db, Argument &arg, const char *which)
00084   {
00085     int cnt = arg.u.array->getCount();
00086 
00087     for (int i = 0; i < cnt; i++)
00088       {
00089         Status s = eyedb_CHECKObjType(db, *((*arg.u.array)[i]), which);
00090         if (s) return s;
00091       }
00092 
00093     return Success;
00094   }
00095 
00096   Status
00097   eyedb_CHECKArgument(Database *db, ArgType t1, Argument &arg,
00098                       const char *typname, const char *name, const char *which,
00099                       int inout)
00100   {
00101     int type = t1.getType();
00102 
00103     if (!inout || (type & inout)) {
00104       ArgType t2 = *arg.type;
00105 
00106       t1.setType((ArgType_Type)(type & ~(INOUT_ARG_TYPE)), False);
00107 
00108       if (!t1.getType()) // means ANY
00109         return Success;
00110 
00111       Status s = eyedb_CHECKObjType(db, arg, which);
00112       if (s) return s;
00113 
00114       if (t1 != t2) {
00115         if (t1.getType() == OBJ_TYPE && t2.getType() == OBJ_TYPE) {
00116           if (!arg.u.o) // means nil objects
00117             return Success;
00118           const Class *m1, *m2;
00119           m1 = db->getSchema()->getClass(t1.getClname().c_str());
00120           m2 = db->getSchema()->getClass(t2.getClname().c_str());
00121           /*
00122             printf("check obj argument: m1 '%s' m2 '%s'\n",
00123             t1.getClname(), t2.getClname());
00124           */
00125           Bool is;
00126           if (m1 && m2 && !m1->isSuperClassOf(m2, &is) && is)
00127             return Success;
00128         }
00129 
00130         return Exception::make(IDB_EXECUTABLE_ERROR,
00131                                "%s %s, %s argument %s mismatch, "
00132                                "expected %s, got %s",
00133                                typname, name, 
00134                                (inout ? ((inout & IN_ARG_TYPE) ?
00135                                          "input" : "output") : "return"),
00136                                which,
00137                                Argument::getArgTypeStr(&t1),
00138                                Argument::getArgTypeStr(&t2));
00139       }
00140     }
00141   
00142     return Success;
00143   }
00144 
00145   Status
00146   eyedb_CHECKArguments(Database *db, const Signature *sign,
00147                        ArgArray &array, const char *typname,
00148                        const char *name, int inout)
00149   {
00150     int cnt = sign->getNargs();
00151     if (cnt != array.getCount())
00152       return Exception::make(IDB_EXECUTABLE_ERROR,
00153                              "%s %s, %d arguments expected, got %d",
00154                              typname, name, cnt,
00155                              array.getCount());
00156 
00157     for (int i = 0; i < cnt; i++) {
00158       char which[12];
00159       sprintf(which, "#%d", i+1);
00160 
00161       Status s = eyedb_CHECKArgument(db, *sign->getTypes(i), *array[i],
00162                                      typname, name, which, inout);
00163       if (s) return s;
00164     }
00165 
00166     return Success;
00167   }
00168 
00169   // ---------------------------------------------------------------------------
00170   //
00171   // Executable Methods
00172   //
00173   // ---------------------------------------------------------------------------
00174 
00175   const char *
00176   Executable::getSOTag()
00177   {
00178     static std::string s = std::string("-") + getVersion();
00179     return s.c_str();
00180   }
00181 
00182   /*
00183     const char *
00184     Executable::getSOTag(const Compiler *comp)
00185     {
00186     static std::string s;
00187 
00188     s = std::string("-") + eyedb::getVersion() +
00189     (comp ? comp->getSoTag() : eyedb::getDefaultCompiler()->getSoTag());
00190     return s;
00191     }
00192   */
00193 
00194   const char *
00195   Executable::makeExtRef(const char *extref)
00196   {
00197     static std::string s;
00198 
00199     int len = strlen(extref);
00200     if (len > 3 && !strcmp(&extref[len-3], ".so"))
00201       return extref;
00202 
00203     //  s = std::string(extref) + getSOTag(comp) + ".so";
00204     s = std::string(extref) + getSOTag() + ".so";
00205 
00206     return s.c_str();
00207   }
00208 
00209   static const char *
00210   get_next_path(const char *sopath, int &idx)
00211   {
00212     static char path[512];
00213 
00214     const char *s = strchr(sopath+idx, ':');
00215     if (!s)
00216       {
00217         s = sopath+idx;
00218         idx += strlen(sopath+idx);
00219         return s;
00220       }
00221 
00222     int len = s-sopath-idx;
00223     strncpy(path, sopath+idx, len);
00224     path[len] = 0;
00225     idx += strlen(path)+1;
00226     return path;
00227   }
00228 
00229   void *
00230   Executable::_dlopen(const char *extref)
00231   {
00232     const char *s = makeExtRef(extref);
00233     const char *sopath = ServerConfig::getSValue("sopath");
00234 
00235     if (!sopath)
00236       return (void *)0;
00237 
00238     const char *x;
00239     int idx = 0;
00240     while (*(x = get_next_path(sopath, idx)))
00241       {
00242         void *dl = dlopen((std::string(x) + "/" + s).c_str(), RTLD_LAZY);
00243         if (dl)
00244           return dl;
00245       }
00246 
00247     return (void *)0;
00248   }
00249 
00250   const char *
00251   Executable::getSOFile(const char *extref)
00252   {
00253     static std::string file;
00254     //  const char *s = makeExtRef(extref, comp);
00255     const char *s = makeExtRef(extref);
00256     const char *sopath = ServerConfig::getSValue("sopath");
00257 
00258     if (!sopath)
00259       return (const char *)0;
00260 
00261     const char *x;
00262     int idx = 0;
00263     while (*(x = get_next_path(sopath, idx)))
00264       {
00265         file = std::string(x) + "/" + s;
00266         int fd = open(file.c_str(), O_RDONLY);
00267         if (fd >= 0)
00268           {
00269             close(fd);
00270             return file.c_str();
00271           }
00272       }
00273 
00274     return (const char *)0;
00275   }
00276 
00277   Status
00278   Executable::checkRealize(const char *extref, const char *intname,
00279                            void **pdl, void **pcsym)
00280   {
00281     if (!extref)
00282       return Exception::make(IDB_EXECUTABLE_ERROR,
00283                              "invalid null external reference for"
00284                              "function '%s'", intname);
00285     if (*pdl)
00286       dlclose(*pdl);
00287 
00288     *pdl = Executable::_dlopen(extref);
00289 
00290     if (!*pdl)
00291       {
00292         std::string s = std::string("method `") + intname + "' check failed : " +
00293           dlerror();
00294         return Exception::make(IDB_EXECUTABLE_ERROR, s);
00295       }
00296 
00297     *pcsym = dlsym(*pdl, intname);
00298 
00299     if (!*pcsym)
00300       {
00301         dlclose(*pdl);
00302         *pdl = 0;
00303         return Exception::make(IDB_EXECUTABLE_ERROR,
00304                                "symbol '%s' not found in external reference '%s'",
00305                                intname, extref);
00306       }
00307 
00308     return Success;
00309   }
00310 
00311   // ---------------------------------------------------------------------------
00312   //
00313   // const char *
00314   // Executable::makeInternalName(const char *exname,
00315   //                                 const Signature *sign,
00316   //                               Bool isClassMethod, const char *clname)
00317   //
00318   // Builds the internal name from the executable name, the signature and
00319   // the optionnal class name
00320   //
00321   // ---------------------------------------------------------------------------
00322 
00323   const char *
00324   Executable::makeInternalName(const char *exname, const Signature *sign,
00325                                Bool isClassMethod,
00326                                const char *clname)
00327   {
00328     static char intname[512];
00329 
00330     strcpy(intname, "method_");
00331 
00332     if (isClassMethod)
00333       strcat(intname, "static");
00334 
00335     if (sign)
00336       strcat(intname, Argument::getArgTypeStr(sign->getRettype(), False));
00337 
00338     int n = (sign ? sign->getNargs() : 0);
00339 
00340     strcat(intname, "_");
00341     strcat(intname, exname);
00342 
00343     if (clname)
00344       {
00345         strcat(intname, "_");
00346         strcat(intname, clname);
00347       }
00348 
00349     for (int i = 0; i < n; i++)
00350       {
00351         strcat(intname, "_");
00352         strcat(intname, Argument::getArgTypeStr(sign->getTypes(i), False));
00353       }
00354 
00355     return intname;
00356   }
00357 
00358   int Executable::isStaticExec() const
00359   {
00360     return (getLoc() & STATIC_EXEC) ? 1 : 0;
00361   }
00362 
00363   void Executable::initExec(const char *exname,
00364                             ExecutableLang lang,
00365                             Bool isSystem,
00366                             ExecutableLocalisation loc,
00367                             Signature *sign,
00368                             Class *_class)
00369   {
00370     setExname(exname);
00371     setLang((ExecutableLang)(lang | (isSystem ? SYSTEM_EXEC : 0)),
00372             False);
00373     setLoc(loc, False);
00374     if (sign)
00375       *getSign() = *sign;
00376     const char *name = makeInternalName
00377       (exname, (sign ? getSign() : 0),
00378        ((loc & STATIC_EXEC) ? True : False),
00379        //     (_class ? _class->getName() : 0));
00380        // changed the 19/05/99
00381        (_class ? _class->getAliasName() : 0));
00382     setIntname(name);
00383   }
00384 
00385   void Executable::userInitialize()
00386   {
00387     dl = (void *)0;
00388   }
00389 
00390   void Executable::userCopy(const Object &)
00391   {
00392     userInitialize();
00393   }
00394 
00395   Status Executable::checkRealize(const char *extref, const char *mcname,
00396                                   void **pcsym)
00397   {
00398     const char *intname = makeInternalName
00399       (getExname().c_str(), getSign(),
00400        ((getLoc()&STATIC_EXEC) ? True : False), mcname);
00401 
00402     return checkRealize(extref, intname, &dl, pcsym);
00403   }
00404 
00405   Status Executable::execCheck()
00406   {
00407     return Success;
00408   }
00409 
00410   // ---------------------------------------------------------------------------
00411   //
00412   // Method Methods
00413   //
00414   // ---------------------------------------------------------------------------
00415 
00416   Status Method::execCheck()
00417   {
00418     return Success;
00419   }
00420 
00421   Status Method::realize(const RecMode *rcm)
00422   {
00423     if (!db)
00424       return Exception::make(IDB_ERROR, "no database associated with object");
00425 
00426     if (!oid.isValid()) {
00427       OQL q(db, "select method.ex.intname = \"%s\"", getEx()->getIntname().c_str());
00428 
00429       ObjectArray obj_arr(true);
00430       Status s = q.execute(obj_arr);
00431 
00432       if (obj_arr.getCount()) {
00433         //obj_arr[0]->release();
00434         return Exception::make(IDB_UNIQUE_CONSTRAINT_ERROR,
00435                                "method '%s::%s' already exists in"
00436                                " database '%s'",
00437                                getClassOwner()->getName(),
00438                                getEx()->getIntname().c_str(),
00439                                db->getName());
00440       }
00441     }
00442 
00443     return ClassComponent::realize(rcm);
00444   }
00445 
00446   Status Method::remove(const RecMode *rcm)
00447   {
00448     return ClassComponent::remove(rcm);
00449   }
00450 
00451   Status Method::check(Class *cl) const
00452   {
00453     return Success;
00454   }
00455 
00456   int Method::getInd() const
00457   {
00458     return Class::Method_C;
00459   }
00460 
00461   const char *
00462   Method::getPrototype(Bool scope) const
00463   {
00464     return getEx()->_getPrototype(getClassOwner(), scope);
00465   }
00466 
00467   Bool Method::isInherit() const
00468   {
00469     return True;
00470   }
00471 
00472   const char *
00473   Executable::_getPrototype(const Class *_class,
00474                             Bool scope) const
00475   {
00476     static std::string proto;
00477 
00478     Bool istrs;
00479     if (db && !db->isInTransaction())
00480       {
00481         db->transactionBegin();
00482         istrs = True;
00483       }
00484     else
00485       istrs = False;    
00486 
00487     //proto.reset();
00488     proto = "";
00489 
00490     const Signature *sign = getSign();
00491 
00492     ArgType rettype = *sign->getRettype();
00493     rettype.setType((ArgType_Type)(rettype.getType() & ~INOUT_ARG_TYPE),
00494                     False);
00495     //  proto.append(Argument::getArgTypeStr(&rettype));
00496     proto += Argument::getArgTypeStr(&rettype);
00497 
00498     char tok[256];
00499     if (_class && scope)
00500       sprintf(tok, " %s::%s(", _class->getName(), getExname().c_str());
00501     else
00502       sprintf(tok, " %s(", getExname().c_str());
00503 
00504     //  proto.append(tok);
00505     proto += tok;
00506 
00507     int n = sign->getNargs();
00508     for (int i = 0; i < n; i++)
00509       {
00510         sprintf(tok, "%s%s", (i ? ", " : ""),
00511                 Argument::getArgTypeStr(sign->getTypes(i)));
00512         //proto.append(tok);
00513         proto += tok;
00514       }
00515 
00516     //proto.append(")");
00517     proto += ")";
00518 
00519     if (istrs)
00520       db->transactionCommit();
00521 
00522     return proto.c_str();
00523   }
00524 
00525   extern void print_oqlexec(FILE *fd, const char *body);
00526 
00527   Status
00528   Method::m_trace(FILE *fd, int indent, unsigned int flags,
00529                   const RecMode* rcm) const
00530   {
00531     Status s = Success;
00532     Bool istrs;
00533     if (db && !db->isInTransaction())
00534       {
00535         db->transactionBegin();
00536         istrs = True;
00537       }
00538     else
00539       istrs = False;    
00540 
00541     const Executable *ex = getEx();
00542     const Signature *sign = ex->getSign();
00543     const Class *_class = getClassOwner();
00544 
00545     ArgType t = *sign->getRettype();
00546     t.setType((ArgType_Type)(t.getType() & ~OUT_ARG_TYPE), False);
00547     fprintf(fd, "%s_method <%s> %s ",
00548             (ex->isStaticExec() ? "class" : "instance"),
00549             (asFEMethod_C() ? "client" : "server"),
00550             Argument::getArgTypeStr(&t));
00551 
00552     if (flags & NoScope)
00553       fprintf(fd, "%s(", ex->getExname().c_str());
00554     else
00555       fprintf(fd, "%s::%s(", (_class ? _class->getName() : "??"),
00556               ex->getExname().c_str());
00557 
00558     int is_clang = (ex->getLang() & C_LANG);
00559     int n = sign->getNargs();
00560     for (int i = 0; i < n; i++)
00561       {
00562         fprintf(fd, "%s%s",
00563                 (i ? ", " : ""), Argument::getArgTypeStr(sign->getTypes(i)));
00564         if (!is_clang && (flags & ExecBodyTrace))
00565           fprintf(fd, " x%d", i);
00566       }
00567 
00568     fprintf(fd, ")");
00569 
00570     if (flags & ExecBodyTrace)
00571       {
00572         if (is_clang)
00573           fprintf(fd, " C++(\"%s\")", ex->getExtrefBody().c_str());
00574         else
00575           {
00576             ((Method *)this)->asBEMethod_OQL()->runtimeInit();
00577             if (asBEMethod_OQL()->body)
00578               print_oqlexec(fd, asBEMethod_OQL()->body);
00579           }
00580       }
00581 
00582     if (rcm->getType() == RecMode_FullRecurs)
00583       {
00584         fprintf(fd, " ");
00585         s = ObjectPeer::trace_realize(this, fd, indent + INDENT_INC, flags, rcm);
00586       }
00587 
00588     if ((flags & CompOidTrace) == CompOidTrace)
00589       fprintf(fd, " %s", oid.getString());
00590 
00591     if (istrs)
00592       db->transactionCommit();
00593 
00594     return s;
00595   }
00596 
00597   Status Method::applyTo(Database *_db, Object *o,
00598                          ArgArray &array, Argument &retarg,
00599                          Bool checkArgs)
00600   {
00601     return Success;
00602   }
00603 
00604   Status Method::get(Database *db, Class *_class,
00605                      const char *exname,
00606                      const Signature *sign, Bool isClassMethod,
00607                      Method* &mth)
00608   {
00609     const char *intname = Executable::makeInternalName
00610       //    (exname, sign, isClassMethod, _class->getName());
00611       // changed the 19/5/99
00612       (exname, sign, isClassMethod, _class->getAliasName());
00613 
00614     mth = 0;
00615 
00616     const LinkedList *mth_list = _class->getCompList(Class::Method_C);
00617     if (!mth_list || !mth_list->getCount())
00618       return Success;
00619 
00620     //  Method **pmth = new Method*[mth_list->getCount()];
00621     Method **pmth = (Method **)malloc(sizeof(Method *) *
00622                                       mth_list->getCount());
00623     int mth_cnt = 0;
00624     LinkedListCursor *c = new LinkedListCursor(mth_list);
00625     Method *tmth;
00626 
00627     while (mth_list->getNextObject(c, (void *&)tmth))
00628       {
00629         Executable *ex = tmth->getEx();
00630         if (!strcmp(ex->getExname().c_str(), exname) && *ex->getSign() == *sign)
00631           pmth[mth_cnt++] = tmth;
00632       }
00633 
00634     mth_list->endScan(c);
00635 
00636     if (mth_cnt == 1)
00637       mth = pmth[0];
00638     else if (mth_cnt > 1)
00639       {
00640         Class *cl = _class;
00641         int carryon = 1;
00642         while (cl && carryon)
00643           {
00644             for (int i = 0; i < mth_cnt; i++)
00645               if (pmth[i]->getClassOwner()->compare(cl))
00646                 {
00647                   mth = pmth[i];
00648                   carryon = 0;
00649                   break;
00650                 }
00651             cl = cl->getParent();
00652           }
00653       }
00654 
00655     free(pmth);
00656 
00657     return Success;
00658   }
00659 
00660   //
00661   // Signature utilities
00662   //
00663 
00664 #define check_symbol(C) \
00665 (((C) >= 'a' && (C) <= 'z') || ((C) >= 'A' && (C) <= 'Z') || (C) == '_' ||\
00666  (C) >= '0' && (C) <= '9')
00667 
00668   static const char *
00669   getSpaceRid(const char *s, unsigned int len)
00670   {
00671     static char *mem;
00672     static int mem_len;
00673 
00674     if (strlen(s) > mem_len)
00675       {
00676         mem_len = strlen(s);
00677         mem = (char *)malloc(mem_len + 1);
00678       }
00679 
00680     char *p = mem;
00681     char c;
00682     unsigned int l = 0;
00683 
00684     if (!len)
00685       len = ~0;
00686 
00687     while ((c = *s) && l < len)
00688       {
00689         if (check_symbol(c) || c == '*' || c == '[' || c == ']')
00690           *p++ = *s;
00691         s++;
00692         l++;
00693       }
00694 
00695     *p = 0;
00696     return mem;
00697   }
00698 
00699   static char *
00700   getReturnType(const char *s, const char *& p)
00701   {
00702     p = s;
00703     char c;
00704     int state = 0;
00705 
00706     while (c = *p)
00707       {
00708         if (c != ' ' && c != '\t')
00709           break;
00710         p++;
00711       }
00712 
00713     while (c = *p)
00714       {
00715         if (state && check_symbol(c))
00716           {
00717             int len = p-s;
00718             return strdup(getSpaceRid(s, p-s));
00719           }
00720 
00721         if (c == ' ' || c == '\t' || c == '*' || c == ']')
00722           state = 1;
00723           
00724         p++;
00725       }
00726 
00727     return 0;
00728   }
00729   
00730   static char *
00731   getExecName(const char *s, const char *& p)
00732   {
00733     const char *q = p;
00734     char *name = 0;
00735     char c;
00736 
00737     while (c = *p)
00738       {
00739         if (c == '(')
00740           {
00741             name = strdup(getSpaceRid(q, p-q));
00742             break;
00743           }
00744 
00745         if (!check_symbol(c))
00746           return 0;
00747         p++;
00748       }
00749 
00750     if (!name)
00751       return 0;
00752 
00753     return name;
00754   }
00755 
00756   struct Arg {
00757     int inout;
00758     char *arg;
00759 
00760     Arg() {
00761       inout = 0;
00762       arg = NULL;
00763     }
00764 
00765     void set(int _inout, const char *_arg) {
00766       inout = _inout;
00767       arg = strdup(_arg);
00768     }
00769 
00770     ~Arg() {
00771       free(arg);
00772     }
00773   };
00774 
00775   static int
00776   getInOut(const char *t)
00777   {
00778     if (!strcasecmp(t, "in"))
00779       return IN_ARG_TYPE;
00780 
00781     if (!strcasecmp(t, "out"))
00782       return OUT_ARG_TYPE;
00783 
00784     if (!strcasecmp(t, "inout"))
00785       return INOUT_ARG_TYPE;    
00786 
00787     return 0;
00788   }
00789 
00790   static int
00791   getArgTypes(const char *s, const char *& p, Arg args[], int &nargs,
00792               const char *&str)
00793   {
00794     static const char missinout[] =
00795       "missing IN, OUT or INOUT keyword(s) in signature";
00796 
00797     int carryon = 1;
00798     char c;
00799     nargs = 0;
00800     p++;
00801     str = "";
00802 
00803     for (nargs = 0; carryon; )
00804       {
00805         int state = 0;
00806         const char *q = p;
00807         int inout = 0;
00808         while (c = *p)
00809           {
00810             if (c == ',')
00811               {
00812                 args[nargs].set(inout, getSpaceRid(q, p-q));
00813 
00814                 if (!inout)
00815                   {
00816                     str = missinout;
00817                     return 0;
00818                   }
00819 
00820                 if (*args[nargs].arg)
00821                   nargs++;
00822                 else
00823                   return 0;
00824                 p++;
00825                 break;
00826               }
00827 
00828             if (c == ')')
00829               {
00830                 args[nargs].set(inout, getSpaceRid(q, p-q));
00831 
00832                 if (!inout && !*args[nargs].arg)
00833                   return 1;
00834 
00835                 if (!inout)
00836                   {
00837                     str = missinout;
00838                     return 0;
00839                   }
00840 
00841                 if (*args[nargs].arg)
00842                   nargs++;
00843                 else
00844                   return 0;
00845 
00846                 p++;
00847                 carryon = 0;
00848                 break;
00849               }
00850 
00851             if (c == ' ' || c == '\t')
00852               {
00853                 if (state == 1)
00854                   {
00855                     if (!(inout = getInOut(getSpaceRid(q, p-q))))
00856                       {
00857                         str = missinout;
00858                         return 0;
00859                       }
00860 
00861                     state = 2;
00862                     q = p;
00863                   }
00864               }
00865             else if (!state)
00866               state = 1;
00867 
00868             p++;
00869           }
00870 
00871         if (!c)
00872           break;
00873       }
00874 
00875     while (c = *p)
00876       {
00877         if (c != ' ' && c != '\t')
00878           return 0;
00879         p++;
00880       }
00881     return 1;
00882   }
00883 
00884   Status
00885   Method::getSignature(Database *db, Class *cls, 
00886                        const char *s, Signature *&sign, char *&name)
00887   {
00888     char *rettype;
00889     int nargs;
00890     Arg args[64];
00891     const char *ctx = 0;
00892     sign = NULL;
00893 
00894     if (!(rettype = getReturnType(s, ctx)))
00895       return Exception::make
00896         (IDB_ERROR, "invalid signature syntax: invalid return type");
00897 
00898     if (!(name = getExecName(s, ctx))) {
00899       free(rettype);
00900       return Exception::make
00901         (IDB_ERROR, "invalid signature syntax: invalid method name");
00902     }
00903   
00904     const char *str;
00905     if (!getArgTypes(s, ctx, args, nargs, str)) {
00906       free(rettype);
00907       free(name);
00908       return Exception::make(IDB_ERROR, "invalid signature syntax: %s", str);
00909     }
00910     
00911     sign = new Signature(db);
00912     Schema *m = db->getSchema();
00913     ArgType *type = ArgType::make(m, rettype);
00914 
00915     free(rettype);
00916 
00917     if (type) {
00918       ArgType *t = sign->getRettype();
00919       t->setDatabase(db);
00920       t->setType((ArgType_Type)(type->getType() | OUT_ARG_TYPE),
00921                  False);
00922       if (type->getClname().c_str())
00923         t->setClname(type->getClname().c_str());
00924       type->release();
00925     }
00926     else
00927       return Exception::make(IDB_ERROR,
00928                              "invalid signature syntax: invalid return type");
00929 
00930     sign->setNargs(nargs);
00931     sign->getClass()->getAttribute("types")->setSize(sign, nargs);
00932 
00933     for (int i = 0; i < nargs; i++) {
00934       if (type = ArgType::make(m, args[i].arg)) {
00935         ArgType *t = sign->getTypes(i);
00936         t->setDatabase(db);
00937         t->setType((ArgType_Type)(type->getType() | args[i].inout),
00938                    False);
00939         if (type->getClname().c_str())
00940           t->setClname(type->getClname().c_str());
00941         type->release();
00942       }
00943       else
00944         return Exception::make(IDB_ERROR, "invalid signature syntax: invalid argument type '%s'", args[i].arg);
00945     }
00946   
00947     return Success;
00948   }
00949 
00950   Status Method::get(Database *db, Class *_class,
00951                      const char *sign_str, Bool isClassMethod,
00952                      Method *&mth)
00953   {
00954     Signature *sign = NULL;
00955     char *fname = NULL;
00956 
00957     if (!_class)
00958       return Exception::make(IDB_EXECUTABLE_ERROR, "invalid null class");
00959 
00960     Status s = getSignature(db, _class, sign_str, sign, fname);
00961     if (s) return s;
00962 
00963     s = get(db, _class, fname, sign, isClassMethod, mth);
00964 
00965     free(fname);
00966     sign->release();
00967 
00968     return s;
00969   }
00970 
00971   // ---------------------------------------------------------------------------
00972   //
00973   // FEMethod_C Methods
00974   //
00975   // ---------------------------------------------------------------------------
00976 
00977   FEMethod_C::FEMethod_C(Database *_db, Class *_class,
00978                          const char *name, Signature *sign,
00979                          Bool isClassMethod,
00980                          Bool isSystem, const char *extref)
00981     : FEMethod(_db, (const Dataspace *)0, 1)
00982   {
00983     initialize(_db);
00984     db = _db;
00985     Executable *ex = getEx();
00986     ex->initExec(name, C_LANG, isSystem,
00987                  (ExecutableLocalisation)(FRONTEND | (isClassMethod ? STATIC_EXEC : 0)),
00988                  sign, _class);
00989     setClassOwner(_class);
00990     ex->setExtrefBody(extref);
00991     setName(ex->getIntname());
00992   }
00993 
00994   void FEMethod_C::userInitialize()
00995   {
00996     getEx()->Executable::userInitialize();
00997     csym = 0;
00998   }
00999 
01000   void FEMethod_C::userCopy(const Object &)
01001   {
01002     userInitialize();
01003   }
01004 
01005   Status FEMethod_C::applyTo(Database *_db, Object *o,
01006                              ArgArray &array, Argument &retarg,
01007                              Bool checkArgs)
01008   {
01009     Executable *ex = getEx();
01010     Status s;
01011 
01012     if (checkArgs) {
01013       s = eyedb_CHECKArguments(db, ex->getSign(), array, "method",
01014                                ex->getExname().c_str(), IN_ARG_TYPE);
01015       if (s) return s;
01016     }
01017 
01018     if (!csym)
01019       {
01020         Bool isTrs = _db->isInTransaction();
01021         if (!isTrs)
01022           _db->transactionBegin();
01023         const char *mcname = getClassOwner()->getName();
01024         if (!isTrs)
01025           _db->transactionCommit();
01026         Status s = ex->checkRealize(ex->getExtrefBody().c_str(), mcname,
01027                                     (void **)&csym);
01028         if (s) return s;
01029       }
01030 
01031     return csym(_db, this, o, array, retarg);
01032   }
01033 
01034   Status FEMethod_C::execCheck()
01035   {
01036     Executable *ex = getEx();
01037     return ex->checkRealize(ex->getExtrefBody().c_str(), NULL, (void **)&csym);
01038   }
01039 
01040   // ---------------------------------------------------------------------------
01041   //
01042   // BEMethod_C Methods
01043   //
01044   // ---------------------------------------------------------------------------
01045 
01046   BEMethod_C::BEMethod_C(Database *_db, Class *_class,
01047                          const char *name, Signature *sign,
01048                          Bool isClassMethod, Bool isSystem,
01049                          const char *extref)
01050     : BEMethod(_db, (const Dataspace *)0, 1)
01051   {
01052     initialize(_db);
01053     //db = _db;
01054     Executable *ex = getEx();
01055     ex->initExec(name, C_LANG, isSystem,
01056                  (ExecutableLocalisation)(BACKEND | (isClassMethod ? STATIC_EXEC : 0)),
01057                  sign, _class);
01058     setClassOwner(_class);
01059     ex->setExtrefBody(extref);
01060     setName(ex->getIntname());
01061   }
01062 
01063   Status BEMethod_C::execCheck()
01064   {
01065     if (!db)
01066       return Exception::make(IDB_EXECUTABLE_ERROR,
01067                              "BEMethod_C: cannot set external "
01068                              "reference, database is not set");
01069 
01070     Executable *ex = getEx();
01071 
01072     if (db->isBackEnd())
01073       return ex->checkRealize(ex->getExtrefBody().c_str(), NULL, (void **)&csym);
01074 
01075     RPCStatus rpc_status;
01076 
01077     rpc_status = eyedb::execCheck(db->getDbHandle(),
01078                                   ex->getIntname().c_str(), oid.getOid(),
01079                                   ex->getExtrefBody().c_str());
01080 
01081     return StatusMake(rpc_status);
01082   }
01083 
01084   Status BEMethod_C::applyTo(Database *_db, Object *o,
01085                              ArgArray &array, Argument &retarg,
01086                              Bool checkArgs)
01087   {
01088     const eyedbsm::Oid *objoid;
01089     Oid nulloid;
01090 
01091     if (o && !o->getOid().isValid() &&
01092         (!o->asCollection() || !o->asCollection()->getOidC().isValid())) {
01093       //extern eyedbsm::Boolean se_backend;
01094       //if (!se_backend)
01095       if (!(db->getOpenFlag() & _DBOpenLocal) &&
01096           !db->isBackEnd()) // test added the 12/06/01
01097         return Exception::make(IDB_EXECUTABLE_ERROR,
01098                                "cannot apply a backend method on a "
01099                                "non persistent object");
01100     }
01101   
01102     if (o)
01103       objoid = (o->asCollection() ? o->asCollection()->getOidC().getOid() :
01104                 o->getOid().getOid());
01105     else
01106       objoid = nulloid.getOid();
01107 
01108     Executable *ex = getEx();
01109     Status s;
01110 
01111     if (checkArgs) {
01112       s = eyedb_CHECKArguments(db, ex->getSign(), array, "method",
01113                                ex->getExname().c_str(), IN_ARG_TYPE);
01114       if (s) return s;
01115     }
01116 
01117     RPCStatus rpc_status;
01118     const eyedbsm::Oid *_oid = getOid().getOid();;
01119   
01120     rpc_status = execExecute(_db->getDbHandle(), 
01121                                  _db->getUser(),
01122                                  _db->getPassword(),
01123                                  ex->getIntname().c_str(),
01124                                  ex->getExname().c_str(),
01125                                  METHOD_C_TYPE |
01126                                  (getEx()->isStaticExec() ? STATIC_EXEC : 0),
01127                                  getClassOwner()->getOid().getOid(),
01128                                  ex->getExtrefBody().c_str(),
01129                                  ex->getSign(),
01130                                  _oid,
01131                                  objoid,
01132                                  o,
01133                                  (const void *)&array,
01134                                  (void **)&retarg);
01135 
01136     if (rpc_status)
01137       return StatusMake(rpc_status);
01138 
01139     return Success;
01140   }
01141 
01142   // ---------------------------------------------------------------------------
01143   //
01144   // BEMethod_OQL Methods
01145   //
01146   // ---------------------------------------------------------------------------
01147 
01148   BEMethod_OQL::BEMethod_OQL(Database *_db, Class *_class,
01149                              const char *name, Signature *sign,
01150                              Bool isClassMethod, Bool isSystem,
01151                              const char *_body)
01152   {
01153     initialize(_db);
01154     db = _db;
01155     Executable *ex = getEx();
01156     ex->initExec(name, OQL_LANG, isSystem,
01157                  (ExecutableLocalisation)(BACKEND|
01158                                           (isClassMethod ? STATIC_EXEC : 0)),
01159                  sign, _class);
01160     setClassOwner(_class);
01161     ex->setExtrefBody(_body);
01162     setName(ex->getIntname());
01163   }
01164 
01165   Status BEMethod_OQL::applyTo(Database *, Object *,
01166                                ArgArray &, Argument &retarg,
01167                                Bool checkArgs)
01168   {
01169     return Exception::make("cannot use the 'applyTo' method to an OQL method");
01170   }
01171 
01172   Status BEMethod_OQL::execCheck()
01173   {
01174     // for now
01175     return Success;
01176   }
01177 
01178   Status BEMethod_OQL::setBody(const char *_body)
01179   {
01180     getEx()->setExtrefBody(_body);
01181     return Success;
01182   }
01183 
01184   //
01185   // extref coding
01186   //
01187   // paramcnt:varname#1:varname#2:...:funcname:body
01188   //
01189 
01190   std::string
01191   BEMethod_OQL::makeExtrefBody(const Class *cls, const char *oql,
01192                                const char *name,
01193                                char *typnames[],
01194                                char *varnames[],
01195                                unsigned int param_cnt,
01196                                std::string &oqlConstruct)
01197   {
01198     std::string s = str_convert((long)param_cnt);
01199     int i;
01200 
01201     for (i = 0; i < param_cnt; i++)
01202       s += std::string(":") + varnames[i];
01203 
01204     s += ":";
01205 
01206     std::string funcname = std::string("oql$") + cls->getAliasName() + "$" +
01207       name;
01208 
01209     for (i = 0; i < param_cnt; i++)
01210       funcname += std::string("$") + typnames[i];
01211 
01212     s += funcname;
01213     s += ":";
01214 
01215     oqlConstruct = std::string("function ") + funcname + " (";
01216 
01217     for (i = 0; i < param_cnt; i++)
01218       {
01219         if (i) oqlConstruct += ",";
01220         oqlConstruct += varnames[i];
01221       }
01222 
01223     oqlConstruct += ")";
01224     oqlConstruct += oql;
01225 
01226     return s + oql;
01227   }
01228 
01229   Status
01230   BEMethod_OQL::runtimeInit()
01231   {
01232     if (isRTInitialized)
01233       return Success;
01234 
01235     char *r;
01236     const char *s = getEx()->getExtrefBody().c_str();
01237 
01238     tmpbuf = strdup(s);
01239     char *q = strchr(tmpbuf, ':');
01240 
01241     if (!q)
01242       return Exception::make(IDB_EXECUTABLE_ERROR,
01243                              "invalid internal format '%s'", s);
01244     *q = 0;
01245     param_cnt = atoi(tmpbuf);
01246 
01247     varnames = new char *[param_cnt];
01248     std::string tmp = "(";
01249     for (int i = 0; i < param_cnt; i++)
01250       {
01251         r = strchr(q+1, ':');
01252         if (!r)
01253           return Exception::make(IDB_EXECUTABLE_ERROR,
01254                                  "invalid internal format '%s'", s);
01255         *r = 0;
01256         varnames[i] = q+1;
01257         if (i) tmp += ",";
01258         tmp += varnames[i];
01259         q = r;
01260       }
01261 
01262     tmp += ")";
01263     r = strchr(q+1, ':');
01264     if (!r)
01265       return Exception::make(IDB_EXECUTABLE_ERROR,
01266                              "invalid internal format '%s'", s);
01267     *r = 0;
01268     funcname = q+1;
01269 
01270     r++;
01271     body = r;
01272     fullBody = strdup((std::string("function ") + funcname + tmp + body).c_str());
01273     isRTInitialized = True;
01274     return Success;
01275   }
01276 
01277   void
01278   BEMethod_OQL::userInitialize()
01279   {
01280     isRTInitialized = False;
01281     varnames = 0;
01282     param_cnt = 0;
01283     body = 0;
01284     fullBody = 0;
01285     funcname = 0;
01286     tmpbuf = 0;
01287     entry = 0;
01288   }
01289 
01290   void BEMethod_OQL::userCopy(const Object &)
01291   {
01292     userInitialize();
01293   }
01294 
01295   void
01296   BEMethod_OQL::userGarbage()
01297   {
01298     delete[] varnames;
01299     free(tmpbuf);
01300     free(fullBody);
01301   }
01302 
01303 }
01304   

Generated on Mon Dec 22 18:15:54 2008 for eyedb by  doxygen 1.5.3