fmgr.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
- /*-------------------------------------------------------------------------
- *
- * fmgr.c
- * Interface routines for the table-driven function manager.
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.28.2.1 1999/08/02 05:25:06 scrappy Exp $
- *
- *-------------------------------------------------------------------------
- */
- #include "postgres.h"
- #include "catalog/pg_language.h"
- #include "catalog/pg_proc.h"
- #include "commands/trigger.h"
- #include "utils/builtins.h"
- #include "utils/fmgrtab.h"
- #include "utils/syscache.h"
- /*
- * Interface for PL functions
- *
- * XXX: use of global fmgr_pl_finfo variable is really ugly. FIXME
- */
- static char *
- fmgr_pl(char *arg0,...)
- {
- va_list pvar;
- FmgrValues values;
- int n_arguments = fmgr_pl_finfo->fn_nargs;
- bool isNull = false;
- int i;
- memset(&values, 0, sizeof(values));
- if (n_arguments > 0)
- {
- values.data[0] = arg0;
- if (n_arguments > 1)
- {
- if (n_arguments > MAXFMGRARGS)
- elog(ERROR, "fmgr_pl: function %u: too many arguments (%d > %d)",
- fmgr_pl_finfo->fn_oid, n_arguments, MAXFMGRARGS);
- va_start(pvar, arg0);
- for (i = 1; i < n_arguments; i++)
- values.data[i] = va_arg(pvar, char *);
- va_end(pvar);
- }
- }
- /* Call the PL handler */
- CurrentTriggerData = NULL;
- return (*(fmgr_pl_finfo->fn_plhandler)) (fmgr_pl_finfo,
- &values,
- &isNull);
- }
- /*
- * Interface for untrusted functions
- */
- static char *
- fmgr_untrusted(char *arg0,...)
- {
- /*
- * 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 */
- }
- /*
- * Interface for SQL-language functions
- */
- static char *
- fmgr_sql(char *arg0,...)
- {
- /*
- * 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 */
- }
- /*
- * 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.
- */
- char *
- fmgr_c(FmgrInfo *finfo,
- FmgrValues *values,
- bool *isNull)
- {
- char *returnValue = (char *) NULL;
- int n_arguments = finfo->fn_nargs;
- func_ptr user_fn = fmgr_faddr(finfo);
- /*
- * If finfo contains a PL handler for this function, call that
- * instead.
- */
- if (finfo->fn_plhandler != NULL)
- return (*(finfo->fn_plhandler)) (finfo, values, isNull);
- if (user_fn == (func_ptr) NULL)
- elog(ERROR, "Internal error: fmgr_c received NULL function pointer.");
- 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(ERROR, "fmgr_c: function %u: too many arguments (%d > %d)",
- finfo->fn_oid, n_arguments, MAXFMGRARGS);
- break;
- }
- return returnValue;
- }
- /*
- * Expand a regproc OID into an FmgrInfo cache struct.
- */
- void
- fmgr_info(Oid procedureId, FmgrInfo *finfo)
- {
- FmgrCall *fcp;
- HeapTuple procedureTuple;
- FormData_pg_proc *procedureStruct;
- HeapTuple languageTuple;
- Form_pg_language languageStruct;
- Oid language;
- char *prosrc;
- finfo->fn_addr = NULL;
- finfo->fn_plhandler = NULL;
- finfo->fn_oid = procedureId;
- if ((fcp = fmgr_isbuiltin(procedureId)) != NULL)
- {
- /*
- * Fast path for builtin functions: don't bother consulting
- * pg_proc
- */
- finfo->fn_addr = fcp->func;
- finfo->fn_nargs = fcp->nargs;
- }
- else
- {
- procedureTuple = SearchSysCacheTuple(PROOID,
- 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)
- {
- 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:
- /*
- * 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(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;
- }
- }
- }
- /*
- * 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;
- int i;
- int pronargs;
- FmgrValues values;
- FmgrInfo finfo;
- bool isNull = false;
- fmgr_info(procedureId, &finfo);
- pronargs = finfo.fn_nargs;
- if (pronargs > MAXFMGRARGS)
- elog(ERROR, "fmgr: function %u: too many arguments (%d > %d)",
- procedureId, pronargs, MAXFMGRARGS);
- va_start(pvar, procedureId);
- 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(&finfo, &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.
- *
- * funcinfo, n_arguments, args...
- */
- #ifdef TRACE_FMGR_PTR
- char *
- fmgr_ptr(FmgrInfo *finfo,...)
- {
- 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 > MAXFMGRARGS)
- {
- elog(ERROR, "fmgr_ptr: function %u: 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(&local_finfo, &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)
- {
- FmgrInfo finfo;
- fmgr_info(procedureId, &finfo);
- finfo.fn_nargs = nargs;
- /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
- return fmgr_c(&finfo,
- (FmgrValues *) args,
- isNull);
- }