Hi

pá 16. 8. 2019 v 8:41 odesílatel Pavel Stehule <pavel.steh...@gmail.com>
napsal:

> Hi
>
> rebase
>

another rebase

Regards

Pavel


> Pavel
>
diff --git a/contrib/Makefile b/contrib/Makefile
index 92184ed487..dafa42844d 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -15,6 +15,7 @@ SUBDIRS = \
 		citext		\
 		cube		\
 		dblink		\
+		decode		\
 		dict_int	\
 		dict_xsyn	\
 		earthdistance	\
diff --git a/contrib/decode/.gitignore b/contrib/decode/.gitignore
new file mode 100644
index 0000000000..5dcb3ff972
--- /dev/null
+++ b/contrib/decode/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/contrib/decode/Makefile b/contrib/decode/Makefile
new file mode 100644
index 0000000000..bb29732c61
--- /dev/null
+++ b/contrib/decode/Makefile
@@ -0,0 +1,20 @@
+# contrib/decode/Makefile
+
+MODULES = decode
+
+EXTENSION = decode
+DATA = decode--1.0.sql
+PGFILEDESC = "decode - example of parser support function"
+
+REGRESS = decode
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/decode
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/decode/decode--1.0.sql b/contrib/decode/decode--1.0.sql
new file mode 100644
index 0000000000..34408809ff
--- /dev/null
+++ b/contrib/decode/decode--1.0.sql
@@ -0,0 +1,26 @@
+/* contrib/decode/decode--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION decode" to load this file. \quit
+
+--
+--  PostgreSQL code for decode.
+--
+
+--
+-- Parser support function - allow to specify returning type when
+-- system with polymorphic variables is possible to use.
+--
+CREATE FUNCTION decode_support(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+--
+-- decode function - example of function that returns "any" type
+--
+CREATE FUNCTION decode(variadic "any")
+RETURNS "any"
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE SUPPORT decode_support;
+
diff --git a/contrib/decode/decode.c b/contrib/decode/decode.c
new file mode 100644
index 0000000000..32919bf846
--- /dev/null
+++ b/contrib/decode/decode.c
@@ -0,0 +1,459 @@
+/*
+ * contrib/decode/decode.c
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "catalog/pg_type.h"
+#include "nodes/supportnodes.h"
+#include "parser/parse_coerce.h"
+#include "parser/parse_oper.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(decode_support);
+PG_FUNCTION_INFO_V1(decode);
+
+static void decode_detect_types(int nargs, Oid *argtypes, Oid *search_oid, Oid *result_oid);
+static Oid select_common_type_from_vector(int nargs, Oid *typeids, bool noerror);
+
+typedef struct decode_cache
+{
+	Oid			rettype;
+	int			nargs;
+	Oid		   *argtypes;
+	Oid		   *target_types;
+	Oid			search_typid;
+	Oid			result_typid;
+	CoercionPathType *ctype;
+	FmgrInfo   *cast_finfo;
+	FmgrInfo   *input_finfo;
+	Oid		   *typioparam;
+	FmgrInfo	eqop_finfo;
+} decode_cache;
+
+static void
+free_cache(decode_cache *cache)
+{
+	pfree(cache->argtypes);
+	pfree(cache->target_types);
+	pfree(cache->ctype);
+	pfree(cache->cast_finfo);
+	pfree(cache->input_finfo);
+	pfree(cache->typioparam);
+	pfree(cache);
+}
+
+/*
+ * prepare persistent cache used for fast internal parameter casting
+ */
+static decode_cache *
+build_cache(int nargs,
+			Oid *argtypes,
+			MemoryContext target_ctx)
+{
+	Oid		search_typid;
+	Oid		result_typid;
+	Oid			eqop;
+	decode_cache *cache;
+	MemoryContext		oldctx;
+	int		i;
+
+	oldctx = MemoryContextSwitchTo(target_ctx);
+
+	cache = palloc(sizeof(decode_cache));
+
+	cache->argtypes = palloc(nargs * sizeof(Oid));
+	cache->target_types = palloc(nargs * sizeof(Oid));
+	cache->ctype = palloc(nargs * sizeof(CoercionPathType));
+	cache->cast_finfo = palloc(nargs * sizeof(FmgrInfo));
+	cache->input_finfo = palloc(nargs * sizeof(FmgrInfo));
+	cache->typioparam = palloc(nargs * sizeof(Oid));
+
+	MemoryContextSwitchTo(oldctx);
+
+	decode_detect_types(nargs, argtypes, &search_typid, &result_typid);
+
+	cache->search_typid = search_typid;
+	cache->result_typid = result_typid;
+
+	for (i = 0; i < nargs; i++)
+	{
+		Oid		src_typid;
+		Oid		target_typid;
+
+		src_typid = cache->argtypes[i] = argtypes[i];
+
+		if (i == 0)
+			target_typid = search_typid;
+		else if (i % 2) /* even position */
+		{
+			if (i + 1 < nargs)
+				target_typid = search_typid;
+			else
+				/* last even argument is a default value */
+				target_typid = result_typid;
+		}
+		else /* odd position */
+			target_typid = result_typid;
+
+		cache->target_types[i] = target_typid;
+
+		/* prepare cast if it is necessary */
+		if (src_typid != target_typid)
+		{
+			Oid		funcid;
+
+			cache->ctype[i] = find_coercion_pathway(target_typid, src_typid,
+										COERCION_ASSIGNMENT, &funcid);
+			if (cache->ctype[i] == COERCION_PATH_NONE)
+				/* A previously detected cast is not available now */
+				elog(ERROR, "could not find cast from %u to %u",
+					 src_typid, target_typid);
+
+			if (cache->ctype[i] != COERCION_PATH_RELABELTYPE)
+			{
+				if (cache->ctype[i] == COERCION_PATH_FUNC)
+				{
+					fmgr_info(funcid, &cache->cast_finfo[i]);
+				}
+				else
+				{
+					Oid		outfuncoid;
+					Oid		infunc;
+					bool	typisvarlena;
+
+					getTypeOutputInfo(src_typid, &outfuncoid, &typisvarlena);
+					fmgr_info(outfuncoid, &cache->cast_finfo[i]);
+
+					getTypeInputInfo(target_typid, &infunc, &cache->typioparam[i]);
+					fmgr_info(infunc, &cache->input_finfo[i]);
+				}
+			}
+		}
+	}
+
+	get_sort_group_operators(search_typid, false, true, false, NULL, &eqop, NULL, NULL);
+	fmgr_info(get_opcode(eqop), &cache->eqop_finfo);
+
+	return cache;
+}
+
+/*
+ * Returns converted value into target type
+ */
+static Datum
+decode_cast(decode_cache *cache, int argn, Datum value)
+{
+	Datum result;
+
+	if (cache->argtypes[argn] != cache->target_types[argn])
+	{
+		if (cache->ctype[argn] == COERCION_PATH_RELABELTYPE)
+			result = value;
+		else if (cache->ctype[argn] == COERCION_PATH_FUNC)
+			result = FunctionCall1(&cache->cast_finfo[argn], value);
+		else
+		{
+			char	*str;
+
+			str = OutputFunctionCall(&cache->cast_finfo[argn], value);
+			result = InputFunctionCall(&cache->input_finfo[argn],
+									   str,
+									   cache->typioparam[argn],
+									   -1);
+		}
+	}
+	else
+		result = value;
+
+	return result;
+}
+
+/*
+ * Returns true, if cache can be used again
+ */
+static bool
+is_valid_cache(int nargs, Oid *argtypes, decode_cache *cache)
+{
+	if (cache)
+	{
+		if (nargs == cache->nargs)
+		{
+			int		i;
+
+			for (i = 0; i < nargs; i++)
+				if (argtypes[i] != cache->argtypes[i])
+					return false;
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static void
+decode_detect_types(int nargs,
+					Oid *argtypes,
+					Oid *search_oid,	/* result */
+					Oid *result_oid)	/* result */
+{
+	Oid		search_typids[FUNC_MAX_ARGS];
+	Oid		result_typids[FUNC_MAX_ARGS];
+	int		search_nargs = 0;
+	int		result_nargs = 0;
+
+	Assert(nargs >= 3);
+
+	*search_oid = argtypes[1] != UNKNOWNOID ? argtypes[1] : TEXTOID;
+	*result_oid = argtypes[2] != UNKNOWNOID ? argtypes[2] : TEXTOID;
+
+	/* Search most common type if target type is not a text */
+	if (*search_oid != TEXTOID || *result_oid != TEXTOID)
+	{
+		int		i;
+
+		for (i = 0; i < nargs; i++)
+		{
+			if (i == 0)
+				search_typids[search_nargs++] = argtypes[0];
+			else if (i % 2) /* even position */
+			{
+				if (i + 1 < nargs)
+					search_typids[search_nargs++] = argtypes[i];
+				else
+					result_typids[result_nargs++] = argtypes[i];
+			}
+			else /* odd position */
+				result_typids[result_nargs++] = argtypes[i];
+		}
+
+		if (*search_oid != TEXTOID)
+		{
+			*search_oid = select_common_type_from_vector(search_nargs,
+														 search_typids,
+														 true);
+
+			if (!OidIsValid(*search_oid)) /* should not to be */
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("cannot to detect common type for search expression")));
+		}
+
+		if (*result_oid != TEXTOID)
+		{
+			*result_oid = select_common_type_from_vector(result_nargs,
+														 result_typids,
+														 true);
+
+			if (!OidIsValid(*result_oid)) /* should not to be */
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("cannot to detect common type for result expression")));
+		}
+	}
+}
+
+
+Datum
+decode_support(PG_FUNCTION_ARGS)
+{
+	Node	   *rawreq = (Node *) PG_GETARG_POINTER(0);
+	Node	   *ret = NULL;
+
+	if (IsA(rawreq, SupportRequestRettype))
+	{
+		SupportRequestRettype *req = (SupportRequestRettype *) rawreq;
+		Oid		search_oid;
+		Oid		result_oid;
+
+		if (req->nargs < 3)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("too few function arguments"),
+					 errhint("The decode function requires at least 3 arguments")));
+
+		decode_detect_types(req->nargs, req->actual_arg_types, &search_oid, &result_oid);
+
+		req->rettype = result_oid;
+
+		ret = (Node *) req;
+	}
+
+	PG_RETURN_POINTER(ret);
+}
+
+Datum
+decode(PG_FUNCTION_ARGS)
+{
+	Datum		expr = (Datum) 0;
+	bool	expr_isnull;
+	Oid		argtypes[FUNC_MAX_ARGS];
+	Oid		collation;
+	decode_cache *cache;
+	int		nargs = PG_NARGS();
+	int		result_argn;
+	int		i;
+
+	if (nargs < 3)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("too few function arguments"),
+				 errhint("The decode function requires at least 3 arguments")));
+
+	/* collect arg types */
+	for (i = 0; i < nargs; i++)
+		argtypes[i] = get_fn_expr_argtype(fcinfo->flinfo, i);
+
+	cache = (decode_cache *) fcinfo->flinfo->fn_extra;
+	if (!is_valid_cache(nargs, argtypes, cache))
+	{
+		if (cache)
+			free_cache(cache);
+		cache = build_cache(nargs, argtypes, fcinfo->flinfo->fn_mcxt);
+
+		fcinfo->flinfo->fn_extra = cache;
+	}
+
+	/* recheck rettype, should not be */
+	if (get_fn_expr_rettype(fcinfo->flinfo) != cache->result_typid)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("function has unexpected result type %d", get_fn_expr_rettype(fcinfo->flinfo)),
+				 errhint("The decode expects \"%s\" type",
+							format_type_be(cache->result_typid))));
+
+	/* try to set result_argn to position with default arrgument */
+	result_argn = nargs % 2 ? - 1 : nargs - 1;
+
+	expr_isnull = PG_ARGISNULL(0);
+	collation = PG_GET_COLLATION();
+
+	if (!expr_isnull)
+		expr = decode_cast(cache, 0, PG_GETARG_DATUM(0));
+
+	for (i = 1; i < nargs; i+= 2)
+	{
+		if (!expr_isnull && !PG_ARGISNULL(i) && i + 1 < nargs)
+		{
+			Datum		eqop_result;
+			Datum		value;
+
+			value = decode_cast(cache, i, PG_GETARG_DATUM(i));
+			eqop_result = FunctionCall2Coll(&cache->eqop_finfo, collation, expr, value);
+
+			if (DatumGetBool(eqop_result))
+			{
+				result_argn = i + 1;
+				break;
+			}
+		}
+		else if (expr_isnull && PG_ARGISNULL(i))
+		{
+			result_argn = i + 1;
+			break;
+		}
+	}
+
+	if (result_argn >= 0 && !PG_ARGISNULL(result_argn))
+		PG_RETURN_DATUM(decode_cast(cache, result_argn, PG_GETARG_DATUM(result_argn)));
+
+	PG_RETURN_NULL();
+}
+
+/*
+ * select_common_type_from_vector()
+ *		Determine the common supertype of vector of Oids.
+ *
+ * Similar to select_common_type() but simplified for polymorphics
+ * type processing. When there are no supertype, then returns InvalidOid,
+ * when noerror is true, or raise exception when noerror is false.
+ */
+static Oid
+select_common_type_from_vector(int nargs, Oid *typeids, bool noerror)
+{
+	int	i = 0;
+	Oid			ptype;
+	TYPCATEGORY pcategory;
+	bool		pispreferred;
+
+	Assert(nargs > 0);
+	ptype = typeids[0];
+
+	/* fast leave when all types are same */
+	if (ptype != UNKNOWNOID)
+	{
+		for (i = 1; i < nargs; i++)
+		{
+			if (ptype != typeids[i])
+				break;
+		}
+
+		if (i == nargs)
+			return ptype;
+	}
+
+	/*
+	 * Nope, so set up for the full algorithm.  Note that at this point, lc
+	 * points to the first list item with type different from pexpr's; we need
+	 * not re-examine any items the previous loop advanced over.
+	 */
+	ptype = getBaseType(ptype);
+	get_type_category_preferred(ptype, &pcategory, &pispreferred);
+
+	for (; i < nargs; i++)
+	{
+		Oid			ntype = getBaseType(typeids[i]);
+
+		/* move on to next one if no new information... */
+		if (ntype != UNKNOWNOID && ntype != ptype)
+		{
+			TYPCATEGORY ncategory;
+			bool		nispreferred;
+
+			get_type_category_preferred(ntype, &ncategory, &nispreferred);
+
+			if (ptype == UNKNOWNOID)
+			{
+				/* so far, only unknowns so take anything... */
+				ptype = ntype;
+				pcategory = ncategory;
+				pispreferred = nispreferred;
+			}
+			else if (ncategory != pcategory)
+			{
+				if (noerror)
+					return InvalidOid;
+
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("types %s and %s cannot be matched",
+								format_type_be(ptype),
+								format_type_be(ntype))));
+			}
+			else if (!pispreferred &&
+					 can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
+					 !can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT))
+			{
+				/*
+				 * take new type if can coerce to it implicitly but not the
+				 * other way; but if we have a preferred type, stay on it.
+				 */
+				ptype = ntype;
+				pcategory = ncategory;
+				pispreferred = nispreferred;
+			}
+		}
+	}
+
+	/*
+	 * Be consistent with select_common_type()
+	 */
+	if (ptype == UNKNOWNOID)
+		ptype = TEXTOID;
+
+	return ptype;
+}
diff --git a/contrib/decode/decode.control b/contrib/decode/decode.control
new file mode 100644
index 0000000000..048499d4ab
--- /dev/null
+++ b/contrib/decode/decode.control
@@ -0,0 +1,5 @@
+# decode extension
+comment = 'decode - demo of function with parser support function'
+default_version = '1.0'
+module_pathname = '$libdir/decode'
+relocatable = true
diff --git a/contrib/decode/expected/decode.out b/contrib/decode/expected/decode.out
new file mode 100644
index 0000000000..dfb9edbdbc
--- /dev/null
+++ b/contrib/decode/expected/decode.out
@@ -0,0 +1,40 @@
+--
+--  Test decode function
+--
+CREATE EXTENSION decode;
+SELECT decode(1, 1, 5, 0);
+ decode 
+--------
+      5
+(1 row)
+
+SELECT decode(2, 1, 5, 0);
+ decode 
+--------
+      0
+(1 row)
+
+SELECT decode(1, 1, 5, 0.5);
+ decode 
+--------
+      5
+(1 row)
+
+SELECT decode(2, 1, 5, 0.5);
+ decode 
+--------
+    0.5
+(1 row)
+
+SELECT decode(1, 1, 'Ahoj', 'Nazdar');
+ decode 
+--------
+ Ahoj
+(1 row)
+
+SELECT decode(2, 1, 'Ahoj', 'Nazdar');
+ decode 
+--------
+ Nazdar
+(1 row)
+
diff --git a/contrib/decode/sql/decode.sql b/contrib/decode/sql/decode.sql
new file mode 100644
index 0000000000..ee93ad058c
--- /dev/null
+++ b/contrib/decode/sql/decode.sql
@@ -0,0 +1,13 @@
+--
+--  Test decode function
+--
+
+CREATE EXTENSION decode;
+
+SELECT decode(1, 1, 5, 0);
+SELECT decode(2, 1, 5, 0);
+SELECT decode(1, 1, 5, 0.5);
+SELECT decode(2, 1, 5, 0.5);
+
+SELECT decode(1, 1, 'Ahoj', 'Nazdar');
+SELECT decode(2, 1, 'Ahoj', 'Nazdar');
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 1ac235a0f4..fe0f440353 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -845,6 +845,7 @@ lookup_agg_function(List *fnName,
 	int			nvargs;
 	Oid			vatype;
 	Oid		   *true_oid_array;
+	Oid			support_func;
 	FuncDetailCode fdresult;
 	AclResult	aclresult;
 	int			i;
@@ -860,7 +861,8 @@ lookup_agg_function(List *fnName,
 							   nargs, input_types, false, false,
 							   &fnOid, rettype, &retset,
 							   &nvargs, &vatype,
-							   &true_oid_array, NULL);
+							   &true_oid_array, NULL,
+							   &support_func);
 
 	/* only valid case is a normal function not returning a set */
 	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index d9c6dc1901..978ceb1290 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -22,6 +22,7 @@
 #include "lib/stringinfo.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
