diff options
Diffstat (limited to 'src/backend/utils/fmgr/fmgr.c')
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 1765 |
1 files changed, 1168 insertions, 597 deletions
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index bdac32a2551..793497834fd 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * fmgr.c - * Interface routines for the table-driven function manager. + * The Postgres function manager. * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.39 2000/05/22 02:34:22 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.40 2000/05/28 17:56:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,112 +17,249 @@ #include "catalog/pg_language.h" #include "catalog/pg_proc.h" -#include "commands/trigger.h" +#include "commands/trigger.h" /* TEMPORARY: for CurrentTriggerData */ #include "utils/builtins.h" #include "utils/fmgrtab.h" #include "utils/syscache.h" +static Datum fmgr_oldstyle(PG_FUNCTION_ARGS); +static Datum fmgr_untrusted(PG_FUNCTION_ARGS); +static Datum fmgr_sql(PG_FUNCTION_ARGS); + /* - * Interface for PL functions - * - * XXX: use of global fmgr_pl_finfo variable is really ugly. FIXME + * Lookup routines for builtin-function table. We can search by either Oid + * or name, but search by Oid is much faster. */ -FmgrInfo *fmgr_pl_finfo; -static char * -fmgr_pl(char *arg0,...) +static const FmgrBuiltin * +fmgr_isbuiltin(Oid id) { - va_list pvar; - FmgrValues values; - int n_arguments = fmgr_pl_finfo->fn_nargs; - bool isNull = false; - int i; + int low = 0; + int high = fmgr_nbuiltins - 1; - memset(&values, 0, sizeof(values)); + /* Loop invariant: low is the first index that could contain target + * entry, and high is the last index that could contain it. + */ + while (low <= high) + { + int i = (high + low) / 2; + const FmgrBuiltin *ptr = &fmgr_builtins[i]; - if (n_arguments > 0) + if (id == ptr->foid) + return ptr; + else if (id > ptr->foid) + low = i + 1; + else + high = i - 1; + } + return (const FmgrBuiltin *) NULL; +} + +/* + * Lookup a builtin by name. Note there can be more than one entry in + * the array with the same name, but they should all point to the same + * routine. + */ +static const FmgrBuiltin * +fmgr_lookupByName(const char *name) +{ + int i; + + for (i = 0; i < fmgr_nbuiltins; i++) { - values.data[0] = arg0; - if (n_arguments > 1) + if (strcmp(name, fmgr_builtins[i].funcName) == 0) + return fmgr_builtins + i; + } + return (const FmgrBuiltin *) NULL; +} + +/* + * This routine fills a FmgrInfo struct, given the OID + * of the function to be called. + */ +void +fmgr_info(Oid functionId, FmgrInfo *finfo) +{ + const FmgrBuiltin *fbp; + HeapTuple procedureTuple; + Form_pg_proc procedureStruct; + HeapTuple languageTuple; + Form_pg_language languageStruct; + Oid language; + char *prosrc; + + finfo->fn_oid = functionId; + finfo->fn_extra = NULL; + + if ((fbp = fmgr_isbuiltin(functionId)) != NULL) + { + /* + * Fast path for builtin functions: don't bother consulting pg_proc + */ + finfo->fn_nargs = fbp->nargs; + finfo->fn_strict = fbp->strict; + if (fbp->oldstyle) { - if (n_arguments > FUNC_MAX_ARGS) - elog(ERROR, "fmgr_pl: function %u: too many arguments (%d > %d)", - fmgr_pl_finfo->fn_oid, n_arguments, FUNC_MAX_ARGS); - va_start(pvar, arg0); - for (i = 1; i < n_arguments; i++) - values.data[i] = va_arg(pvar, char *); - va_end(pvar); + finfo->fn_addr = fmgr_oldstyle; + finfo->fn_extra = (void *) fbp->func; } + else + { + finfo->fn_addr = fbp->func; + } + return; } - /* Call the PL handler */ - CurrentTriggerData = NULL; - return (*(fmgr_pl_finfo->fn_plhandler)) (fmgr_pl_finfo, - &values, - &isNull); -} + /* Otherwise we need the pg_proc entry */ + procedureTuple = SearchSysCacheTuple(PROCOID, + ObjectIdGetDatum(functionId), + 0, 0, 0); + if (!HeapTupleIsValid(procedureTuple)) + elog(ERROR, "fmgr_info: function %u: cache lookup failed", + functionId); + procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); + finfo->fn_nargs = procedureStruct->pronargs; + finfo->fn_strict = procedureStruct->proisstrict; -/* - * Interface for untrusted functions - */ + if (!procedureStruct->proistrusted) + { + finfo->fn_addr = fmgr_untrusted; + return; + } -static char * -fmgr_untrusted(char *arg0,...) -{ + language = procedureStruct->prolang; + switch (language) + { + case INTERNALlanguageId: + case NEWINTERNALlanguageId: + /* + * For an ordinary builtin function, we should never get + * here because the isbuiltin() search above will have + * succeeded. However, if the user has done a CREATE + * FUNCTION to create an alias for a builtin function, we + * can end up here. In that case we have to look up the + * function by name. The name of the internal function is + * stored in prosrc (it doesn't have to be the same as the + * name of the alias!) + */ + prosrc = textout(&(procedureStruct->prosrc)); + fbp = fmgr_lookupByName(prosrc); + if (fbp == NULL) + elog(ERROR, "fmgr_info: function %s not in internal table", + prosrc); + pfree(prosrc); + if (fbp->oldstyle) + { + finfo->fn_addr = fmgr_oldstyle; + finfo->fn_extra = (void *) fbp->func; + } + else + { + finfo->fn_addr = fbp->func; + } + break; - /* - * Currently these are unsupported. Someday we might do something - * like forking a subprocess to execute 'em. - */ - elog(ERROR, "Untrusted functions not supported."); - return NULL; /* keep compiler happy */ + case ClanguageId: + finfo->fn_addr = fmgr_oldstyle; + finfo->fn_extra = (void *) fmgr_dynamic(functionId); + break; + + case NEWClanguageId: + finfo->fn_addr = fmgr_dynamic(functionId); + break; + + case SQLlanguageId: + finfo->fn_addr = fmgr_sql; + break; + + default: + /* + * Might be a created procedural language; try to look it up. + */ + languageTuple = SearchSysCacheTuple(LANGOID, + ObjectIdGetDatum(language), + 0, 0, 0); + if (!HeapTupleIsValid(languageTuple)) + { + elog(ERROR, "fmgr_info: cache lookup for language %u failed", + language); + } + languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); + if (languageStruct->lanispl) + { + FmgrInfo plfinfo; + + fmgr_info(languageStruct->lanplcallfoid, &plfinfo); + finfo->fn_addr = plfinfo.fn_addr; + /* + * If lookup of the PL handler function produced nonnull + * fn_extra, complain --- it must be an oldstyle function! + * We no longer support oldstyle PL handlers. + */ + if (plfinfo.fn_extra != NULL) + elog(ERROR, "fmgr_info: language %u has old-style handler", + language); + } + else + { + elog(ERROR, "fmgr_info: function %u: unsupported language %u", + functionId, language); + } + break; + } } /* - * Interface for SQL-language functions + * Specialized lookup routine for pg_proc.c: given the alleged name of + * an internal function, return the OID of the function's language. + * If the name is not known, return InvalidOid. */ - -static char * -fmgr_sql(char *arg0,...) +Oid +fmgr_internal_language(const char *proname) { + const FmgrBuiltin *fbp = fmgr_lookupByName(proname); - /* - * XXX It'd be really nice to support SQL functions anywhere that - * builtins are supported. What would we have to do? What pitfalls - * are there? - */ - elog(ERROR, "SQL-language function not supported in this context."); - return NULL; /* keep compiler happy */ + if (fbp == NULL) + return InvalidOid; + return fbp->oldstyle ? INTERNALlanguageId : NEWINTERNALlanguageId; } /* - * fmgr_c is not really for C functions only; it can be called for functions - * in any language. Many parts of the system use this entry point if they - * want to pass the arguments in an array rather than as explicit arguments. + * Handler for old-style internal and "C" language functions + * + * We expect fmgr_info to have placed the old-style function's address + * in fn_extra of *flinfo. This is a bit of a hack since fn_extra is really + * void * which might be a different size than a pointer to function, but + * it will work on any machine that our old-style call interface works on... */ - -char * -fmgr_c(FmgrInfo *finfo, - FmgrValues *values, - bool *isNull) +static Datum +fmgr_oldstyle(PG_FUNCTION_ARGS) { - char *returnValue = (char *) NULL; - int n_arguments = finfo->fn_nargs; - func_ptr user_fn = fmgr_faddr(finfo); + char *returnValue = NULL; + int n_arguments = fcinfo->nargs; + int i; + bool isnull; + func_ptr user_fn; + + if (fcinfo->flinfo == NULL || fcinfo->flinfo->fn_extra == NULL) + elog(ERROR, "Internal error: fmgr_oldstyle received NULL function pointer"); /* - * If finfo contains a PL handler for this function, call that - * instead. + * Result is NULL if any argument is NULL, but we still call the function + * (peculiar, but that's the way it worked before, and after all this is + * a backwards-compatibility wrapper). Note, however, that we'll never + * get here with NULL arguments if the function is marked strict. */ - if (finfo->fn_plhandler != NULL) - return (*(finfo->fn_plhandler)) (finfo, values, isNull); + isnull = false; + for (i = 0; i < n_arguments; i++) + isnull |= PG_ARGISNULL(i); + fcinfo->isnull = isnull; - if (user_fn == (func_ptr) NULL) - elog(ERROR, "Internal error: fmgr_c received NULL function pointer."); + user_fn = (func_ptr) fcinfo->flinfo->fn_extra; switch (n_arguments) { @@ -130,604 +267,1038 @@ fmgr_c(FmgrInfo *finfo, returnValue = (*user_fn) (); break; case 1: - /* NullValue() uses isNull to check if args[0] is NULL */ - returnValue = (*user_fn) (values->data[0], isNull); + /* + * nullvalue() used to use isNull to check if arg is NULL; + * perhaps there are other functions still out there that + * also rely on this undocumented hack? + */ + returnValue = (*user_fn) (fcinfo->arg[0], & fcinfo->isnull); break; case 2: - returnValue = (*user_fn) (values->data[0], values->data[1]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1]); break; case 3: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2]); break; case 4: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3]); break; case 5: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[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]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[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]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[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]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7]); break; case 9: - 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]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8]); break; -#if FUNC_MAX_ARGS >= 10 case 10: - 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], values->data[9]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9]); break; -#endif -#if FUNC_MAX_ARGS >= 11 case 11: - 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], values->data[9], - values->data[10]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10]); break; -#endif -#if FUNC_MAX_ARGS >= 12 case 12: - 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], values->data[9], - values->data[10], values->data[11]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11]); break; -#endif -#if FUNC_MAX_ARGS >= 13 case 13: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12]); break; -#endif -#if FUNC_MAX_ARGS >= 14 case 14: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12], fcinfo->arg[13]); break; -#endif -#if FUNC_MAX_ARGS >= 15 case 15: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12], fcinfo->arg[13], + fcinfo->arg[14]); break; -#endif -#if FUNC_MAX_ARGS >= 16 case 16: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15]); - break; -#endif -#if FUNC_MAX_ARGS >= 17 - case 17: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16]); - break; -#endif -#if FUNC_MAX_ARGS >= 18 - case 18: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17]); - break; -#endif -#if FUNC_MAX_ARGS >= 19 - case 19: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18]); - break; -#endif -#if FUNC_MAX_ARGS >= 20 - case 20: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19]); - break; -#endif -#if FUNC_MAX_ARGS >= 21 - case 21: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20]); - break; -#endif -#if FUNC_MAX_ARGS >= 22 - case 22: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21]); - break; -#endif -#if FUNC_MAX_ARGS >= 23 - case 23: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22]); - break; -#endif -#if FUNC_MAX_ARGS >= 24 - case 24: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23]); - break; -#endif -#if FUNC_MAX_ARGS >= 25 - case 25: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24]); - break; -#endif -#if FUNC_MAX_ARGS >= 26 - case 26: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12], fcinfo->arg[13], + fcinfo->arg[14], fcinfo->arg[15]); break; -#endif -#if FUNC_MAX_ARGS >= 27 - case 27: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26]); - break; -#endif -#if FUNC_MAX_ARGS >= 28 - case 28: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27]); - break; -#endif -#if FUNC_MAX_ARGS >= 29 - case 29: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28]); - break; -#endif -#if FUNC_MAX_ARGS >= 30 - case 30: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28], values->data[29]); - break; -#endif -#if FUNC_MAX_ARGS >= 31 - case 31: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28], values->data[29], - values->data[30]); - break; -#endif -#if FUNC_MAX_ARGS >= 32 - case 32: - 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], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28], values->data[29], - values->data[30], values->data[31]); - break; -#endif default: - elog(ERROR, "fmgr_c: function %u: too many arguments (%d > %d)", - finfo->fn_oid, n_arguments, FUNC_MAX_ARGS); + /* + * Increasing FUNC_MAX_ARGS doesn't automatically add cases + * to the above code, so give the actual value in this error + * not FUNC_MAX_ARGS. You could add cases to the above if you + * needed to support old-style functions with many arguments, + * but making 'em be new-style is probably a better idea. + */ + elog(ERROR, "fmgr_oldstyle: function %u: too many arguments (%d > %d)", + fcinfo->flinfo->fn_oid, n_arguments, 16); break; } - return returnValue; + + return (Datum) returnValue; } + /* - * Expand a regproc OID into an FmgrInfo cache struct. + * Handler for all functions marked "untrusted" */ +static Datum +fmgr_untrusted(PG_FUNCTION_ARGS) +{ + /* + * Currently these are unsupported. Someday we might do something + * like forking a subprocess to execute 'em. + */ + elog(ERROR, "Untrusted functions not supported"); + return 0; /* keep compiler happy */ +} -void -fmgr_info(Oid procedureId, FmgrInfo *finfo) +/* + * Handler for SQL-language functions + */ +static Datum +fmgr_sql(PG_FUNCTION_ARGS) { - FmgrCall *fcp; - HeapTuple procedureTuple; - FormData_pg_proc *procedureStruct; - HeapTuple languageTuple; - Form_pg_language languageStruct; - Oid language; - char *prosrc; + /* + * XXX It'd be really nice to support SQL functions anywhere that + * builtins are supported. What would we have to do? What pitfalls + * are there? + */ + elog(ERROR, "SQL-language function not supported in this context"); + return 0; /* keep compiler happy */ +} - finfo->fn_addr = NULL; - finfo->fn_plhandler = NULL; - finfo->fn_oid = procedureId; +/* + * Interface routine for functions using fmgr_faddr + */ +FmgrInfo *fmgr_pl_finfo; /* should GO AWAY */ - if ((fcp = fmgr_isbuiltin(procedureId)) != NULL) - { +char * +fmgr_faddr_link(char *arg0, ...) +{ + FunctionCallInfoData fcinfo; + int n_arguments; + Datum result; - /* - * Fast path for builtin functions: don't bother consulting - * pg_proc - */ - finfo->fn_addr = fcp->func; - finfo->fn_nargs = fcp->nargs; - } - else + MemSet(&fcinfo, 0, sizeof(fcinfo)); + /* We rely on fmgr_faddr macro to have set back-link to FmgrInfo (ugh) */ + fcinfo.flinfo = fmgr_pl_finfo; + fcinfo.nargs = fcinfo.flinfo->fn_nargs; + n_arguments = fcinfo.nargs; + + if (n_arguments > 0) { - procedureTuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(procedureId), - 0, 0, 0); - if (!HeapTupleIsValid(procedureTuple)) - { - elog(ERROR, "fmgr_info: function %u: cache lookup failed", - procedureId); - } - procedureStruct = (FormData_pg_proc *) GETSTRUCT(procedureTuple); - if (!procedureStruct->proistrusted) - { - finfo->fn_addr = (func_ptr) fmgr_untrusted; - finfo->fn_nargs = procedureStruct->pronargs; - return; - } - language = procedureStruct->prolang; - switch (language) + fcinfo.arg[0] = (Datum) arg0; + if (n_arguments > 1) { - case INTERNALlanguageId: - - /* - * For an ordinary builtin function, we should never get - * here because the isbuiltin() search above will have - * succeeded. However, if the user has done a CREATE - * FUNCTION to create an alias for a builtin function, we - * end up here. In that case we have to look up the - * function by name. The name of the internal function is - * stored in prosrc (it doesn't have to be the same as the - * name of the alias!) - */ - prosrc = textout(&(procedureStruct->prosrc)); - finfo->fn_addr = fmgr_lookupByName(prosrc); - if (!finfo->fn_addr) - elog(ERROR, "fmgr_info: function %s not in internal table", - prosrc); - finfo->fn_nargs = procedureStruct->pronargs; - pfree(prosrc); - break; - case ClanguageId: - finfo->fn_addr = fmgr_dynamic(procedureId, &(finfo->fn_nargs)); - break; - case SQLlanguageId: - finfo->fn_addr = (func_ptr) fmgr_sql; - finfo->fn_nargs = procedureStruct->pronargs; - break; - default: + va_list pvar; + int i; - /* - * 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(LANGOID, - ObjectIdGetDatum(procedureStruct->prolang), - 0, 0, 0); - if (!HeapTupleIsValid(languageTuple)) - { - elog(ERROR, "fmgr_info: %s %u", - "Cache lookup for language failed", - DatumGetObjectId(procedureStruct->prolang)); - } - languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); - if (languageStruct->lanispl) - { - FmgrInfo plfinfo; - - fmgr_info(languageStruct->lanplcallfoid, &plfinfo); - finfo->fn_addr = (func_ptr) fmgr_pl; - finfo->fn_plhandler = plfinfo.fn_addr; - finfo->fn_nargs = procedureStruct->pronargs; - } - else - { - elog(ERROR, "fmgr_info: function %u: unknown language %d", - procedureId, language); - } - break; + if (n_arguments > FUNC_MAX_ARGS) + elog(ERROR, "fmgr_faddr_link: function %u: too many arguments (%d > %d)", + fcinfo.flinfo->fn_oid, n_arguments, FUNC_MAX_ARGS); + va_start(pvar, arg0); + for (i = 1; i < n_arguments; i++) + fcinfo.arg[i] = (Datum) va_arg(pvar, char *); + va_end(pvar); } } + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "fmgr_faddr_link: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return (char *) result; } /* * 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. + * This is essentially fmgr_info plus call the function. */ char * fmgr(Oid procedureId,...) { - va_list pvar; - int i; - int pronargs; - FmgrValues values; - FmgrInfo finfo; - bool isNull = false; + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + int n_arguments; + Datum result; + + fmgr_info(procedureId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = flinfo.fn_nargs; + n_arguments = fcinfo.nargs; + + if (n_arguments > 0) + { + va_list pvar; + int i; - fmgr_info(procedureId, &finfo); - pronargs = finfo.fn_nargs; + if (n_arguments > FUNC_MAX_ARGS) + elog(ERROR, "fmgr: function %u: too many arguments (%d > %d)", + flinfo.fn_oid, n_arguments, FUNC_MAX_ARGS); + va_start(pvar, procedureId); + for (i = 0; i < n_arguments; i++) + fcinfo.arg[i] = (Datum) va_arg(pvar, char *); + va_end(pvar); + } - if (pronargs > FUNC_MAX_ARGS) - elog(ERROR, "fmgr: function %u: too many arguments (%d > %d)", - procedureId, pronargs, FUNC_MAX_ARGS); + result = FunctionCallInvoke(&fcinfo); - va_start(pvar, procedureId); - for (i = 0; i < pronargs; ++i) - values.data[i] = va_arg(pvar, char *); - va_end(pvar); + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "fmgr: function %u returned NULL", + flinfo.fn_oid); - /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ - return fmgr_c(&finfo, &values, &isNull); + return (char *) result; } -/* - * 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. - * - * funcinfo, n_arguments, args... + +/*------------------------------------------------------------------------- + * Support routines for callers of fmgr-compatible functions + *------------------------------------------------------------------------- */ -#ifdef TRACE_FMGR_PTR -char * -fmgr_ptr(FmgrInfo *finfo,...) +/* These are for invocation of a specifically named function with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. Also, the function cannot be one that needs to + * look at FmgrInfo, since there won't be any. + */ +Datum +DirectFunctionCall1(PGFunction func, Datum arg1) { - va_list pvar; - int i; - int n_arguments; - FmgrInfo local_finfo; - FmgrValues values; - bool isNull = false; - - local_finfo->fn_addr = finfo->fn_addr; - local_finfo->fn_plhandler = finfo->fn_plhandler; - local_finfo->fn_oid = finfo->fn_oid; - - va_start(pvar, finfo); - n_arguments = va_arg(pvar, int); - local_finfo->fn_nargs = n_arguments; - if (n_arguments > FUNC_MAX_ARGS) - { - elog(ERROR, "fmgr_ptr: function %u: too many arguments (%d > %d)", - func_id, n_arguments, FUNC_MAX_ARGS); - } - for (i = 0; i < n_arguments; ++i) - values.data[i] = va_arg(pvar, char *); - va_end(pvar); + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 1; + fcinfo.arg[0] = arg1; - /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ - return fmgr_c(&local_finfo, &values, &isNull); + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall1: function %p returned NULL", + (void *) func); + + return result; } -#endif +Datum +DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2) +{ + FunctionCallInfoData fcinfo; + Datum result; -/* - * 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(). + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 2; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall2: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2, + Datum arg3) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 3; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall3: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 4; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall4: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 5; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall5: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 6; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall6: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall7(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 7; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall7: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall8(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 8; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall8: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 9; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + fcinfo.arg[8] = arg9; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall9: function %p returned NULL", + (void *) func); + + return result; +} + + +/* These are for invocation of a previously-looked-up function with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. */ -char * -fmgr_array_args(Oid procedureId, int nargs, char *args[], bool *isNull) +Datum +FunctionCall1(FmgrInfo *flinfo, Datum arg1) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 1; + fcinfo.arg[0] = arg1; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall1: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 2; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall2: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall3(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 3; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall3: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall4(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 4; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall4: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall5(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 5; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall5: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall6(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 6; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall6: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall7(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7) { - FmgrInfo finfo; + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 7; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall7: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall8(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 8; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall8: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 9; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + fcinfo.arg[8] = arg9; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall9: function %u returned NULL", + fcinfo.flinfo->fn_oid); - fmgr_info(procedureId, &finfo); - finfo.fn_nargs = nargs; + return result; +} + + +/* These are for invocation of a function identified by OID with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. These are essentially fmgr_info() followed + * by FunctionCallN(). If the same function is to be invoked repeatedly, + * do the fmgr_info() once and then use FunctionCallN(). + */ +Datum +OidFunctionCall1(Oid functionId, Datum arg1) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 1; + fcinfo.arg[0] = arg1; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall1: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall2(Oid functionId, Datum arg1, Datum arg2) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 2; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall2: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall3(Oid functionId, Datum arg1, Datum arg2, + Datum arg3) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 3; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall3: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall4(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 4; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall4: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall5(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 5; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall5: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall6(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 6; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall6: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall7(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 7; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall7: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall8(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 8; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall8: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 9; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + fcinfo.arg[8] = arg9; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall9: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + + +/*------------------------------------------------------------------------- + * Support routines for standard pass-by-reference datatypes + * + * Note: at some point, at least on some platforms, these might become + * pass-by-value types. Obviously Datum must be >= 8 bytes to allow + * int64 or float8 to be pass-by-value. I think that Float4GetDatum + * and Float8GetDatum will need to be out-of-line routines anyway, + * since just casting from float to Datum will not do the right thing; + * some kind of trick with pointer-casting or a union will be needed. + *------------------------------------------------------------------------- + */ + +Datum +Int64GetDatum(int64 X) +{ + int64 *retval = (int64 *) palloc(sizeof(int64)); + + *retval = X; + return PointerGetDatum(retval); +} + +Datum +Float4GetDatum(float4 X) +{ + float4 *retval = (float4 *) palloc(sizeof(float4)); + + *retval = X; + return PointerGetDatum(retval); +} + +Datum +Float8GetDatum(float8 X) +{ + float8 *retval = (float8 *) palloc(sizeof(float8)); - /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ - return fmgr_c(&finfo, - (FmgrValues *) args, - isNull); + *retval = X; + return PointerGetDatum(retval); } |