diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 51fdb63cbdaa546fcce236e5df52639ee659d0ed..9a01ec6d5991277edbab458ef156b84de5e174e9 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1194,6 +1194,7 @@ _copyFuncExpr(const FuncExpr *from)
 	COPY_SCALAR_FIELD(funcid);
 	COPY_SCALAR_FIELD(funcresulttype);
 	COPY_SCALAR_FIELD(funcretset);
+	COPY_SCALAR_FIELD(funcvariadic);
 	COPY_SCALAR_FIELD(funcformat);
 	COPY_SCALAR_FIELD(funccollid);
 	COPY_SCALAR_FIELD(inputcollid);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 4b219b35ba6d118c9a9291e84485c2d3844b6388..034159da31ddfcc9f226234d85e52c16871d89f4 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -239,6 +239,7 @@ _equalFuncExpr(const FuncExpr *a, const FuncExpr *b)
 	COMPARE_SCALAR_FIELD(funcid);
 	COMPARE_SCALAR_FIELD(funcresulttype);
 	COMPARE_SCALAR_FIELD(funcretset);
+	COMPARE_SCALAR_FIELD(funcvariadic);
 	COMPARE_COERCIONFORM_FIELD(funcformat);
 	COMPARE_SCALAR_FIELD(funccollid);
 	COMPARE_SCALAR_FIELD(inputcollid);
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 7b8ac57cd6cf580c6b1b4f0ec59aca66d82e5c96..c487db96d816bc7bc06b98618ef72d88135417d6 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -461,6 +461,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args,
 	funcexpr->funcid = funcid;
 	funcexpr->funcresulttype = rettype;
 	funcexpr->funcretset = false;		/* only allowed case here */
+	funcexpr->funcvariadic = false;		/* only allowed case here */
 	funcexpr->funcformat = fformat;
 	funcexpr->funccollid = funccollid;
 	funcexpr->inputcollid = inputcollid;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3cce5f517e665cfd275c67db73a60b005833e74c..484e426489eb8d9a9b045062eb14c01d2b7f0183 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1000,6 +1000,7 @@ _outFuncExpr(StringInfo str, const FuncExpr *node)
 	WRITE_OID_FIELD(funcid);
 	WRITE_OID_FIELD(funcresulttype);
 	WRITE_BOOL_FIELD(funcretset);
+	WRITE_BOOL_FIELD(funcvariadic);
 	WRITE_ENUM_FIELD(funcformat, CoercionForm);
 	WRITE_OID_FIELD(funccollid);
 	WRITE_OID_FIELD(inputcollid);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e7c6ad67e917eb1441bcfc3151b40f3b36790ad9..ed2354144c4bbe6eb34c20a3abe3bfad65e4ccae 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -537,6 +537,7 @@ _readFuncExpr(void)
 	READ_OID_FIELD(funcid);
 	READ_OID_FIELD(funcresulttype);
 	READ_BOOL_FIELD(funcretset);
+	READ_BOOL_FIELD(funcvariadic);
 	READ_ENUM_FIELD(funcformat, CoercionForm);
 	READ_OID_FIELD(funccollid);
 	READ_OID_FIELD(inputcollid);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 55c4a136441bec77c92a50ad81e1e0042ddff85e..657a18b1be4e2727bff5852badea05035318ecca 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -110,7 +110,7 @@ static Node *simplify_boolean_equality(Oid opno, List *args);
 static Expr *simplify_function(Oid funcid,
 				  Oid result_type, int32 result_typmod,
 				  Oid result_collid, Oid input_collid, List **args_p,
-				  bool process_args, bool allow_non_const,
+				  bool funcvariadic, bool process_args, bool allow_non_const,
 				  eval_const_expressions_context *context);
 static List *expand_function_arguments(List *args, Oid result_type,
 						  HeapTuple func_tuple);
@@ -121,10 +121,12 @@ static void recheck_cast_function_args(List *args, Oid result_type,
 						   HeapTuple func_tuple);
 static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
 				  Oid result_collid, Oid input_collid, List *args,
+				  bool funcvariadic,
 				  HeapTuple func_tuple,
 				  eval_const_expressions_context *context);
 static Expr *inline_function(Oid funcid, Oid result_type, Oid result_collid,
 				Oid input_collid, List *args,
+				bool funcvariadic,
 				HeapTuple func_tuple,
 				eval_const_expressions_context *context);
 static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
@@ -2314,6 +2316,7 @@ eval_const_expressions_mutator(Node *node,
 										   expr->funccollid,
 										   expr->inputcollid,
 										   &args,
+										   expr->funcvariadic,
 										   true,
 										   true,
 										   context);
