summaryrefslogtreecommitdiff
path: root/src/backend/utils/fmgr/fmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/fmgr/fmgr.c')
-rw-r--r--src/backend/utils/fmgr/fmgr.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
new file mode 100644
index 00000000000..6ae276944ee
--- /dev/null
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -0,0 +1,254 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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.1.1.1 1996/07/09 06:22:08 scrappy 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)
+{
+ func_ptr user_fn;
+ 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...
+ */
+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));
+}
+
+/*
+ * 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));
+}