+#include "nodes/supportnodes.h"
 #include "parser/parse_agg.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
@@ -111,6 +112,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 	bool		retset;
 	int			nvargs;
 	Oid			vatype;
+	Oid			support_func;
 	FuncDetailCode fdresult;
 	char		aggkind = 0;
 	ParseCallbackState pcbstate;
@@ -265,7 +267,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 							   !func_variadic, true,
 							   &funcid, &rettype, &retset,
 							   &nvargs, &vatype,
-							   &declared_arg_types, &argdefaults);
+							   &declared_arg_types, &argdefaults,
+							   &support_func);
 
 	cancel_parser_errposition_callback(&pcbstate);
 
@@ -666,6 +669,31 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 	/* perform the necessary typecasting of arguments */
 	make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types);
 
+	/*
+	 * When rettype is ANYOID we can call support function SupportRequestRettype if
+	 * it is available to get real type.
+	 */
+	if (rettype == ANYOID && OidIsValid(support_func))
+	{
+		SupportRequestRettype		req;
+		SupportRequestRettype	   *result;
+
+		req.type = T_SupportRequestRettype;
+		req.funcname = funcname;
+		req.fargs = fargs;
+		req.actual_arg_types = actual_arg_types;
+		req.declared_arg_types = declared_arg_types;
+		req.nargs = nargsplusdefs;
+
+		result = (SupportRequestRettype *)
+					DatumGetPointer(OidFunctionCall1(support_func,
+													 PointerGetDatum(&req)));
+
+		/* use result when it is valid */
+		if (result == &req)
+			rettype = result->rettype;
+	}
+
 	/*
 	 * If the function isn't actually variadic, forget any VARIADIC decoration
 	 * on the call.  (Perhaps we should throw an error instead, but
@@ -1392,7 +1420,8 @@ func_get_detail(List *funcname,
 				int *nvargs,	/* return value */
 				Oid *vatype,	/* return value */
 				Oid **true_typeids, /* return value */