@@ -2330,6 +2333,7 @@ eval_const_expressions_mutator(Node *node,
 				newexpr->funcid = expr->funcid;
 				newexpr->funcresulttype = expr->funcresulttype;
 				newexpr->funcretset = expr->funcretset;
+				newexpr->funcvariadic = expr->funcvariadic;
 				newexpr->funcformat = expr->funcformat;
 				newexpr->funccollid = expr->funccollid;
 				newexpr->inputcollid = expr->inputcollid;
@@ -2359,6 +2363,7 @@ eval_const_expressions_mutator(Node *node,
 										   expr->opcollid,
 										   expr->inputcollid,
 										   &args,
+										   false,
 										   true,
 										   true,
 										   context);
@@ -2464,6 +2469,7 @@ eval_const_expressions_mutator(Node *node,
 											   &args,
 											   false,
 											   false,
+											   false,
 											   context);
 					if (simple) /* successfully simplified it */
 					{
@@ -2665,6 +2671,7 @@ eval_const_expressions_mutator(Node *node,
 										   InvalidOid,
 										   InvalidOid,
 										   &args,
+										   false,
 										   true,
 										   true,
 										   context);
@@ -2697,6 +2704,7 @@ eval_const_expressions_mutator(Node *node,
 											   InvalidOid,
 											   &args,
 											   false,
+											   false,
 											   true,
 											   context);
 					if (simple) /* successfully simplified input fn */
@@ -3565,7 +3573,7 @@ simplify_boolean_equality(Oid opno, List *args)
 static Expr *
 simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
 				  Oid result_collid, Oid input_collid, List **args_p,
-				  bool process_args, bool allow_non_const,
+				  bool funcvariadic, bool process_args, bool allow_non_const,
 				  eval_const_expressions_context *context)
 {
 	List	   *args = *args_p;
@@ -3609,7 +3617,8 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
 	/* Now attempt simplification of the function call proper. */
 
 	newexpr = evaluate_function(funcid, result_type, result_typmod,
-								result_collid, input_collid, args,
+								result_collid, input_collid,
+								args, funcvariadic,
 								func_tuple, context);
 
 	if (!newexpr && allow_non_const && OidIsValid(func_form->protransform))
@@ -3625,6 +3634,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
 		fexpr.funcid = funcid;
 		fexpr.funcresulttype = result_type;
 		fexpr.funcretset = func_form->proretset;
+		fexpr.funcvariadic = funcvariadic;
 		fexpr.funcformat = COERCE_EXPLICIT_CALL;
 		fexpr.funccollid = result_collid;
 		fexpr.inputcollid = input_collid;
@@ -3638,7 +3648,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
 
 	if (!newexpr && allow_non_const)
 		newexpr = inline_function(funcid, result_type, result_collid,
-								  input_collid, args,
+								  input_collid, args, funcvariadic,
 								  func_tuple, context);
 
 	ReleaseSysCache(func_tuple);
@@ -3878,6 +3888,7 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
 static Expr *
 evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
 				  Oid result_collid, Oid input_collid, List *args,
+				  bool funcvariadic,
 				  HeapTuple func_tuple,
 				  eval_const_expressions_context *context)
 {
@@ -3959,6 +3970,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
 	newexpr->funcid = funcid;
 	newexpr->funcresulttype = result_type;
 	newexpr->funcretset = false;
+	newexpr->funcvariadic = funcvariadic;
 	newexpr->funcformat = COERCE_EXPLICIT_CALL;	/* doesn't matter */
 	newexpr->funccollid = result_collid;		/* doesn't matter */
 	newexpr->inputcollid = input_collid;
@@ -4001,6 +4013,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
 static Expr *
 inline_function(Oid funcid, Oid result_type, Oid result_collid,
 				Oid input_collid, List *args,
+				bool funcvariadic,
 				HeapTuple func_tuple,
 				eval_const_expressions_context *context)
 {
@@ -4089,6 +4102,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
 	fexpr->funcid = funcid;
 	fexpr->funcresulttype = result_type;
 	fexpr->funcretset = false;
+	fexpr->funcvariadic = funcvariadic;
 	fexpr->funcformat = COERCE_EXPLICIT_CALL;	/* doesn't matter */
 	fexpr->funccollid = result_collid;	/* doesn't matter */
 	fexpr->inputcollid = input_collid;
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index c7a2a22465a60b56a4549d8d5058af5e7b0efeab..ae7d195a3ea45c1dca216d174216b07430157235 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -384,6 +384,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 		funcexpr->funcid = funcid;
 		funcexpr->funcresulttype = rettype;
 		funcexpr->funcretset = retset;
+		funcexpr->funcvariadic = func_variadic;
 		funcexpr->funcformat = COERCE_EXPLICIT_CALL;
 		/* funccollid and inputcollid will be set by parse_collate.c */
 		funcexpr->args = fargs;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 266cec5ffa2f19f7859d5cf95a0fec849b678fd6..af10471581795f91899c022ef927cd3362cbf530 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -396,8 +396,9 @@ static Node *processIndirection(Node *node, deparse_context *context,
 static void printSubscripts(ArrayRef *aref, deparse_context *context);
 static char *get_relation_name(Oid relid);
 static char *generate_relation_name(Oid relid, List *namespaces);
-static char *generate_function_name(Oid funcid, int nargs, List *argnames,
-					   Oid *argtypes, bool *is_variadic);
+static char *generate_function_name(Oid funcid, int nargs,
+					   List *argnames, Oid *argtypes,
+					   bool was_variadic, bool *use_variadic_p);
 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
 static text *string_to_text(char *str);
 static char *flatten_reloptions(Oid relid);
@@ -858,7 +859,8 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 
 	appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
 					 generate_function_name(trigrec->tgfoid, 0,
-											NIL, NULL, NULL));
+											NIL, NULL,
+											false, NULL));
 
 	if (trigrec->tgnargs > 0)
 	{
@@ -7269,7 +7271,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
 	Oid			argtypes[FUNC_MAX_ARGS];
 	int			nargs;
 	List	   *argnames;
-	bool		is_variadic;
+	bool		use_variadic;
 	ListCell   *l;
 
 	/*
@@ -7327,13 +7329,14 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
 	appendStringInfo(buf, "%s(",
 					 generate_function_name(funcoid, nargs,
 											argnames, argtypes,
-											&is_variadic));
+											expr->funcvariadic,
+											&use_variadic));
 	nargs = 0;
 	foreach(l, expr->args)
 	{
 		if (nargs++ > 0)
 			appendStringInfoString(buf, ", ");
-		if (is_variadic && lnext(l) == NULL)
+		if (use_variadic && lnext(l) == NULL)
 			appendStringInfoString(buf, "VARIADIC ");
 		get_rule_expr((Node *) lfirst(l), context, true);
 	}
@@ -7374,7 +7377,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
 
 	appendStringInfo(buf, "%s(%s",
 					 generate_function_name(aggref->aggfnoid, nargs,
-											NIL, argtypes, NULL),
+											NIL, argtypes,
+											false, NULL),
 					 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
 	/* aggstar can be set only in zero-argument aggregates */
 	if (aggref->aggstar)
@@ -7416,7 +7420,8 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
 
 	appendStringInfo(buf, "%s(",
 					 generate_function_name(wfunc->winfnoid, nargs,
-											NIL, argtypes, NULL));
+											NIL, argtypes,
+											false, NULL));
 	/* winstar can be set only in zero-argument aggregates */
 	if (wfunc->winstar)
 		appendStringInfoChar(buf, '*');
