postgresql/src/backend/utils/fmgr/fmgr.c

257 lines
6.7 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* 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.3 1997/08/19 21:35:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdarg.h>
#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"
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 denotes untrusted function (in postgres 4.2).
* Untrusted functions have very limited use and is clumsy. We
* just get rid of it.
*/
elog(WARN, "internal error: untrusted function not supported.");
}
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(WARN, "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)
{
1996-11-08 07:02:30 +01:00
func_ptr user_fn = NULL;
FmgrCall *fcp;
HeapTuple procedureTuple;
FormData_pg_proc *procedureStruct;
Oid language;
if (!(fcp = fmgr_isbuiltin(procedureId))) {
procedureTuple = SearchSysCacheTuple(PROOID,
ObjectIdGetDatum(procedureId),
0,0,0);
if (!HeapTupleIsValid(procedureTuple)) {
elog(WARN, "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(WARN, "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:
elog(WARN, "fmgr_info: function %d: unknown language %d",
procedureId, language);
}
} 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(WARN, "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(WARN, "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));
}