diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index be47d411c5bdf51eb52ac96fa416672f5dc286ba..02ca0f820c7a806593b7263bad242d11634f0956 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -2,7 +2,7 @@
  *
  * funcapi.c
  *	  Utility and convenience functions for fmgr functions that return
- *	  sets and/or composite types.
+ *	  sets and/or composite types, or deal with VARIADIC inputs.
  *
  * Copyright (c) 2002-2017, PostgreSQL Global Development Group
  *
@@ -1397,3 +1397,116 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
 
 	return tupdesc;
 }
+
+/*
+ * extract_variadic_args
+ *
+ * Extract a set of argument values, types and NULL markers for a given
+ * input function which makes use of a VARIADIC input whose argument list
+ * depends on the caller context. When doing a VARIADIC call, the caller
+ * has provided one argument made of an array of values, so deconstruct the
+ * array data before using it for the next processing. If no VARIADIC call
+ * is used, just fill in the status data based on all the arguments given
+ * by the caller.
+ *
+ * This function returns the number of arguments generated, or -1 in the
+ * case of "VARIADIC NULL".
+ */
+int
+extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
+					  bool convert_unknown, Datum **args, Oid **types,
+					  bool **nulls)
+{
+	bool		variadic = get_fn_expr_variadic(fcinfo->flinfo);
+	Datum	   *args_res;
+	bool	   *nulls_res;
+	Oid		   *types_res;
+	int			nargs, i;
+
+	*args = NULL;
+	*types = NULL;
+	*nulls = NULL;
+
+	if (variadic)
+	{
+		ArrayType  *array_in;
+		Oid			element_type;
+		bool		typbyval;
+		char		typalign;
+		int16		typlen;
+
+		Assert(PG_NARGS() == variadic_start + 1);
+
+		if (PG_ARGISNULL(variadic_start))
+			return -1;
+
+		array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
+		element_type = ARR_ELEMTYPE(array_in);
+
+		get_typlenbyvalalign(element_type,
+							 &typlen, &typbyval, &typalign);
+		deconstruct_array(array_in, element_type, typlen, typbyval,
+						  typalign, &args_res, &nulls_res,
+						  &nargs);
+
+		/* All the elements of the array have the same type */
+		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
+		for (i = 0; i < nargs; i++)
+			types_res[i] = element_type;
+	}
+	else
+	{
+		nargs = PG_NARGS() - variadic_start;
+		Assert (nargs > 0);
+		nulls_res = (bool *) palloc0(nargs * sizeof(bool));
+		args_res = (Datum *) palloc0(nargs * sizeof(Datum));
+		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
+
+		for (i = 0; i < nargs; i++)
+		{
+			nulls_res[i] = PG_ARGISNULL(i + variadic_start);
+			types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
+											   i + variadic_start);
+
+			/*
+			 * Turn a constant (more or less literal) value that's of unknown
+			 * type into text if required . Unknowns come in as a cstring
+			 * pointer.
+			 * Note: for functions declared as taking type "any", the parser
+			 * will not do any type conversion on unknown-type literals (that
+			 * is, undecorated strings or NULLs).
+			 */
+			if (convert_unknown &&
+				types_res[i] == UNKNOWNOID &&
+				get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
+			{
+				types_res[i] = TEXTOID;
+
+				if (PG_ARGISNULL(i + variadic_start))
+					args_res[i] = (Datum) 0;
+				else
+					args_res[i] =
+						CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
+			}
+			else
+			{
+				/* no conversion needed, just take the datum as given */
+				args_res[i] = PG_GETARG_DATUM(i + variadic_start);
+			}
+
+			if (!OidIsValid(types_res[i]) ||
+				(convert_unknown && types_res[i] == UNKNOWNOID))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("could not determine data type for argument %d",
+								i + 1)));
+		}
+	}
+
+	/* Fill in results */
+	*args = args_res;
+	*nulls = nulls_res;
+	*types = types_res;
+
+	return nargs;
+}
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 951af2aad3d0a9c3ed5bd69f46ed2f117f9d6fd2..d2dbc163f294bdec680ccb78724b15647daf11b1 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -2,6 +2,7 @@
  *
  * funcapi.h
  *	  Definitions for functions which return composite type and/or sets
+ *	  or work on VARIADIC inputs.
  *
  * This file must be included by all Postgres modules that either define
  * or call FUNCAPI-callable functions or macros.
@@ -315,4 +316,26 @@ extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);
 		PG_RETURN_NULL(); \
 	} while (0)
 
+/*----------
+ *	Support to ease writing of functions dealing with VARIADIC inputs
+ *----------
+ *
+ * This function extracts a set of argument values, types and NULL markers
+ * for a given input function. This returns a set of data:
+ * - **values includes the set of Datum values extracted.
+ * - **types the data type OID for each element.
+ * - **nulls tracks if an element is NULL.
+ *
+ * variadic_start indicates the argument number where the VARIADIC argument
+ * starts.
+ * convert_unknown set to true will enforce the conversion of arguments
+ * with unknown data type to text.
+ *
+ * The return result is the number of elements stored, or -1 in the case of
+ * "VARIADIC NULL".
+ */
+extern int extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
+								 bool convert_unknown, Datum **values,
+								 Oid **types, bool **nulls);
+
 #endif							/* FUNCAPI_H */