@@ -8507,18 +8512,25 @@ generate_relation_name(Oid relid, List *namespaces)
  *		given that it is being called with the specified actual arg names and
  *		types.	(Those matter because of ambiguous-function resolution rules.)
  *
- * The result includes all necessary quoting and schema-prefixing.	We can
- * also pass back an indication of whether the function is variadic.
+ * If we're dealing with a potentially variadic function (in practice, this
+ * means a FuncExpr and not some other way of calling the function), then
+ * was_variadic must specify whether VARIADIC appeared in the original call,
+ * and *use_variadic_p will be set to indicate whether to print VARIADIC in
+ * the output.  For non-FuncExpr cases, was_variadic should be FALSE and
+ * use_variadic_p can be NULL.
+ *
+ * The result includes all necessary quoting and schema-prefixing.
  */
 static char *
-generate_function_name(Oid funcid, int nargs, List *argnames,
-					   Oid *argtypes, bool *is_variadic)
+generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
+					   bool was_variadic, bool *use_variadic_p)
 {
+	char	   *result;
 	HeapTuple	proctup;
 	Form_pg_proc procform;
 	char	   *proname;
+	bool		use_variadic;
 	char	   *nspname;
-	char	   *result;
 	FuncDetailCode p_result;
 	Oid			p_funcid;
 	Oid			p_rettype;
@@ -8532,15 +8544,47 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
 	procform = (Form_pg_proc) GETSTRUCT(proctup);
 	proname = NameStr(procform->proname);
 
+	/*
+	 * Determine whether VARIADIC should be printed.  We must do this first
+	 * since it affects the lookup rules in func_get_detail().
+	 *
+	 * Currently, we always print VARIADIC if the function is variadic and
+	 * takes a variadic type other than ANY.  (In principle, if VARIADIC
+	 * wasn't originally specified and the array actual argument is
+	 * deconstructable, we could print the array elements separately and not
+	 * print VARIADIC, thus more nearly reproducing the original input.  For
+	 * the moment that seems like too much complication for the benefit.)
+	 * However, if the function takes VARIADIC ANY, then the parser didn't
+	 * fold the arguments together into an array, so we must print VARIADIC if
+	 * and only if it was used originally.
+	 */
+	if (use_variadic_p)
+	{
+		if (OidIsValid(procform->provariadic))
+		{
+			if (procform->provariadic != ANYOID)
+				use_variadic = true;
+			else
+				use_variadic = was_variadic;
+		}
+		else
+			use_variadic = false;
+		*use_variadic_p = use_variadic;
+	}
+	else
+	{
+		Assert(!was_variadic);
+		use_variadic = false;
+	}
+
 	/*
 	 * The idea here is to schema-qualify only if the parser would fail to
 	 * resolve the correct function given the unqualified func name with the
-	 * specified argtypes.	If the function is variadic, we should presume
-	 * that VARIADIC will be included in the call.
+	 * specified argtypes and VARIADIC flag.
 	 */
 	p_result = func_get_detail(list_make1(makeString(proname)),
 							   NIL, argnames, nargs, argtypes,
-							   !OidIsValid(procform->provariadic), true,
+							   !use_variadic, true,
 							   &p_funcid, &p_rettype,
 							   &p_retset, &p_nvargs, &p_true_typeids, NULL);
 	if ((p_result == FUNCDETAIL_NORMAL ||
@@ -8553,17 +8597,6 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
 
 	result = quote_qualified_identifier(nspname, proname);
 
-	/* Check variadic-ness if caller cares */
-	if (is_variadic)
-	{
-		/* "any" variadics are not treated as variadics for listing */
-		if (OidIsValid(procform->provariadic) &&
-			procform->provariadic != ANYOID)
-			*is_variadic = true;
-		else
-			*is_variadic = false;
-	}
-
 	ReleaseSysCache(proctup);
 
 	return result;
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index e21bed83e39c93cd954ba140c4503ee58139028a..42de04c60a8368038d2afdd3cde849251fdcb283 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -2281,6 +2281,7 @@ pg_detoast_datum_packed(struct varlena * datum)
  * These are needed by polymorphic functions, which accept multiple possible
  * input types and need help from the parser to know what they've got.
  * Also, some functions might be interested in whether a parameter is constant.
+ * Functions taking VARIADIC ANY also need to know about the VARIADIC keyword.
  *-------------------------------------------------------------------------
  */
 
@@ -2445,3 +2446,28 @@ get_call_expr_arg_stable(Node *expr, int argnum)
 
 	return false;
 }
+
+/*
+ * Get the VARIADIC flag from the function invocation
+ *
+ * Returns false (the default assumption) if information is not available
+ */
+bool
+get_fn_expr_variadic(FmgrInfo *flinfo)
+{
+	Node	   *expr;
+
+	/*
+	 * can't return anything useful if we have no FmgrInfo or if its fn_expr
+	 * node has not been initialized
+	 */
+	if (!flinfo || !flinfo->fn_expr)
+		return false;
+
+	expr = flinfo->fn_expr;
+
+	if (IsA(expr, FuncExpr))
+		return ((FuncExpr *) expr)->funcvariadic;
+	else
+		return false;
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index cd562ef40cb41ce03a62a5e254d5ca5a02520e87..a676793566d54e4eefaba16098613928831b946b 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201301171
+#define CATALOG_VERSION_NO	201301211
 
 #endif
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index fe4a41ba09684eca1e0077a96b7245cc973c74ec..1f72e1bd48f96d585cbe76d252a9765bbf4b3f41 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -624,6 +624,7 @@ extern Oid	get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
 extern Oid	get_call_expr_argtype(fmNodePtr expr, int argnum);
 extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum);
 extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
+extern bool get_fn_expr_variadic(FmgrInfo *flinfo);
 
 /*
  * Routines in dfmgr.c
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index ac53e463fc6053d3f282b0f66e4953bb0840bbfb..1d657669e132a25690ae1dbdad947cf262c1db22 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -340,6 +340,7 @@ typedef struct FuncExpr
 	Oid			funcid;			/* PG_PROC OID of the function */
 	Oid			funcresulttype; /* PG_TYPE OID of result value */
 	bool		funcretset;		/* true if function returns set */
+	bool		funcvariadic;	/* true if VARIADIC was used in call */
 	CoercionForm funcformat;	/* how to display this function call */
 	Oid			funccollid;		/* OID of collation of result */
 	Oid			inputcollid;	/* OID of collation that function should use */