summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2005-12-28 18:11:25 +0000
committerTom Lane2005-12-28 18:11:25 +0000
commitfc56946e2210e96d460e08b3c58c6919654d7fdc (patch)
treea452cf97e597bd5f60143f54fe301834a8399be8
parent891ffee3a0c1d4d61302637c2f97e1f700e73310 (diff)
Move plpgsql's fetchArgInfo() into funcapi.c, and rename to
get_func_arg_info() for consistency with other names there. This code will probably be useful to other PLs when they start to support OUT parameters, so better to have it in the main backend. Also, fix plpgsql validator to detect bogus OUT parameters even when check_function_bodies is off.
-rw-r--r--src/backend/utils/fmgr/funcapi.c103
-rw-r--r--src/include/funcapi.h8
-rw-r--r--src/pl/plpgsql/src/pl_comp.c102
-rw-r--r--src/pl/plpgsql/src/pl_handler.c31
4 files changed, 127 insertions, 117 deletions
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 146592036d..ff4383499b 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -629,6 +629,109 @@ get_type_func_class(Oid typid)
/*
+ * get_func_arg_info
+ *
+ * Fetch info about the argument types, names, and IN/OUT modes from the
+ * pg_proc tuple. Return value is the total number of arguments.
+ * Other results are palloc'd. *p_argtypes is always filled in, but
+ * *p_argnames and *p_argmodes will be set NULL in the default cases
+ * (no names, and all IN arguments, respectively).
+ *
+ * Note that this function simply fetches what is in the pg_proc tuple;
+ * it doesn't do any interpretation of polymorphic types.
+ */
+int
+get_func_arg_info(HeapTuple procTup,
+ Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
+{
+ Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
+ Datum proallargtypes;
+ Datum proargmodes;
+ Datum proargnames;
+ bool isNull;
+ ArrayType *arr;
+ int numargs;
+ Datum *elems;
+ int nelems;
+ int i;
+
+ /* First discover the total number of parameters and get their types */
+ proallargtypes = SysCacheGetAttr(PROCOID, procTup,
+ Anum_pg_proc_proallargtypes,
+ &isNull);
+ if (!isNull)
+ {
+ /*
+ * We expect the arrays to be 1-D arrays of the right types; verify
+ * that. For the OID and char arrays, we don't need to use
+ * deconstruct_array() since the array data is just going to look like
+ * a C array of values.
+ */
+ arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
+ numargs = ARR_DIMS(arr)[0];
+ if (ARR_NDIM(arr) != 1 ||
+ numargs < 0 ||
+ ARR_HASNULL(arr) ||
+ ARR_ELEMTYPE(arr) != OIDOID)
+ elog(ERROR, "proallargtypes is not a 1-D Oid array");
+ Assert(numargs >= procStruct->pronargs);
+ *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
+ memcpy(*p_argtypes, ARR_DATA_PTR(arr),
+ numargs * sizeof(Oid));
+ }
+ else
+ {
+ /* If no proallargtypes, use proargtypes */
+ numargs = procStruct->proargtypes.dim1;
+ Assert(numargs == procStruct->pronargs);
+ *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
+ memcpy(*p_argtypes, procStruct->proargtypes.values,
+ numargs * sizeof(Oid));
+ }
+
+ /* Get argument names, if available */
+ proargnames = SysCacheGetAttr(PROCOID, procTup,
+ Anum_pg_proc_proargnames,
+ &isNull);
+ if (isNull)
+ *p_argnames = NULL;
+ else
+ {
+ deconstruct_array(DatumGetArrayTypeP(proargnames),
+ TEXTOID, -1, false, 'i',
+ &elems, NULL, &nelems);
+ if (nelems != numargs) /* should not happen */
+ elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
+ *p_argnames = (char **) palloc(sizeof(char *) * numargs);
+ for (i = 0; i < numargs; i++)
+ (*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout,
+ elems[i]));
+ }
+
+ /* Get argument modes, if available */
+ proargmodes = SysCacheGetAttr(PROCOID, procTup,
+ Anum_pg_proc_proargmodes,
+ &isNull);
+ if (isNull)
+ *p_argmodes = NULL;
+ else
+ {
+ arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
+ if (ARR_NDIM(arr) != 1 ||
+ ARR_DIMS(arr)[0] != numargs ||
+ ARR_HASNULL(arr) ||
+ ARR_ELEMTYPE(arr) != CHAROID)
+ elog(ERROR, "proargmodes is not a 1-D char array");
+ *p_argmodes = (char *) palloc(numargs * sizeof(char));
+ memcpy(*p_argmodes, ARR_DATA_PTR(arr),
+ numargs * sizeof(char));
+ }
+
+ return numargs;
+}
+
+
+/*
* get_func_result_name
*
* If the function has exactly one output parameter, and that parameter
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 6334db6ed1..7ff6b346cf 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -165,12 +165,16 @@ extern TypeFuncClass get_func_result_type(Oid functionId,
Oid *resultTypeId,
TupleDesc *resultTupleDesc);
-extern char *get_func_result_name(Oid functionId);
-
extern bool resolve_polymorphic_argtypes(int numargs, Oid *argtypes,
char *argmodes,
Node *call_expr);
+extern int get_func_arg_info(HeapTuple procTup,
+ Oid **p_argtypes, char ***p_argnames,
+ char **p_argmodes);
+
+extern char *get_func_result_name(Oid functionId);
+
extern TupleDesc build_function_result_tupdesc_d(Datum proallargtypes,
Datum proargmodes,
Datum proargnames);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 01b413d110..3306dd866f 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -123,9 +123,6 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
HeapTuple procTup,
PLpgSQL_func_hashkey *hashkey,
bool forValidator);
-static int fetchArgInfo(HeapTuple procTup,
- Oid **p_argtypes, char ***p_argnames,
- char **p_argmodes);
static PLpgSQL_row *build_row_from_class(Oid classOid);
static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
@@ -358,7 +355,8 @@ do_compile(FunctionCallInfo fcinfo,
*/
MemoryContextSwitchTo(compile_tmp_cxt);
- numargs = fetchArgInfo(procTup, &argtypes, &argnames, &argmodes);
+ numargs = get_func_arg_info(procTup,
+ &argtypes, &argnames, &argmodes);
plpgsql_resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
fcinfo->flinfo->fn_expr,
@@ -751,102 +749,6 @@ plpgsql_compile_error_callback(void *arg)
}
-/*
- * Fetch info about the argument types, names, and IN/OUT modes from the
- * pg_proc tuple. Return value is the number of arguments.
- * Other results are palloc'd.
- */
-static int
-fetchArgInfo(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames,
- char **p_argmodes)
-{
- Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
- Datum proallargtypes;
- Datum proargmodes;
- Datum proargnames;
- bool isNull;
- ArrayType *arr;
- int numargs;
- Datum *elems;
- int nelems;
- int i;
-
- /* First discover the total number of parameters and get their types */
- proallargtypes = SysCacheGetAttr(PROCOID, procTup,
- Anum_pg_proc_proallargtypes,
- &isNull);
- if (!isNull)
- {
- /*
- * We expect the arrays to be 1-D arrays of the right types; verify
- * that. For the OID and char arrays, we don't need to use
- * deconstruct_array() since the array data is just going to look like
- * a C array of values.
- */
- arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
- numargs = ARR_DIMS(arr)[0];
- if (ARR_NDIM(arr) != 1 ||
- numargs < 0 ||
- ARR_HASNULL(arr) ||
- ARR_ELEMTYPE(arr) != OIDOID)
- elog(ERROR, "proallargtypes is not a 1-D Oid array");
- Assert(numargs >= procStruct->pronargs);
- *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
- memcpy(*p_argtypes, ARR_DATA_PTR(arr),
- numargs * sizeof(Oid));
- }
- else
- {
- /* If no proallargtypes, use proargtypes */
- numargs = procStruct->proargtypes.dim1;
- Assert(numargs == procStruct->pronargs);
- *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
- memcpy(*p_argtypes, procStruct->proargtypes.values,
- numargs * sizeof(Oid));
- }
-
- /* Get argument names, if available */
- proargnames = SysCacheGetAttr(PROCOID, procTup,
- Anum_pg_proc_proargnames,
- &isNull);
- if (isNull)
- *p_argnames = NULL;
- else
- {
- deconstruct_array(DatumGetArrayTypeP(proargnames),
- TEXTOID, -1, false, 'i',
- &elems, NULL, &nelems);
- if (nelems != numargs) /* should not happen */
- elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
- *p_argnames = (char **) palloc(sizeof(char *) * numargs);
- for (i = 0; i < numargs; i++)
- (*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout,
- elems[i]));
- }
-
- /* Get argument modes, if available */
- proargmodes = SysCacheGetAttr(PROCOID, procTup,
- Anum_pg_proc_proargmodes,
- &isNull);
- if (isNull)
- *p_argmodes = NULL;
- else
- {
- arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
- if (ARR_NDIM(arr) != 1 ||
- ARR_DIMS(arr)[0] != numargs ||
- ARR_HASNULL(arr) ||
- ARR_ELEMTYPE(arr) != CHAROID)
- elog(ERROR, "proargmodes is not a 1-D char array");
- *p_argmodes = (char *) palloc(numargs * sizeof(char));
- memcpy(*p_argmodes, ARR_DATA_PTR(arr),
- numargs * sizeof(char));
- }
-
- return numargs;
-}
-
-
/* ----------
* plpgsql_parse_word The scanner calls this to postparse
* any single word not found by a
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 006bab0bf9..16eab3fb9a 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -41,6 +41,7 @@
#include "access/heapam.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+#include "funcapi.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -147,9 +148,11 @@ plpgsql_validator(PG_FUNCTION_ARGS)
HeapTuple tuple;
Form_pg_proc proc;
char functyptype;
+ int numargs;
+ Oid *argtypes;
+ char **argnames;
+ char *argmodes;
bool istrigger = false;
- bool haspolyresult;
- bool haspolyarg;
int i;
/* perform initialization */
@@ -173,32 +176,30 @@ plpgsql_validator(PG_FUNCTION_ARGS)
if (proc->prorettype == TRIGGEROID ||
(proc->prorettype == OPAQUEOID && proc->pronargs == 0))
istrigger = true;
- else if (proc->prorettype == ANYARRAYOID ||
- proc->prorettype == ANYELEMENTOID)
- haspolyresult = true;
else if (proc->prorettype != RECORDOID &&
- proc->prorettype != VOIDOID)
+ proc->prorettype != VOIDOID &&
+ proc->prorettype != ANYARRAYOID &&
+ proc->prorettype != ANYELEMENTOID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot return type %s",
format_type_be(proc->prorettype))));
}
- /* Disallow pseudotypes in arguments */
+ /* Disallow pseudotypes in arguments (either IN or OUT) */
/* except for ANYARRAY or ANYELEMENT */
- haspolyarg = false;
- for (i = 0; i < proc->pronargs; i++)
+ numargs = get_func_arg_info(tuple,
+ &argtypes, &argnames, &argmodes);
+ for (i = 0; i < numargs; i++)
{
- if (get_typtype(proc->proargtypes.values[i]) == 'p')
+ if (get_typtype(argtypes[i]) == 'p')
{
- if (proc->proargtypes.values[i] == ANYARRAYOID ||
- proc->proargtypes.values[i] == ANYELEMENTOID)
- haspolyarg = true;
- else
+ if (argtypes[i] != ANYARRAYOID &&
+ argtypes[i] != ANYELEMENTOID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot take type %s",
- format_type_be(proc->proargtypes.values[i]))));
+ format_type_be(argtypes[i]))));
}
}