/*------------------------------------------------------------------------- * * fmgr.c-- * Interface routines for the table-driven function manager. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.8 1998/01/05 03:34:44 momjian Exp $ * *------------------------------------------------------------------------- */ #include #include #include "postgres.h" /* these 2 files are generated by Gen_fmgrtab.sh; contain the declarations */ #include "fmgr.h" #include "utils/fmgrtab.h" #include "nodes/pg_list.h" #include "catalog/pg_proc.h" #include "catalog/pg_language.h" #include "utils/syscache.h" #include "nodes/params.h" #include "utils/elog.h" #include "nodes/parsenodes.h" #include "commands/trigger.h" char * fmgr_pl(Oid func_id, int n_arguments, FmgrValues * values, bool * isNull) { HeapTuple procedureTuple; HeapTuple languageTuple; Form_pg_proc procedureStruct; Form_pg_language languageStruct; func_ptr plcall_fn; int plcall_nargs; /* Fetch the pg_proc tuple from the syscache */ procedureTuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id), 0, 0, 0); if (!HeapTupleIsValid(procedureTuple)) { elog(ABORT, "fmgr_pl(): Cache lookup of procedure %ld failed.", ObjectIdGetDatum(func_id)); } procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); /* Fetch the pg_language tuple from the syscache */ languageTuple = SearchSysCacheTuple(LANOID, ObjectIdGetDatum(procedureStruct->prolang), 0, 0, 0); if (!HeapTupleIsValid(languageTuple)) { elog(ABORT, "fmgr_pl(): Cache lookup of language %ld for procedure %ld failed.", ObjectIdGetDatum(procedureStruct->prolang), ObjectIdGetDatum(func_id)); } languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); /* Get the function pointer for the PL call handler */ fmgr_info(languageStruct->lanplcallfoid, &plcall_fn, &plcall_nargs); if (plcall_fn == NULL) { elog(ABORT, "fmgr_pl(): failed to load PL handler for procedure %ld.", ObjectIdGetDatum(func_id)); } /* Call the PL handler */ CurrentTriggerData = NULL; return (*plcall_fn) (func_id, n_arguments, values, isNull); } char * fmgr_c(func_ptr user_fn, Oid func_id, int n_arguments, FmgrValues * values, bool * isNull) { char *returnValue = (char *) NULL; if (user_fn == (func_ptr) NULL) { /* * a NULL func_ptr denotet untrusted function (in postgres 4.2). * Untrusted functions have very limited use and is clumsy. We now * use this feature for procedural languages. */ return fmgr_pl(func_id, n_arguments, values, isNull); } switch (n_arguments) { case 0: returnValue = (*user_fn) (); break; case 1: /* NullValue() uses isNull to check if args[0] is NULL */ returnValue = (*user_fn) (values->data[0], isNull); break; case 2: returnValue = (*user_fn) (values->data[0], values->data[1]); break; case 3: returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2]); break; case 4: returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2], values->data[3]); break; case 5: returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2], values->data[3], values->data[4]); break; case 6: returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5]); break; case 7: returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5], values->data[6]); break; case 8: returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5], values->data[6], values->data[7]); break; case 9: /* * XXX Note that functions with >8 arguments can only be * called from inside the system, not from the user level, * since the catalogs only store 8 argument types for user * type-checking! */ returnValue = (*user_fn) (values->data[0], values->data[1], values->data[2], values->data[3], values->data[4], values->data[5], values->data[6], values->data[7], values->data[8]); break; default: elog(ABORT, "fmgr_c: function %d: too many arguments (%d > %d)", func_id, n_arguments, MAXFMGRARGS); break; } return (returnValue); } void fmgr_info(Oid procedureId, func_ptr * function, int *nargs) { func_ptr user_fn = NULL; FmgrCall *fcp; HeapTuple procedureTuple; FormData_pg_proc *procedureStruct; HeapTuple languageTuple; Form_pg_language languageStruct; Oid language; if (!(fcp = fmgr_isbuiltin(procedureId))) { procedureTuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(procedureId), 0, 0, 0); if (!HeapTupleIsValid(procedureTuple)) { elog(ABORT, "fmgr_info: function %d: cache lookup failed\n", procedureId); } procedureStruct = (FormData_pg_proc *) GETSTRUCT(procedureTuple); if (!procedureStruct->proistrusted) { *function = (func_ptr) NULL; *nargs = procedureStruct->pronargs; return; } language = procedureStruct->prolang; switch (language) { case INTERNALlanguageId: user_fn = fmgr_lookupByName(procedureStruct->proname.data); if (!user_fn) elog(ABORT, "fmgr_info: function %s: not in internal table", procedureStruct->proname.data); break; case ClanguageId: user_fn = fmgr_dynamic(procedureId, nargs); break; case SQLlanguageId: user_fn = (func_ptr) NULL; *nargs = procedureStruct->pronargs; break; default: /* * Might be a created procedural language Lookup the * syscache for the language and check the lanispl flag If * this is the case, we return a NULL function pointer and * the number of arguments from the procedure. */ languageTuple = SearchSysCacheTuple(LANOID, ObjectIdGetDatum(procedureStruct->prolang), 0, 0, 0); if (!HeapTupleIsValid(languageTuple)) { elog(ABORT, "fmgr_info: %s %ld", "Cache lookup for language %d failed", ObjectIdGetDatum(procedureStruct->prolang)); } languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); if (languageStruct->lanispl) { user_fn = (func_ptr) NULL; *nargs = procedureStruct->pronargs; } else { elog(ABORT, "fmgr_info: function %d: unknown language %d", procedureId, language); } break; } } else { user_fn = fcp->func; *nargs = fcp->nargs; } *function = user_fn; } /* * fmgr - return the value of a function call * * If the function is a system routine, it's compiled in, so call * it directly. * * Otherwise pass it to the the appropriate 'language' function caller. * * Returns the return value of the invoked function if succesful, * 0 if unsuccessful. */ char * fmgr(Oid procedureId,...) { va_list pvar; register i; int pronargs; FmgrValues values; func_ptr user_fn; bool isNull = false; va_start(pvar, procedureId); fmgr_info(procedureId, &user_fn, &pronargs); if (pronargs > MAXFMGRARGS) { elog(ABORT, "fmgr: function %d: too many arguments (%d > %d)", procedureId, pronargs, MAXFMGRARGS); } for (i = 0; i < pronargs; ++i) values.data[i] = va_arg(pvar, char *); va_end(pvar); /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ return (fmgr_c(user_fn, procedureId, pronargs, &values, &isNull)); } /* * This is just a version of fmgr() in which the hacker can prepend a C * function pointer. This routine is not normally called; generally, * if you have all of this information you're likely to just jump through * the pointer, but it's available for use with macros in fmgr.h if you * want this routine to do sanity-checking for you. * * func_ptr, func_id, n_arguments, args... */ #ifdef NOT_USED char * fmgr_ptr(func_ptr user_fn, Oid func_id,...) { va_list pvar; register i; int n_arguments; FmgrValues values; bool isNull = false; va_start(pvar, func_id); n_arguments = va_arg(pvar, int); if (n_arguments > MAXFMGRARGS) { elog(ABORT, "fmgr_ptr: function %d: too many arguments (%d > %d)", func_id, n_arguments, MAXFMGRARGS); } for (i = 0; i < n_arguments; ++i) values.data[i] = va_arg(pvar, char *); va_end(pvar); /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ return (fmgr_c(user_fn, func_id, n_arguments, &values, &isNull)); } #endif /* * This routine is not well thought out. When I get around to adding a * function pointer field to FuncIndexInfo, it will be replace by calls * to fmgr_c(). */ char * fmgr_array_args(Oid procedureId, int nargs, char *args[], bool * isNull) { func_ptr user_fn; int true_arguments; fmgr_info(procedureId, &user_fn, &true_arguments); /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ return (fmgr_c(user_fn, procedureId, true_arguments, (FmgrValues *) args, isNull)); }