-				List **argdefaults) /* optional return value */
+				List **argdefaults, /* optional return value */
+				Oid *support_func) /* return value */
 {
 	FuncCandidateList raw_candidates;
 	FuncCandidateList best_candidate;
@@ -1404,6 +1433,7 @@ func_get_detail(List *funcname,
 	*nvargs = 0;
 	*vatype = InvalidOid;
 	*true_typeids = NULL;
+	*support_func = InvalidOid;
 	if (argdefaults)
 		*argdefaults = NIL;
 
@@ -1518,6 +1548,7 @@ func_get_detail(List *funcname,
 					*nvargs = 0;
 					*vatype = InvalidOid;
 					*true_typeids = argtypes;
+					*support_func = InvalidOid;
 					return FUNCDETAIL_COERCION;
 				}
 			}
@@ -1615,6 +1646,7 @@ func_get_detail(List *funcname,
 		*rettype = pform->prorettype;
 		*retset = pform->proretset;
 		*vatype = pform->provariadic;
+		*support_func = pform->prosupport;
 		/* fetch default args if caller wants 'em */
 		if (argdefaults && best_candidate->ndargs > 0)
 		{
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 13685a0a0e..c4347b037b 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -10880,6 +10880,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
 	int			p_nvargs;
 	Oid			p_vatype;
 	Oid		   *p_true_typeids;
+	Oid			p_support_func;
 	bool		force_qualify = false;
 
 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
@@ -10934,7 +10935,8 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
 								   !use_variadic, true,
 								   &p_funcid, &p_rettype,
 								   &p_retset, &p_nvargs, &p_vatype,
-								   &p_true_typeids, NULL);
+								   &p_true_typeids, NULL,
+								   &p_support_func);
 	else
 	{
 		p_result = FUNCDETAIL_NOTFOUND;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index bce2d59b0d..0e636d95e6 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -513,7 +513,8 @@ typedef enum NodeTag
 	T_SupportRequestSelectivity,	/* in nodes/supportnodes.h */
 	T_SupportRequestCost,		/* in nodes/supportnodes.h */
 	T_SupportRequestRows,		/* in nodes/supportnodes.h */
-	T_SupportRequestIndexCondition	/* in nodes/supportnodes.h */
+	T_SupportRequestIndexCondition,	/* in nodes/supportnodes.h */
+	T_SupportRequestRettype		/* in nodes/supportnodes.h */
 } NodeTag;
 
 /*
diff --git a/src/include/nodes/supportnodes.h b/src/include/nodes/supportnodes.h
index 460d75bd2d..abaf42cf96 100644
--- a/src/include/nodes/supportnodes.h
+++ b/src/include/nodes/supportnodes.h
@@ -239,4 +239,25 @@ typedef struct SupportRequestIndexCondition
 								 * equivalent of the function call */
 } SupportRequestIndexCondition;
 
+/*
+ * The SupportRequestRettype request type allows to calculate result type for
+ * functions that returns "any" type. It is designed for procedural specification
+ * return type.
+ */
+typedef struct SupportRequestRettype
+{
+	NodeTag		type;
+
+	/* Input fields */
+	List	   *funcname;
+	List	   *fargs;
+	Oid		   *actual_arg_types;
+	Oid		   *declared_arg_types;
+	int			nargs;
+
+	/* Output fields */
+	Oid			rettype;
+
+} SupportRequestRettype;
+
 #endif							/* SUPPORTNODES_H */
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index 5a3b287eaf..7fc2ef1d37 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -41,7 +41,8 @@ extern FuncDetailCode func_get_detail(List *funcname,
 									  bool expand_variadic, bool expand_defaults,
 									  Oid *funcid, Oid *rettype,
 									  bool *retset, int *nvargs, Oid *vatype,
-									  Oid **true_typeids, List **argdefaults);
+									  Oid **true_typeids, List **argdefaults,
+									  Oid *support_func);
 
 extern int	func_match_argtypes(int nargs,
 								Oid *input_typeids,

Reply via email to