summaryrefslogtreecommitdiff
path: root/src/backend/catalog/pg_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/pg_proc.c')
-rw-r--r--src/backend/catalog/pg_proc.c86
1 files changed, 63 insertions, 23 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 48b90e56ef..4ec4c44bd4 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.97 2003/06/15 17:59:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.98 2003/07/01 00:04:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,7 +33,6 @@
#include "utils/syscache.h"
-static void checkretval(Oid rettype, char fn_typtype, List *queryTreeList);
Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
Datum fmgr_c_validator(PG_FUNCTION_ARGS);
Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
@@ -317,15 +316,20 @@ ProcedureCreate(const char *procedureName,
}
/*
- * checkretval() -- check return value of a list of sql parse trees.
+ * check_sql_fn_retval() -- check return value of a list of sql parse trees.
*
* The return value of a sql function is the value returned by
- * the final query in the function. We do some ad-hoc define-time
- * type checking here to be sure that the user is returning the
- * type he claims.
+ * the final query in the function. We do some ad-hoc type checking here
+ * to be sure that the user is returning the type he claims.
+ *
+ * This is normally applied during function definition, but in the case
+ * of a function with polymorphic arguments, we instead apply it during
+ * function execution startup. The rettype is then the actual resolved
+ * output type of the function, rather than the declared type. (Therefore,
+ * we should never see ANYARRAY or ANYELEMENT as rettype.)
*/
-static void
-checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
+void
+check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
{
Query *parse;
int cmd;
@@ -472,7 +476,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
relation_close(reln, AccessShareLock);
}
- else if (fn_typtype == 'p' && rettype == RECORDOID)
+ else if (rettype == RECORDOID)
{
/* Shouldn't have a typerelid */
Assert(typerelid == InvalidOid);
@@ -482,6 +486,14 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
* tuple.
*/
}
+ else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
+ {
+ /*
+ * This should already have been caught ...
+ */
+ elog(ERROR, "functions returning ANYARRAY or ANYELEMENT must " \
+ "have at least one argument of either type");
+ }
else
elog(ERROR, "return type %s is not supported for SQL functions",
format_type_be(rettype));
@@ -505,7 +517,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
Datum tmp;
char *prosrc;
- tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcoid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
@@ -544,7 +558,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
char *prosrc;
char *probin;
- tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcoid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
@@ -585,38 +601,62 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
Datum tmp;
char *prosrc;
char functyptype;
+ bool haspolyarg;
int i;
- tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcoid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
functyptype = get_typtype(proc->prorettype);
- /* Disallow pseudotypes in arguments and result */
- /* except that return type can be RECORD or VOID */
+ /* Disallow pseudotype result */
+ /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
if (functyptype == 'p' &&
proc->prorettype != RECORDOID &&
- proc->prorettype != VOIDOID)
+ proc->prorettype != VOIDOID &&
+ proc->prorettype != ANYARRAYOID &&
+ proc->prorettype != ANYELEMENTOID)
elog(ERROR, "SQL functions cannot return type %s",
format_type_be(proc->prorettype));
+ /* Disallow pseudotypes in arguments */
+ /* except for ANYARRAY or ANYELEMENT */
+ haspolyarg = false;
for (i = 0; i < proc->pronargs; i++)
{
if (get_typtype(proc->proargtypes[i]) == 'p')
- elog(ERROR, "SQL functions cannot have arguments of type %s",
- format_type_be(proc->proargtypes[i]));
+ {
+ if (proc->proargtypes[i] == ANYARRAYOID ||
+ proc->proargtypes[i] == ANYELEMENTOID)
+ haspolyarg = true;
+ else
+ elog(ERROR, "SQL functions cannot have arguments of type %s",
+ format_type_be(proc->proargtypes[i]));
+ }
}
- tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
- if (isnull)
- elog(ERROR, "null prosrc");
+ /*
+ * We can't precheck the function definition if there are any polymorphic
+ * input types, because actual datatypes of expression results will be
+ * unresolvable. The check will be done at runtime instead.
+ */
+ if (!haspolyarg)
+ {
+ tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+ if (isnull)
+ elog(ERROR, "null prosrc");
- prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+ prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
- querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
- checkretval(proc->prorettype, functyptype, querytree_list);
+ querytree_list = pg_parse_and_rewrite(prosrc,
+ proc->proargtypes,
+ proc->pronargs);
+ check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
+ }
ReleaseSysCache(tuple);